1 #![deny(warnings)] 2 3 extern crate cc; 4 extern crate ctest2 as ctest; 5 6 use std::env; 7 8 fn do_cc() { 9 let target = env::var("TARGET").unwrap(); 10 if cfg!(unix) { 11 let exclude = ["redox", "wasi"]; 12 if !exclude.iter().any(|x| target.contains(x)) { 13 let mut cmsg = cc::Build::new(); 14 15 cmsg.file("src/cmsg.c"); 16 17 if target.contains("solaris") || target.contains("illumos") { 18 cmsg.define("_XOPEN_SOURCE", "700"); 19 } 20 cmsg.compile("cmsg"); 21 } 22 } 23 if target.contains("android") || target.contains("linux") { 24 cc::Build::new().file("src/errqueue.c").compile("errqueue"); 25 } 26 } 27 28 fn do_ctest() { 29 match &env::var("TARGET").unwrap() { 30 t if t.contains("android") => return test_android(t), 31 t if t.contains("apple") => return test_apple(t), 32 t if t.contains("cloudabi") => return test_cloudabi(t), 33 t if t.contains("dragonfly") => return test_dragonflybsd(t), 34 t if t.contains("emscripten") => return test_emscripten(t), 35 t if t.contains("freebsd") => return test_freebsd(t), 36 t if t.contains("linux") => return test_linux(t), 37 t if t.contains("netbsd") => return test_netbsd(t), 38 t if t.contains("openbsd") => return test_openbsd(t), 39 t if t.contains("redox") => return test_redox(t), 40 t if t.contains("solaris") => return test_solarish(t), 41 t if t.contains("illumos") => return test_solarish(t), 42 t if t.contains("wasi") => return test_wasi(t), 43 t if t.contains("windows") => return test_windows(t), 44 t if t.contains("vxworks") => return test_vxworks(t), 45 t => panic!("unknown target {}", t), 46 } 47 } 48 49 fn ctest_cfg() -> ctest::TestGenerator { 50 let mut cfg = ctest::TestGenerator::new(); 51 let libc_cfgs = [ 52 "libc_priv_mod_use", 53 "libc_union", 54 "libc_const_size_of", 55 "libc_align", 56 "libc_core_cvoid", 57 "libc_packedN", 58 "libc_thread_local", 59 ]; 60 for f in &libc_cfgs { 61 cfg.cfg(f, None); 62 } 63 cfg 64 } 65 66 fn main() { 67 do_cc(); 68 do_ctest(); 69 } 70 71 macro_rules! headers { 72 ($cfg:ident: [$m:expr]: $header:literal) => { 73 if $m { 74 $cfg.header($header); 75 } 76 }; 77 ($cfg:ident: $header:literal) => { 78 $cfg.header($header); 79 }; 80 ($($cfg:ident: $([$c:expr]:)* $header:literal,)*) => { 81 $(headers!($cfg: $([$c]:)* $header);)* 82 }; 83 ($cfg:ident: $( $([$c:expr]:)* $header:literal,)*) => { 84 headers!($($cfg: $([$c]:)* $header,)*); 85 }; 86 ($cfg:ident: $( $([$c:expr]:)* $header:literal),*) => { 87 headers!($($cfg: $([$c]:)* $header,)*); 88 }; 89 } 90 91 fn test_apple(target: &str) { 92 assert!(target.contains("apple")); 93 let x86_64 = target.contains("x86_64"); 94 let i686 = target.contains("i686"); 95 96 let mut cfg = ctest_cfg(); 97 cfg.flag("-Wno-deprecated-declarations"); 98 cfg.define("__APPLE_USE_RFC_3542", None); 99 100 headers! { cfg: 101 "aio.h", 102 "ctype.h", 103 "dirent.h", 104 "dlfcn.h", 105 "errno.h", 106 "execinfo.h", 107 "fcntl.h", 108 "glob.h", 109 "grp.h", 110 "ifaddrs.h", 111 "langinfo.h", 112 "limits.h", 113 "locale.h", 114 "mach-o/dyld.h", 115 "mach/mach_time.h", 116 "malloc/malloc.h", 117 "net/bpf.h", 118 "net/if.h", 119 "net/if_arp.h", 120 "net/if_dl.h", 121 "net/if_utun.h", 122 "net/route.h", 123 "net/route.h", 124 "netdb.h", 125 "netinet/if_ether.h", 126 "netinet/in.h", 127 "netinet/in.h", 128 "netinet/ip.h", 129 "netinet/tcp.h", 130 "netinet/udp.h", 131 "poll.h", 132 "pthread.h", 133 "pwd.h", 134 "regex.h", 135 "resolv.h", 136 "sched.h", 137 "semaphore.h", 138 "signal.h", 139 "spawn.h", 140 "stddef.h", 141 "stdint.h", 142 "stdio.h", 143 "stdlib.h", 144 "string.h", 145 "sys/event.h", 146 "sys/file.h", 147 "sys/ioctl.h", 148 "sys/ipc.h", 149 "sys/kern_control.h", 150 "sys/mman.h", 151 "sys/mount.h", 152 "sys/proc_info.h", 153 "sys/ptrace.h", 154 "sys/quota.h", 155 "sys/resource.h", 156 "sys/sem.h", 157 "sys/shm.h", 158 "sys/socket.h", 159 "sys/stat.h", 160 "sys/statvfs.h", 161 "sys/sys_domain.h", 162 "sys/sysctl.h", 163 "sys/time.h", 164 "sys/times.h", 165 "sys/timex.h", 166 "sys/types.h", 167 "sys/uio.h", 168 "sys/un.h", 169 "sys/utsname.h", 170 "sys/wait.h", 171 "sys/xattr.h", 172 "syslog.h", 173 "termios.h", 174 "time.h", 175 "unistd.h", 176 "util.h", 177 "utime.h", 178 "utmpx.h", 179 "wchar.h", 180 "xlocale.h", 181 [x86_64]: "crt_externs.h", 182 } 183 184 cfg.skip_struct(move |ty| { 185 match ty { 186 // FIXME: actually a union 187 "sigval" => true, 188 189 _ => false, 190 } 191 }); 192 193 cfg.skip_const(move |name| { 194 match name { 195 // These OSX constants are removed in Sierra. 196 // https://developer.apple.com/library/content/releasenotes/General/APIDiffsMacOS10_12/Swift/Darwin.html 197 "KERN_KDENABLE_BG_TRACE" | "KERN_KDDISABLE_BG_TRACE" => true, 198 // FIXME: the value has been changed since Catalina (0xffff0000 -> 0x3fff0000). 199 "SF_SETTABLE" => true, 200 // FIXME: the value has been changed since Catalina (VM_FLAGS_RESILIENT_MEDIA is also contained now). 201 "VM_FLAGS_USER_REMAP" => true, 202 _ => false, 203 } 204 }); 205 206 cfg.skip_fn(move |name| { 207 // skip those that are manually verified 208 match name { 209 // FIXME: https://github.com/rust-lang/libc/issues/1272 210 "execv" | "execve" | "execvp" => true, 211 212 // close calls the close_nocancel system call 213 "close" => true, 214 215 _ => false, 216 } 217 }); 218 219 cfg.skip_field(move |struct_, field| { 220 match (struct_, field) { 221 // FIXME: the array size has been changed since macOS 10.15 ([8] -> [7]). 222 ("statfs", "f_reserved") => true, 223 _ => false, 224 } 225 }); 226 227 cfg.skip_field_type(move |struct_, field| { 228 match (struct_, field) { 229 // FIXME: actually a union 230 ("sigevent", "sigev_value") => true, 231 _ => false, 232 } 233 }); 234 235 cfg.volatile_item(|i| { 236 use ctest::VolatileItemKind::*; 237 match i { 238 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => { 239 true 240 } 241 _ => false, 242 } 243 }); 244 245 cfg.type_name(move |ty, is_struct, is_union| { 246 match ty { 247 // Just pass all these through, no need for a "struct" prefix 248 "FILE" | "DIR" | "Dl_info" => ty.to_string(), 249 250 // OSX calls this something else 251 "sighandler_t" => "sig_t".to_string(), 252 253 t if is_union => format!("union {}", t), 254 t if t.ends_with("_t") => t.to_string(), 255 t if is_struct => format!("struct {}", t), 256 t => t.to_string(), 257 } 258 }); 259 260 cfg.field_name(move |struct_, field| { 261 match field { 262 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 263 s.replace("e_nsec", "espec.tv_nsec") 264 } 265 // FIXME: sigaction actually contains a union with two variants: 266 // a sa_sigaction with type: (*)(int, struct __siginfo *, void *) 267 // a sa_handler with type sig_t 268 "sa_sigaction" if struct_ == "sigaction" => { 269 "sa_handler".to_string() 270 } 271 s => s.to_string(), 272 } 273 }); 274 275 cfg.skip_roundtrip(move |s| match s { 276 // FIXME: this type has the wrong ABI 277 "max_align_t" if i686 => true, 278 _ => false, 279 }); 280 cfg.generate("../src/lib.rs", "main.rs"); 281 } 282 283 fn test_openbsd(target: &str) { 284 assert!(target.contains("openbsd")); 285 286 let mut cfg = ctest_cfg(); 287 cfg.flag("-Wno-deprecated-declarations"); 288 289 headers! { cfg: 290 "elf.h", 291 "errno.h", 292 "fcntl.h", 293 "limits.h", 294 "link.h", 295 "locale.h", 296 "stddef.h", 297 "stdint.h", 298 "stdio.h", 299 "stdlib.h", 300 "sys/stat.h", 301 "sys/types.h", 302 "time.h", 303 "wchar.h", 304 "ctype.h", 305 "dirent.h", 306 "sys/socket.h", 307 "net/if.h", 308 "net/route.h", 309 "net/if_arp.h", 310 "netdb.h", 311 "netinet/in.h", 312 "netinet/ip.h", 313 "netinet/tcp.h", 314 "netinet/udp.h", 315 "net/bpf.h", 316 "regex.h", 317 "resolv.h", 318 "pthread.h", 319 "dlfcn.h", 320 "signal.h", 321 "string.h", 322 "sys/file.h", 323 "sys/ioctl.h", 324 "sys/mman.h", 325 "sys/resource.h", 326 "sys/socket.h", 327 "sys/time.h", 328 "sys/un.h", 329 "sys/wait.h", 330 "unistd.h", 331 "utime.h", 332 "pwd.h", 333 "grp.h", 334 "sys/utsname.h", 335 "sys/ptrace.h", 336 "sys/mount.h", 337 "sys/uio.h", 338 "sched.h", 339 "termios.h", 340 "poll.h", 341 "syslog.h", 342 "semaphore.h", 343 "sys/statvfs.h", 344 "sys/times.h", 345 "glob.h", 346 "ifaddrs.h", 347 "langinfo.h", 348 "sys/sysctl.h", 349 "utmp.h", 350 "sys/event.h", 351 "net/if_dl.h", 352 "util.h", 353 "ufs/ufs/quota.h", 354 "pthread_np.h", 355 "sys/syscall.h", 356 "sys/shm.h", 357 } 358 359 cfg.skip_struct(move |ty| { 360 match ty { 361 // FIXME: actually a union 362 "sigval" => true, 363 364 _ => false, 365 } 366 }); 367 368 cfg.skip_const(move |name| { 369 match name { 370 // Removed in OpenBSD 6.0 371 "KERN_USERMOUNT" | "KERN_ARND" => true, 372 _ => false, 373 } 374 }); 375 376 cfg.skip_fn(move |name| { 377 match name { 378 // FIXME: https://github.com/rust-lang/libc/issues/1272 379 "execv" | "execve" | "execvp" | "execvpe" => true, 380 381 // Removed in OpenBSD 6.5 382 // https://marc.info/?l=openbsd-cvs&m=154723400730318 383 "mincore" => true, 384 385 _ => false, 386 } 387 }); 388 389 cfg.type_name(move |ty, is_struct, is_union| { 390 match ty { 391 // Just pass all these through, no need for a "struct" prefix 392 "FILE" | "DIR" | "Dl_info" | "Elf32_Phdr" | "Elf64_Phdr" => { 393 ty.to_string() 394 } 395 396 // OSX calls this something else 397 "sighandler_t" => "sig_t".to_string(), 398 399 t if is_union => format!("union {}", t), 400 t if t.ends_with("_t") => t.to_string(), 401 t if is_struct => format!("struct {}", t), 402 t => t.to_string(), 403 } 404 }); 405 406 cfg.field_name(move |struct_, field| match field { 407 "st_birthtime" if struct_.starts_with("stat") => { 408 "__st_birthtime".to_string() 409 } 410 "st_birthtime_nsec" if struct_.starts_with("stat") => { 411 "__st_birthtimensec".to_string() 412 } 413 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 414 s.replace("e_nsec", ".tv_nsec") 415 } 416 "sa_sigaction" if struct_ == "sigaction" => "sa_handler".to_string(), 417 s => s.to_string(), 418 }); 419 420 cfg.skip_field_type(move |struct_, field| { 421 // type siginfo_t.si_addr changed from OpenBSD 6.0 to 6.1 422 struct_ == "siginfo_t" && field == "si_addr" 423 }); 424 425 cfg.skip_field(|struct_, field| { 426 match (struct_, field) { 427 // conflicting with `p_type` macro from <resolve.h>. 428 ("Elf32_Phdr", "p_type") => true, 429 ("Elf64_Phdr", "p_type") => true, 430 _ => false, 431 } 432 }); 433 434 cfg.generate("../src/lib.rs", "main.rs"); 435 } 436 437 fn test_windows(target: &str) { 438 assert!(target.contains("windows")); 439 let gnu = target.contains("gnu"); 440 441 let mut cfg = ctest_cfg(); 442 cfg.define("_WIN32_WINNT", Some("0x8000")); 443 444 headers! { cfg: 445 "direct.h", 446 "errno.h", 447 "fcntl.h", 448 "io.h", 449 "limits.h", 450 "locale.h", 451 "process.h", 452 "signal.h", 453 "stddef.h", 454 "stdint.h", 455 "stdio.h", 456 "stdlib.h", 457 "sys/stat.h", 458 "sys/types.h", 459 "sys/utime.h", 460 "time.h", 461 "wchar.h", 462 [gnu]: "ws2tcpip.h", 463 [!gnu]: "Winsock2.h", 464 } 465 466 cfg.type_name(move |ty, is_struct, is_union| { 467 match ty { 468 // Just pass all these through, no need for a "struct" prefix 469 "FILE" | "DIR" | "Dl_info" => ty.to_string(), 470 471 // FIXME: these don't exist: 472 "time64_t" => "__time64_t".to_string(), 473 "ssize_t" => "SSIZE_T".to_string(), 474 475 "sighandler_t" if !gnu => "_crt_signal_t".to_string(), 476 "sighandler_t" if gnu => "__p_sig_fn_t".to_string(), 477 478 t if is_union => format!("union {}", t), 479 t if t.ends_with("_t") => t.to_string(), 480 481 // Windows uppercase structs don't have `struct` in front: 482 t if is_struct => { 483 if ty.clone().chars().next().unwrap().is_uppercase() { 484 t.to_string() 485 } else if t == "stat" { 486 "struct __stat64".to_string() 487 } else if t == "utimbuf" { 488 "struct __utimbuf64".to_string() 489 } else { 490 // put `struct` in front of all structs: 491 format!("struct {}", t) 492 } 493 } 494 t => t.to_string(), 495 } 496 }); 497 498 cfg.fn_cname(move |name, cname| cname.unwrap_or(name).to_string()); 499 500 cfg.skip_type(move |name| match name { 501 "SSIZE_T" if !gnu => true, 502 "ssize_t" if !gnu => true, 503 _ => false, 504 }); 505 506 cfg.skip_const(move |name| { 507 match name { 508 // FIXME: API error: 509 // SIG_ERR type is "void (*)(int)", not "int" 510 "SIG_ERR" => true, 511 _ => false, 512 } 513 }); 514 515 // FIXME: All functions point to the wrong addresses? 516 cfg.skip_fn_ptrcheck(|_| true); 517 518 cfg.skip_signededness(move |c| { 519 match c { 520 // windows-isms 521 n if n.starts_with("P") => true, 522 n if n.starts_with("H") => true, 523 n if n.starts_with("LP") => true, 524 "sighandler_t" if gnu => true, 525 _ => false, 526 } 527 }); 528 529 cfg.skip_fn(move |name| { 530 match name { 531 // FIXME: https://github.com/rust-lang/libc/issues/1272 532 "execv" | "execve" | "execvp" | "execvpe" => true, 533 534 _ => false, 535 } 536 }); 537 538 cfg.generate("../src/lib.rs", "main.rs"); 539 } 540 541 fn test_redox(target: &str) { 542 assert!(target.contains("redox")); 543 544 let mut cfg = ctest_cfg(); 545 cfg.flag("-Wno-deprecated-declarations"); 546 547 headers! { 548 cfg: 549 "ctype.h", 550 "dirent.h", 551 "dlfcn.h", 552 "errno.h", 553 "fcntl.h", 554 "grp.h", 555 "limits.h", 556 "locale.h", 557 "netdb.h", 558 "netinet/in.h", 559 "netinet/ip.h", 560 "netinet/tcp.h", 561 "poll.h", 562 "pwd.h", 563 "semaphore.h", 564 "string.h", 565 "strings.h", 566 "sys/file.h", 567 "sys/ioctl.h", 568 "sys/mman.h", 569 "sys/ptrace.h", 570 "sys/resource.h", 571 "sys/socket.h", 572 "sys/stat.h", 573 "sys/statvfs.h", 574 "sys/time.h", 575 "sys/types.h", 576 "sys/uio.h", 577 "sys/un.h", 578 "sys/utsname.h", 579 "sys/wait.h", 580 "termios.h", 581 "time.h", 582 "unistd.h", 583 "utime.h", 584 "wchar.h", 585 } 586 587 cfg.generate("../src/lib.rs", "main.rs"); 588 } 589 590 fn test_cloudabi(target: &str) { 591 assert!(target.contains("cloudabi")); 592 593 let mut cfg = ctest_cfg(); 594 cfg.flag("-Wno-deprecated-declarations"); 595 596 headers! { 597 cfg: 598 "execinfo.h", 599 "glob.h", 600 "ifaddrs.h", 601 "langinfo.h", 602 "sys/ptrace.h", 603 "sys/quota.h", 604 "sys/sysctl.h", 605 "utmpx.h", 606 "ctype.h", 607 "dirent.h", 608 "dlfcn.h", 609 "errno.h", 610 "fcntl.h", 611 "grp.h", 612 "limits.h", 613 "locale.h", 614 "net/if.h", 615 "net/if_arp.h", 616 "net/route.h", 617 "netdb.h", 618 "netinet/in.h", 619 "netinet/ip.h", 620 "netinet/tcp.h", 621 "netinet/udp.h", 622 "poll.h", 623 "pthread.h", 624 "pwd.h", 625 "resolv.h", 626 "sched.h", 627 "semaphore.h", 628 "signal.h", 629 "stddef.h", 630 "stdint.h", 631 "stdio.h", 632 "stdlib.h", 633 "string.h", 634 "strings.h", 635 "sys/file.h", 636 "sys/ioctl.h", 637 "sys/mman.h", 638 "sys/mount.h", 639 "sys/resource.h", 640 "sys/socket.h", 641 "sys/stat.h", 642 "sys/statvfs.h", 643 "sys/time.h", 644 "sys/times.h", 645 "sys/types.h", 646 "sys/uio.h", 647 "sys/un.h", 648 "sys/utsname.h", 649 "sys/wait.h", 650 "syslog.h", 651 "termios.h", 652 "time.h", 653 "unistd.h", 654 "utime.h", 655 "wchar.h", 656 } 657 658 cfg.generate("../src/lib.rs", "main.rs"); 659 } 660 661 fn test_solarish(target: &str) { 662 let is_solaris = target.contains("solaris"); 663 let is_illumos = target.contains("illumos"); 664 assert!(is_solaris || is_illumos); 665 666 // ctest generates arguments supported only by clang, so make sure to run with CC=clang. 667 // While debugging, "CFLAGS=-ferror-limit=<large num>" is useful to get more error output. 668 let mut cfg = ctest_cfg(); 669 cfg.flag("-Wno-deprecated-declarations"); 670 671 cfg.define("_XOPEN_SOURCE", Some("700")); 672 cfg.define("__EXTENSIONS__", None); 673 cfg.define("_LCONV_C99", None); 674 675 headers! { 676 cfg: 677 "ctype.h", 678 "dirent.h", 679 "dlfcn.h", 680 "door.h", 681 "errno.h", 682 "execinfo.h", 683 "fcntl.h", 684 "glob.h", 685 "grp.h", 686 "ifaddrs.h", 687 "langinfo.h", 688 "limits.h", 689 "locale.h", 690 "mqueue.h", 691 "net/if.h", 692 "net/if_arp.h", 693 "net/route.h", 694 "netdb.h", 695 "netinet/in.h", 696 "netinet/ip.h", 697 "netinet/tcp.h", 698 "netinet/udp.h", 699 "poll.h", 700 "port.h", 701 "pthread.h", 702 "pwd.h", 703 "resolv.h", 704 "sched.h", 705 "semaphore.h", 706 "signal.h", 707 "stddef.h", 708 "stdint.h", 709 "stdio.h", 710 "stdlib.h", 711 "string.h", 712 "sys/epoll.h", 713 "sys/eventfd.h", 714 "sys/file.h", 715 "sys/filio.h", 716 "sys/ioctl.h", 717 "sys/loadavg.h", 718 "sys/mman.h", 719 "sys/mount.h", 720 "sys/resource.h", 721 "sys/socket.h", 722 "sys/stat.h", 723 "sys/statvfs.h", 724 "sys/stropts.h", 725 "sys/shm.h", 726 "sys/time.h", 727 "sys/times.h", 728 "sys/timex.h", 729 "sys/types.h", 730 "sys/uio.h", 731 "sys/un.h", 732 "sys/utsname.h", 733 "sys/wait.h", 734 "syslog.h", 735 "termios.h", 736 "time.h", 737 "ucontext.h", 738 "unistd.h", 739 "utime.h", 740 "utmpx.h", 741 "wchar.h", 742 } 743 744 cfg.skip_type(move |ty| { 745 match ty { 746 // sighandler_t is not present here 747 "sighandler_t" => true, 748 _ => false, 749 } 750 }); 751 752 cfg.type_name(move |ty, is_struct, is_union| match ty { 753 "FILE" => "__FILE".to_string(), 754 "DIR" | "Dl_info" => ty.to_string(), 755 t if t.ends_with("_t") => t.to_string(), 756 t if is_struct => format!("struct {}", t), 757 t if is_union => format!("union {}", t), 758 t => t.to_string(), 759 }); 760 761 cfg.field_name(move |struct_, field| { 762 match struct_ { 763 // rust struct uses raw u64, rather than union 764 "epoll_event" if field == "u64" => "data.u64".to_string(), 765 // rust struct was committed with typo for Solaris 766 "door_arg_t" if field == "dec_num" => "desc_num".to_string(), 767 "stat" if field.ends_with("_nsec") => { 768 // expose stat.Xtim.tv_nsec fields 769 field.trim_end_matches("e_nsec").to_string() + ".tv_nsec" 770 } 771 _ => field.to_string(), 772 } 773 }); 774 775 cfg.skip_const(move |name| match name { 776 "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" 777 | "DT_SOCK" | "USRQUOTA" | "GRPQUOTA" | "PRIO_MIN" | "PRIO_MAX" => { 778 true 779 } 780 781 // skip sighandler_t assignments 782 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, 783 784 "DT_UNKNOWN" => true, 785 786 "_UTX_LINESIZE" | "_UTX_USERSIZE" | "_UTX_PADSIZE" | "_UTX_IDSIZE" 787 | "_UTX_HOSTSIZE" => true, 788 789 "EADI" | "EXTPROC" | "IPC_SEAT" => true, 790 791 // This evaluates to a sysconf() call rather than a constant 792 "PTHREAD_STACK_MIN" => true, 793 794 // EPOLLEXCLUSIVE is a relatively recent addition to the epoll interface and may not be 795 // defined on older systems. It is, however, safe to use on systems which do not 796 // explicitly support it. (A no-op is an acceptable implementation of EPOLLEXCLUSIVE.) 797 "EPOLLEXCLUSIVE" => true, 798 799 _ => false, 800 }); 801 802 cfg.skip_struct(move |ty| { 803 // the union handling is a mess 804 if ty.contains("door_desc_t_") { 805 return true; 806 } 807 match ty { 808 // union, not a struct 809 "sigval" => true, 810 // a bunch of solaris-only fields 811 "utmpx" if is_illumos => true, 812 _ => false, 813 } 814 }); 815 816 cfg.skip_field(move |s, field| { 817 match s { 818 // C99 sizing on this is tough 819 "dirent" if field == "d_name" => true, 820 // the union/macro makes this rough 821 "sigaction" if field == "sa_sigaction" => true, 822 // Missing in illumos 823 "sigevent" if field == "ss_sp" => true, 824 // Avoid sigval union issues 825 "sigevent" if field == "sigev_value" => true, 826 // const issues 827 "sigevent" if field == "sigev_notify_attributes" => true, 828 829 // Avoid const and union issues 830 "door_arg" if field == "desc_ptr" => true, 831 "door_desc_t" if field == "d_data" => true, 832 "door_arg_t" if field.ends_with("_ptr") => true, 833 "door_arg_t" if field.ends_with("rbuf") => true, 834 835 _ => false, 836 } 837 }); 838 839 cfg.skip_fn(move |name| { 840 // skip those that are manually verified 841 match name { 842 // const-ness only added recently 843 "dladdr" => true, 844 845 // Definition of those functions as changed since unified headers 846 // from NDK r14b These changes imply some API breaking changes but 847 // are still ABI compatible. We can wait for the next major release 848 // to be compliant with the new API. 849 // 850 // FIXME: unskip these for next major release 851 "setpriority" | "personality" => true, 852 853 // signal is defined in terms of sighandler_t, so ignore 854 "signal" => true, 855 856 // Currently missing 857 "cfmakeraw" | "cfsetspeed" => true, 858 859 // const-ness issues 860 "execv" | "execve" | "execvp" | "settimeofday" | "sethostname" => { 861 true 862 } 863 864 // Solaris-different 865 "getpwent_r" | "getgrent_r" | "updwtmpx" if is_illumos => true, 866 "madvise" | "mprotect" if is_illumos => true, 867 "door_call" | "door_return" | "door_create" if is_illumos => true, 868 869 // These functions may return int or void depending on the exact 870 // configuration of the compilation environment, but the return 871 // value is not useful (always 0) so we can ignore it: 872 "setservent" | "endservent" if is_illumos => true, 873 874 _ => false, 875 } 876 }); 877 878 cfg.generate("../src/lib.rs", "main.rs"); 879 } 880 881 fn test_netbsd(target: &str) { 882 assert!(target.contains("netbsd")); 883 let rumprun = target.contains("rumprun"); 884 let mut cfg = ctest_cfg(); 885 886 cfg.flag("-Wno-deprecated-declarations"); 887 cfg.define("_NETBSD_SOURCE", Some("1")); 888 889 headers! { 890 cfg: 891 "elf.h", 892 "errno.h", 893 "fcntl.h", 894 "limits.h", 895 "link.h", 896 "locale.h", 897 "stddef.h", 898 "stdint.h", 899 "stdio.h", 900 "stdlib.h", 901 "sys/stat.h", 902 "sys/types.h", 903 "time.h", 904 "wchar.h", 905 "aio.h", 906 "ctype.h", 907 "dirent.h", 908 "dlfcn.h", 909 "glob.h", 910 "grp.h", 911 "ifaddrs.h", 912 "langinfo.h", 913 "net/if.h", 914 "net/if_arp.h", 915 "net/if_dl.h", 916 "net/route.h", 917 "netdb.h", 918 "netinet/in.h", 919 "netinet/ip.h", 920 "netinet/tcp.h", 921 "netinet/udp.h", 922 "poll.h", 923 "pthread.h", 924 "pwd.h", 925 "regex.h", 926 "resolv.h", 927 "sched.h", 928 "semaphore.h", 929 "signal.h", 930 "string.h", 931 "sys/extattr.h", 932 "sys/file.h", 933 "sys/ioctl.h", 934 "sys/ioctl_compat.h", 935 "sys/mman.h", 936 "sys/mount.h", 937 "sys/ptrace.h", 938 "sys/resource.h", 939 "sys/socket.h", 940 "sys/statvfs.h", 941 "sys/sysctl.h", 942 "sys/time.h", 943 "sys/times.h", 944 "sys/timex.h", 945 "sys/uio.h", 946 "sys/un.h", 947 "sys/utsname.h", 948 "sys/wait.h", 949 "syslog.h", 950 "termios.h", 951 "ufs/ufs/quota.h", 952 "ufs/ufs/quota1.h", 953 "unistd.h", 954 "util.h", 955 "utime.h", 956 "mqueue.h", 957 "netinet/dccp.h", 958 "sys/event.h", 959 "sys/quota.h", 960 "sys/shm.h", 961 } 962 963 cfg.type_name(move |ty, is_struct, is_union| { 964 match ty { 965 // Just pass all these through, no need for a "struct" prefix 966 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" 967 | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym" 968 | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr" 969 | "Elf64_Chdr" => ty.to_string(), 970 971 // OSX calls this something else 972 "sighandler_t" => "sig_t".to_string(), 973 974 t if is_union => format!("union {}", t), 975 976 t if t.ends_with("_t") => t.to_string(), 977 978 // put `struct` in front of all structs:. 979 t if is_struct => format!("struct {}", t), 980 981 t => t.to_string(), 982 } 983 }); 984 985 cfg.field_name(move |struct_, field| { 986 match field { 987 // Our stat *_nsec fields normally don't actually exist but are part 988 // of a timeval struct 989 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 990 s.replace("e_nsec", ".tv_nsec") 991 } 992 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 993 s => s.to_string(), 994 } 995 }); 996 997 cfg.skip_type(move |ty| { 998 match ty { 999 // FIXME: sighandler_t is crazy across platforms 1000 "sighandler_t" => true, 1001 _ => false, 1002 } 1003 }); 1004 1005 cfg.skip_struct(move |ty| { 1006 match ty { 1007 // This is actually a union, not a struct 1008 "sigval" => true, 1009 // These are tested as part of the linux_fcntl tests since there are 1010 // header conflicts when including them with all the other structs. 1011 "termios2" => true, 1012 _ => false, 1013 } 1014 }); 1015 1016 cfg.skip_signededness(move |c| { 1017 match c { 1018 "LARGE_INTEGER" | "float" | "double" => true, 1019 n if n.starts_with("pthread") => true, 1020 // sem_t is a struct or pointer 1021 "sem_t" => true, 1022 _ => false, 1023 } 1024 }); 1025 1026 cfg.skip_const(move |name| { 1027 match name { 1028 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 1029 "SIGUNUSED" => true, // removed in glibc 2.26 1030 1031 // weird signed extension or something like that? 1032 "MS_NOUSER" => true, 1033 "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 1034 "BOTHER" => true, 1035 1036 _ => false, 1037 } 1038 }); 1039 1040 cfg.skip_fn(move |name| { 1041 match name { 1042 // FIXME: https://github.com/rust-lang/libc/issues/1272 1043 "execv" | "execve" | "execvp" => true, 1044 1045 "getrlimit" | "getrlimit64" | // non-int in 1st arg 1046 "setrlimit" | "setrlimit64" | // non-int in 1st arg 1047 "prlimit" | "prlimit64" | // non-int in 2nd arg 1048 1049 // These functions presumably exist on netbsd but don't look like 1050 // they're implemented on rumprun yet, just let them slide for now. 1051 // Some of them look like they have headers but then don't have 1052 // corresponding actual definitions either... 1053 "shm_open" | 1054 "shm_unlink" | 1055 "syscall" | 1056 "mq_open" | 1057 "mq_close" | 1058 "mq_getattr" | 1059 "mq_notify" | 1060 "mq_receive" | 1061 "mq_send" | 1062 "mq_setattr" | 1063 "mq_timedreceive" | 1064 "mq_timedsend" | 1065 "mq_unlink" | 1066 "ptrace" | 1067 "sigaltstack" if rumprun => true, 1068 1069 _ => false, 1070 } 1071 }); 1072 1073 cfg.skip_field_type(move |struct_, field| { 1074 // This is a weird union, don't check the type. 1075 (struct_ == "ifaddrs" && field == "ifa_ifu") || 1076 // sighandler_t type is super weird 1077 (struct_ == "sigaction" && field == "sa_sigaction") || 1078 // sigval is actually a union, but we pretend it's a struct 1079 (struct_ == "sigevent" && field == "sigev_value") || 1080 // aio_buf is "volatile void*" and Rust doesn't understand volatile 1081 (struct_ == "aiocb" && field == "aio_buf") 1082 }); 1083 1084 cfg.skip_field(|struct_, field| { 1085 match (struct_, field) { 1086 // conflicting with `p_type` macro from <resolve.h>. 1087 ("Elf32_Phdr", "p_type") => true, 1088 ("Elf64_Phdr", "p_type") => true, 1089 _ => false, 1090 } 1091 }); 1092 1093 cfg.generate("../src/lib.rs", "main.rs"); 1094 } 1095 1096 fn test_dragonflybsd(target: &str) { 1097 assert!(target.contains("dragonfly")); 1098 let mut cfg = ctest_cfg(); 1099 cfg.flag("-Wno-deprecated-declarations"); 1100 1101 headers! { 1102 cfg: 1103 "aio.h", 1104 "ctype.h", 1105 "dirent.h", 1106 "dlfcn.h", 1107 "errno.h", 1108 "execinfo.h", 1109 "fcntl.h", 1110 "glob.h", 1111 "grp.h", 1112 "ifaddrs.h", 1113 "langinfo.h", 1114 "limits.h", 1115 "locale.h", 1116 "mqueue.h", 1117 "net/if.h", 1118 "net/if_arp.h", 1119 "net/if_dl.h", 1120 "net/route.h", 1121 "netdb.h", 1122 "netinet/in.h", 1123 "netinet/ip.h", 1124 "netinet/tcp.h", 1125 "netinet/udp.h", 1126 "poll.h", 1127 "pthread.h", 1128 "pthread_np.h", 1129 "pwd.h", 1130 "regex.h", 1131 "resolv.h", 1132 "sched.h", 1133 "semaphore.h", 1134 "signal.h", 1135 "stddef.h", 1136 "stdint.h", 1137 "stdio.h", 1138 "stdlib.h", 1139 "string.h", 1140 "sys/event.h", 1141 "sys/file.h", 1142 "sys/ioctl.h", 1143 "sys/mman.h", 1144 "sys/mount.h", 1145 "sys/ptrace.h", 1146 "sys/resource.h", 1147 "sys/rtprio.h", 1148 "sys/socket.h", 1149 "sys/stat.h", 1150 "sys/statvfs.h", 1151 "sys/sysctl.h", 1152 "sys/time.h", 1153 "sys/times.h", 1154 "sys/types.h", 1155 "sys/uio.h", 1156 "sys/un.h", 1157 "sys/utsname.h", 1158 "sys/wait.h", 1159 "syslog.h", 1160 "termios.h", 1161 "time.h", 1162 "ufs/ufs/quota.h", 1163 "unistd.h", 1164 "util.h", 1165 "utime.h", 1166 "utmpx.h", 1167 "wchar.h", 1168 } 1169 1170 cfg.type_name(move |ty, is_struct, is_union| { 1171 match ty { 1172 // Just pass all these through, no need for a "struct" prefix 1173 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" 1174 | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym" 1175 | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr" 1176 | "Elf64_Chdr" => ty.to_string(), 1177 1178 // FIXME: OSX calls this something else 1179 "sighandler_t" => "sig_t".to_string(), 1180 1181 t if is_union => format!("union {}", t), 1182 1183 t if t.ends_with("_t") => t.to_string(), 1184 1185 // put `struct` in front of all structs:. 1186 t if is_struct => format!("struct {}", t), 1187 1188 t => t.to_string(), 1189 } 1190 }); 1191 1192 cfg.field_name(move |struct_, field| { 1193 match field { 1194 // Our stat *_nsec fields normally don't actually exist but are part 1195 // of a timeval struct 1196 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 1197 s.replace("e_nsec", ".tv_nsec") 1198 } 1199 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 1200 // Field is named `type` in C but that is a Rust keyword, 1201 // so these fields are translated to `type_` in the bindings. 1202 "type_" if struct_ == "rtprio" => "type".to_string(), 1203 s => s.to_string(), 1204 } 1205 }); 1206 1207 cfg.skip_type(move |ty| { 1208 match ty { 1209 // sighandler_t is crazy across platforms 1210 "sighandler_t" => true, 1211 1212 _ => false, 1213 } 1214 }); 1215 1216 cfg.skip_struct(move |ty| { 1217 match ty { 1218 // This is actually a union, not a struct 1219 "sigval" => true, 1220 1221 // FIXME: These are tested as part of the linux_fcntl tests since 1222 // there are header conflicts when including them with all the other 1223 // structs. 1224 "termios2" => true, 1225 1226 _ => false, 1227 } 1228 }); 1229 1230 cfg.skip_signededness(move |c| { 1231 match c { 1232 "LARGE_INTEGER" | "float" | "double" => true, 1233 // uuid_t is a struct, not an integer. 1234 "uuid_t" => true, 1235 n if n.starts_with("pthread") => true, 1236 // sem_t is a struct or pointer 1237 "sem_t" => true, 1238 // mqd_t is a pointer on DragonFly 1239 "mqd_t" => true, 1240 1241 _ => false, 1242 } 1243 }); 1244 1245 cfg.skip_const(move |name| { 1246 match name { 1247 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 1248 1249 // weird signed extension or something like that? 1250 "MS_NOUSER" => true, 1251 "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 1252 1253 // These are defined for Solaris 11, but the crate is tested on 1254 // illumos, where they are currently not defined 1255 "EADI" 1256 | "PORT_SOURCE_POSTWAIT" 1257 | "PORT_SOURCE_SIGNAL" 1258 | "PTHREAD_STACK_MIN" => true, 1259 1260 _ => false, 1261 } 1262 }); 1263 1264 cfg.skip_fn(move |name| { 1265 // skip those that are manually verified 1266 match name { 1267 // FIXME: https://github.com/rust-lang/libc/issues/1272 1268 "execv" | "execve" | "execvp" => true, 1269 1270 "getrlimit" | "getrlimit64" | // non-int in 1st arg 1271 "setrlimit" | "setrlimit64" | // non-int in 1st arg 1272 "prlimit" | "prlimit64" // non-int in 2nd arg 1273 => true, 1274 1275 _ => false, 1276 } 1277 }); 1278 1279 cfg.skip_field_type(move |struct_, field| { 1280 // This is a weird union, don't check the type. 1281 (struct_ == "ifaddrs" && field == "ifa_ifu") || 1282 // sighandler_t type is super weird 1283 (struct_ == "sigaction" && field == "sa_sigaction") || 1284 // sigval is actually a union, but we pretend it's a struct 1285 (struct_ == "sigevent" && field == "sigev_value") || 1286 // aio_buf is "volatile void*" and Rust doesn't understand volatile 1287 (struct_ == "aiocb" && field == "aio_buf") 1288 }); 1289 1290 cfg.skip_field(move |struct_, field| { 1291 // this is actually a union on linux, so we can't represent it well and 1292 // just insert some padding. 1293 (struct_ == "siginfo_t" && field == "_pad") || 1294 // sigev_notify_thread_id is actually part of a sigev_un union 1295 (struct_ == "sigevent" && field == "sigev_notify_thread_id") 1296 }); 1297 1298 cfg.generate("../src/lib.rs", "main.rs"); 1299 } 1300 1301 fn test_wasi(target: &str) { 1302 assert!(target.contains("wasi")); 1303 1304 let mut cfg = ctest_cfg(); 1305 cfg.define("_GNU_SOURCE", None); 1306 1307 headers! { cfg: 1308 "ctype.h", 1309 "dirent.h", 1310 "errno.h", 1311 "fcntl.h", 1312 "limits.h", 1313 "locale.h", 1314 "malloc.h", 1315 "poll.h", 1316 "sched.h", 1317 "stdbool.h", 1318 "stddef.h", 1319 "stdint.h", 1320 "stdio.h", 1321 "stdlib.h", 1322 "string.h", 1323 "sys/resource.h", 1324 "sys/select.h", 1325 "sys/socket.h", 1326 "sys/stat.h", 1327 "sys/times.h", 1328 "sys/types.h", 1329 "sys/uio.h", 1330 "sys/utsname.h", 1331 "sys/ioctl.h", 1332 "time.h", 1333 "unistd.h", 1334 "wasi/api.h", 1335 "wasi/libc.h", 1336 "wasi/libc-find-relpath.h", 1337 "wchar.h", 1338 } 1339 1340 cfg.type_name(move |ty, is_struct, is_union| match ty { 1341 "FILE" | "fd_set" | "DIR" => ty.to_string(), 1342 t if is_union => format!("union {}", t), 1343 t if t.starts_with("__wasi") && t.ends_with("_u") => { 1344 format!("union {}", t) 1345 } 1346 t if t.starts_with("__wasi") && is_struct => format!("struct {}", t), 1347 t if t.ends_with("_t") => t.to_string(), 1348 t if is_struct => format!("struct {}", t), 1349 t => t.to_string(), 1350 }); 1351 1352 cfg.field_name(move |_struct, field| { 1353 match field { 1354 // deal with fields as rust keywords 1355 "type_" => "type".to_string(), 1356 s => s.to_string(), 1357 } 1358 }); 1359 1360 // Looks like LLD doesn't merge duplicate imports, so if the Rust 1361 // code imports from a module and the C code also imports from a 1362 // module we end up with two imports of function pointers which 1363 // import the same thing but have different function pointers 1364 cfg.skip_fn_ptrcheck(|f| f.starts_with("__wasi")); 1365 1366 // d_name is declared as a flexible array in WASI libc, so it 1367 // doesn't support sizeof. 1368 cfg.skip_field(|s, field| s == "dirent" && field == "d_name"); 1369 1370 // Currently Rust/clang disagree on function argument ABI, so skip these 1371 // tests. For more info see WebAssembly/tool-conventions#88 1372 cfg.skip_roundtrip(|_| true); 1373 1374 cfg.generate("../src/lib.rs", "main.rs"); 1375 } 1376 1377 fn test_android(target: &str) { 1378 assert!(target.contains("android")); 1379 let target_pointer_width = match target { 1380 t if t.contains("aarch64") || t.contains("x86_64") => 64, 1381 t if t.contains("i686") || t.contains("arm") => 32, 1382 t => panic!("unsupported target: {}", t), 1383 }; 1384 let x86 = target.contains("i686") || target.contains("x86_64"); 1385 1386 let mut cfg = ctest_cfg(); 1387 cfg.define("_GNU_SOURCE", None); 1388 1389 headers! { cfg: 1390 "arpa/inet.h", 1391 "ctype.h", 1392 "dirent.h", 1393 "dlfcn.h", 1394 "errno.h", 1395 "fcntl.h", 1396 "grp.h", 1397 "ifaddrs.h", 1398 "limits.h", 1399 "locale.h", 1400 "malloc.h", 1401 "net/ethernet.h", 1402 "net/if.h", 1403 "net/if_arp.h", 1404 "net/route.h", 1405 "netdb.h", 1406 "netinet/in.h", 1407 "netinet/ip.h", 1408 "netinet/tcp.h", 1409 "netinet/udp.h", 1410 "netpacket/packet.h", 1411 "poll.h", 1412 "pthread.h", 1413 "pty.h", 1414 "pwd.h", 1415 "regex.h", 1416 "resolv.h", 1417 "sched.h", 1418 "semaphore.h", 1419 "signal.h", 1420 "stddef.h", 1421 "stdint.h", 1422 "stdio.h", 1423 "stdlib.h", 1424 "string.h", 1425 "sys/auxv.h", 1426 "sys/epoll.h", 1427 "sys/eventfd.h", 1428 "sys/file.h", 1429 "sys/fsuid.h", 1430 "sys/inotify.h", 1431 "sys/ioctl.h", 1432 "sys/mman.h", 1433 "sys/mount.h", 1434 "sys/personality.h", 1435 "sys/prctl.h", 1436 "sys/ptrace.h", 1437 "sys/random.h", 1438 "sys/reboot.h", 1439 "sys/resource.h", 1440 "sys/sendfile.h", 1441 "sys/signalfd.h", 1442 "sys/socket.h", 1443 "sys/stat.h", 1444 "sys/statvfs.h", 1445 "sys/swap.h", 1446 "sys/syscall.h", 1447 "sys/sysinfo.h", 1448 "sys/time.h", 1449 "sys/times.h", 1450 "sys/timerfd.h", 1451 "sys/types.h", 1452 "sys/ucontext.h", 1453 "sys/uio.h", 1454 "sys/un.h", 1455 "sys/utsname.h", 1456 "sys/vfs.h", 1457 "sys/xattr.h", 1458 "sys/wait.h", 1459 "syslog.h", 1460 "termios.h", 1461 "time.h", 1462 "unistd.h", 1463 "utime.h", 1464 "utmp.h", 1465 "wchar.h", 1466 "xlocale.h", 1467 // time64_t is not defined for 64-bit targets If included it will 1468 // generate the error 'Your time_t is already 64-bit' 1469 [target_pointer_width == 32]: "time64.h", 1470 [x86]: "sys/reg.h", 1471 } 1472 1473 // Include linux headers at the end: 1474 headers! { cfg: 1475 "asm/mman.h", 1476 "linux/auxvec.h", 1477 "linux/dccp.h", 1478 "linux/errqueue.h", 1479 "linux/falloc.h", 1480 "linux/futex.h", 1481 "linux/fs.h", 1482 "linux/genetlink.h", 1483 "linux/if_alg.h", 1484 "linux/if_ether.h", 1485 "linux/if_tun.h", 1486 "linux/magic.h", 1487 "linux/memfd.h", 1488 "linux/module.h", 1489 "linux/net_tstamp.h", 1490 "linux/netfilter/nfnetlink.h", 1491 "linux/netfilter/nfnetlink_log.h", 1492 "linux/netfilter/nfnetlink_queue.h", 1493 "linux/netfilter/nf_tables.h", 1494 "linux/netfilter_ipv4.h", 1495 "linux/netfilter_ipv6.h", 1496 "linux/netfilter_ipv6/ip6_tables.h", 1497 "linux/netlink.h", 1498 "linux/quota.h", 1499 "linux/reboot.h", 1500 "linux/seccomp.h", 1501 "linux/sched.h", 1502 "linux/sockios.h", 1503 "linux/vm_sockets.h", 1504 "linux/wait.h", 1505 1506 } 1507 1508 cfg.type_name(move |ty, is_struct, is_union| { 1509 match ty { 1510 // Just pass all these through, no need for a "struct" prefix 1511 "FILE" | "fd_set" | "Dl_info" => ty.to_string(), 1512 1513 t if is_union => format!("union {}", t), 1514 1515 t if t.ends_with("_t") => t.to_string(), 1516 1517 // sigval is a struct in Rust, but a union in C: 1518 "sigval" => format!("union sigval"), 1519 1520 // put `struct` in front of all structs:. 1521 t if is_struct => format!("struct {}", t), 1522 1523 t => t.to_string(), 1524 } 1525 }); 1526 1527 cfg.field_name(move |struct_, field| { 1528 match field { 1529 // Our stat *_nsec fields normally don't actually exist but are part 1530 // of a timeval struct 1531 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 1532 s.to_string() 1533 } 1534 // FIXME: appears that `epoll_event.data` is an union 1535 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 1536 s => s.to_string(), 1537 } 1538 }); 1539 1540 cfg.skip_type(move |ty| { 1541 match ty { 1542 // FIXME: `sighandler_t` type is incorrect, see: 1543 // https://github.com/rust-lang/libc/issues/1359 1544 "sighandler_t" => true, 1545 _ => false, 1546 } 1547 }); 1548 1549 cfg.skip_struct(move |ty| { 1550 if ty.starts_with("__c_anonymous_") { 1551 return true; 1552 } 1553 match ty { 1554 // These are tested as part of the linux_fcntl tests since there are 1555 // header conflicts when including them with all the other structs. 1556 "termios2" => true, 1557 // uc_sigmask and uc_sigmask64 of ucontext_t are an anonymous union 1558 "ucontext_t" => true, 1559 1560 _ => false, 1561 } 1562 }); 1563 1564 cfg.skip_const(move |name| { 1565 match name { 1566 // FIXME: deprecated: not available in any header 1567 // See: https://github.com/rust-lang/libc/issues/1356 1568 "ENOATTR" => true, 1569 1570 // FIXME: still necessary? 1571 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 1572 // FIXME: deprecated - removed in glibc 2.26 1573 "SIGUNUSED" => true, 1574 1575 // Needs a newer Android SDK for the definition 1576 "P_PIDFD" => true, 1577 1578 // Requires Linux kernel 5.6 1579 "VMADDR_CID_LOCAL" => true, 1580 1581 _ => false, 1582 } 1583 }); 1584 1585 cfg.skip_fn(move |name| { 1586 // skip those that are manually verified 1587 match name { 1588 // FIXME: https://github.com/rust-lang/libc/issues/1272 1589 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 1590 1591 // There are two versions of the sterror_r function, see 1592 // 1593 // https://linux.die.net/man/3/strerror_r 1594 // 1595 // An XSI-compliant version provided if: 1596 // 1597 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE 1598 // 1599 // and a GNU specific version provided if _GNU_SOURCE is defined. 1600 // 1601 // libc provides bindings for the XSI-compliant version, which is 1602 // preferred for portable applications. 1603 // 1604 // We skip the test here since here _GNU_SOURCE is defined, and 1605 // test the XSI version below. 1606 "strerror_r" => true, 1607 1608 _ => false, 1609 } 1610 }); 1611 1612 cfg.skip_field_type(move |struct_, field| { 1613 // This is a weird union, don't check the type. 1614 (struct_ == "ifaddrs" && field == "ifa_ifu") || 1615 // sigval is actually a union, but we pretend it's a struct 1616 (struct_ == "sigevent" && field == "sigev_value") 1617 }); 1618 1619 cfg.skip_field(move |struct_, field| { 1620 // this is actually a union on linux, so we can't represent it well and 1621 // just insert some padding. 1622 (struct_ == "siginfo_t" && field == "_pad") || 1623 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 1624 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 1625 (struct_ == "sigaction" && field == "sa_sigaction") || 1626 // sigev_notify_thread_id is actually part of a sigev_un union 1627 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 1628 // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet. 1629 (struct_ == "signalfd_siginfo" && (field == "ssi_syscall" || 1630 field == "ssi_call_addr" || 1631 field == "ssi_arch")) 1632 }); 1633 1634 cfg.generate("../src/lib.rs", "main.rs"); 1635 1636 test_linux_like_apis(target); 1637 } 1638 1639 fn test_freebsd(target: &str) { 1640 assert!(target.contains("freebsd")); 1641 let mut cfg = ctest_cfg(); 1642 1643 let freebsd_ver = which_freebsd(); 1644 1645 match freebsd_ver { 1646 Some(10) => cfg.cfg("freebsd10", None), 1647 Some(11) => cfg.cfg("freebsd11", None), 1648 Some(12) => cfg.cfg("freebsd12", None), 1649 Some(13) => cfg.cfg("freebsd13", None), 1650 _ => &mut cfg, 1651 }; 1652 1653 // Required for `getline`: 1654 cfg.define("_WITH_GETLINE", None); 1655 // Required for making freebsd11_stat available in the headers 1656 match freebsd_ver { 1657 Some(10) => &mut cfg, 1658 _ => cfg.define("_WANT_FREEBSD11_STAT", None), 1659 }; 1660 1661 headers! { cfg: 1662 "aio.h", 1663 "arpa/inet.h", 1664 "ctype.h", 1665 "dirent.h", 1666 "dlfcn.h", 1667 "elf.h", 1668 "errno.h", 1669 "fcntl.h", 1670 "glob.h", 1671 "grp.h", 1672 "ifaddrs.h", 1673 "langinfo.h", 1674 "libutil.h", 1675 "limits.h", 1676 "link.h", 1677 "locale.h", 1678 "machine/reg.h", 1679 "mqueue.h", 1680 "net/bpf.h", 1681 "net/if.h", 1682 "net/if_arp.h", 1683 "net/if_dl.h", 1684 "net/route.h", 1685 "netdb.h", 1686 "netinet/ip.h", 1687 "netinet/in.h", 1688 "netinet/tcp.h", 1689 "netinet/udp.h", 1690 "poll.h", 1691 "pthread.h", 1692 "pthread_np.h", 1693 "pwd.h", 1694 "regex.h", 1695 "resolv.h", 1696 "sched.h", 1697 "semaphore.h", 1698 "signal.h", 1699 "spawn.h", 1700 "stddef.h", 1701 "stdint.h", 1702 "stdio.h", 1703 "stdlib.h", 1704 "string.h", 1705 "sys/event.h", 1706 "sys/extattr.h", 1707 "sys/file.h", 1708 "sys/ioctl.h", 1709 "sys/ipc.h", 1710 "sys/jail.h", 1711 "sys/mman.h", 1712 "sys/mount.h", 1713 "sys/msg.h", 1714 "sys/procdesc.h", 1715 "sys/ptrace.h", 1716 "sys/random.h", 1717 "sys/resource.h", 1718 "sys/rtprio.h", 1719 "sys/shm.h", 1720 "sys/socket.h", 1721 "sys/stat.h", 1722 "sys/statvfs.h", 1723 "sys/sysctl.h", 1724 "sys/time.h", 1725 "sys/times.h", 1726 "sys/timex.h", 1727 "sys/types.h", 1728 "sys/ucontext.h", 1729 "sys/uio.h", 1730 "sys/un.h", 1731 "sys/utsname.h", 1732 "sys/wait.h", 1733 "syslog.h", 1734 "termios.h", 1735 "time.h", 1736 "ufs/ufs/quota.h", 1737 "unistd.h", 1738 "utime.h", 1739 "utmpx.h", 1740 "wchar.h", 1741 } 1742 1743 cfg.type_name(move |ty, is_struct, is_union| { 1744 match ty { 1745 // Just pass all these through, no need for a "struct" prefix 1746 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" 1747 | "Elf64_Phdr" => ty.to_string(), 1748 1749 // FIXME: https://github.com/rust-lang/libc/issues/1273 1750 "sighandler_t" => "sig_t".to_string(), 1751 1752 t if is_union => format!("union {}", t), 1753 1754 t if t.ends_with("_t") => t.to_string(), 1755 1756 // sigval is a struct in Rust, but a union in C: 1757 "sigval" => format!("union sigval"), 1758 1759 // put `struct` in front of all structs:. 1760 t if is_struct => format!("struct {}", t), 1761 1762 t => t.to_string(), 1763 } 1764 }); 1765 1766 cfg.field_name(move |struct_, field| { 1767 match field { 1768 // Our stat *_nsec fields normally don't actually exist but are part 1769 // of a timeval struct 1770 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 1771 s.replace("e_nsec", ".tv_nsec") 1772 } 1773 // Field is named `type` in C but that is a Rust keyword, 1774 // so these fields are translated to `type_` in the bindings. 1775 "type_" if struct_ == "rtprio" => "type".to_string(), 1776 s => s.to_string(), 1777 } 1778 }); 1779 1780 cfg.skip_const(move |name| { 1781 match name { 1782 // These constants are to be introduced in yet-unreleased FreeBSD 12.2. 1783 "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" 1784 | "F_SEAL_SHRINK" | "F_SEAL_GROW" | "F_SEAL_WRITE" 1785 if Some(12) <= freebsd_ver => 1786 { 1787 true 1788 } 1789 1790 // These constants were introduced in FreeBSD 12: 1791 "SF_USER_READAHEAD" 1792 | "EVFILT_EMPTY" 1793 | "SO_REUSEPORT_LB" 1794 | "IP_ORIGDSTADDR" 1795 | "IP_RECVORIGDSTADDR" 1796 | "IPV6_ORIGDSTADDR" 1797 | "IPV6_RECVORIGDSTADDR" 1798 | "NI_NUMERICSCOPE" 1799 if Some(11) == freebsd_ver => 1800 { 1801 true 1802 } 1803 1804 // These constants were introduced in FreeBSD 11: 1805 "SF_USER_READAHEAD" 1806 | "SF_NOCACHE" 1807 | "RLIMIT_KQUEUES" 1808 | "RLIMIT_UMTXP" 1809 | "EVFILT_PROCDESC" 1810 | "EVFILT_SENDFILE" 1811 | "EVFILT_EMPTY" 1812 | "SO_REUSEPORT_LB" 1813 | "TCP_CCALGOOPT" 1814 | "TCP_PCAP_OUT" 1815 | "TCP_PCAP_IN" 1816 | "IP_BINDMULTI" 1817 | "IP_ORIGDSTADDR" 1818 | "IP_RECVORIGDSTADDR" 1819 | "IPV6_ORIGDSTADDR" 1820 | "IPV6_RECVORIGDSTADDR" 1821 | "PD_CLOEXEC" 1822 | "PD_ALLOWED_AT_FORK" 1823 | "IP_RSS_LISTEN_BUCKET" 1824 | "NI_NUMERICSCOPE" 1825 if Some(10) == freebsd_ver => 1826 { 1827 true 1828 } 1829 1830 // FIXME: This constant has a different value in FreeBSD 10: 1831 "RLIM_NLIMITS" if Some(10) == freebsd_ver => true, 1832 1833 // FIXME: There are deprecated - remove in a couple of releases. 1834 // These constants were removed in FreeBSD 11 (svn r273250) but will 1835 // still be accepted and ignored at runtime. 1836 "MAP_RENAME" | "MAP_NORESERVE" if Some(10) != freebsd_ver => true, 1837 1838 // FIXME: There are deprecated - remove in a couple of releases. 1839 // These constants were removed in FreeBSD 11 (svn r262489), 1840 // and they've never had any legitimate use outside of the 1841 // base system anyway. 1842 "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "USER_MAXID" => true, 1843 1844 // This constant was removed in FreeBSD 13 (svn r363622), and never 1845 // had any legitimate use outside of the base system anyway. 1846 "CTL_P1003_1B_MAXID" => true, 1847 1848 // This was renamed in FreeBSD 12.2 and 13 (r352486). 1849 "CTL_UNSPEC" | "CTL_SYSCTL" => true, 1850 1851 // These were added in FreeBSD 12.2 and 13 (r352486), 1852 // but they are just names for magic numbers that existed for ages. 1853 "CTL_SYSCTL_DEBUG" 1854 | "CTL_SYSCTL_NAME" 1855 | "CTL_SYSCTL_NEXT" 1856 | "CTL_SYSCTL_NAME2OID" 1857 | "CTL_SYSCTL_OIDFMT" 1858 | "CTL_SYSCTL_OIDDESCR" 1859 | "CTL_SYSCTL_OIDLABEL" => true, 1860 1861 // This was renamed in FreeBSD 12.2 and 13 (r350749). 1862 "IPPROTO_SEP" | "IPPROTO_DCCP" => true, 1863 1864 // This was changed to 96(0x60) in FreeBSD 13: 1865 // https://github.com/freebsd/freebsd/ 1866 // commit/06b00ceaa914a3907e4e27bad924f44612bae1d7 1867 "MINCORE_SUPER" if Some(13) == freebsd_ver => true, 1868 1869 // This was increased to 97 in FreeBSD 12.2 and 13. 1870 // https://github.com/freebsd/freebsd/ 1871 // commit/72a21ba0f62da5e86a1c0b462aeb3f5ff849a1b7 1872 "ELAST" if Some(12) == freebsd_ver => true, 1873 1874 _ => false, 1875 } 1876 }); 1877 1878 cfg.skip_struct(move |ty| { 1879 match ty { 1880 // `mmsghdr` is not available in FreeBSD 10 1881 "mmsghdr" if Some(10) == freebsd_ver => true, 1882 1883 // `max_align_t` is not available in FreeBSD 10 1884 "max_align_t" if Some(10) == freebsd_ver => true, 1885 1886 _ => false, 1887 } 1888 }); 1889 1890 cfg.skip_fn(move |name| { 1891 // skip those that are manually verified 1892 match name { 1893 // FIXME: https://github.com/rust-lang/libc/issues/1272 1894 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 1895 1896 // These functions were added in FreeBSD 11: 1897 "fdatasync" | "mq_getfd_np" | "sendmmsg" | "recvmmsg" 1898 if Some(10) == freebsd_ver => 1899 { 1900 true 1901 } 1902 1903 // This function changed its return type from `int` in FreeBSD10 to 1904 // `ssize_t` in FreeBSD11: 1905 "aio_waitcomplete" if Some(10) == freebsd_ver => true, 1906 1907 // The `uname` function in the `utsname.h` FreeBSD header is a C 1908 // inline function (has no symbol) that calls the `__xuname` symbol. 1909 // Therefore the function pointer comparison does not make sense for it. 1910 "uname" => true, 1911 1912 // FIXME: Our API is unsound. The Rust API allows aliasing 1913 // pointers, but the C API requires pointers not to alias. 1914 // We should probably be at least using `&`/`&mut` here, see: 1915 // https://github.com/gnzlbg/ctest/issues/68 1916 "lio_listio" => true, 1917 1918 _ => false, 1919 } 1920 }); 1921 1922 cfg.skip_signededness(move |c| { 1923 match c { 1924 // FIXME: has a different sign in FreeBSD10 1925 "blksize_t" if Some(10) == freebsd_ver => true, 1926 _ => false, 1927 } 1928 }); 1929 1930 cfg.volatile_item(|i| { 1931 use ctest::VolatileItemKind::*; 1932 match i { 1933 // aio_buf is a volatile void** but since we cannot express that in 1934 // Rust types, we have to explicitly tell the checker about it here: 1935 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => { 1936 true 1937 } 1938 _ => false, 1939 } 1940 }); 1941 1942 cfg.skip_field(move |struct_, field| { 1943 match (struct_, field) { 1944 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 1945 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 1946 ("sigaction", "sa_sigaction") => true, 1947 1948 // FIXME: in FreeBSD10 this field has type `char*` instead of 1949 // `void*`: 1950 ("stack_t", "ss_sp") if Some(10) == freebsd_ver => true, 1951 1952 // conflicting with `p_type` macro from <resolve.h>. 1953 ("Elf32_Phdr", "p_type") => true, 1954 ("Elf64_Phdr", "p_type") => true, 1955 1956 _ => false, 1957 } 1958 }); 1959 1960 cfg.generate("../src/lib.rs", "main.rs"); 1961 } 1962 1963 fn test_emscripten(target: &str) { 1964 assert!(target.contains("emscripten")); 1965 1966 let mut cfg = ctest_cfg(); 1967 cfg.define("_GNU_SOURCE", None); // FIXME: ?? 1968 1969 headers! { cfg: 1970 "aio.h", 1971 "ctype.h", 1972 "dirent.h", 1973 "dlfcn.h", 1974 "errno.h", 1975 "fcntl.h", 1976 "glob.h", 1977 "grp.h", 1978 "ifaddrs.h", 1979 "langinfo.h", 1980 "limits.h", 1981 "locale.h", 1982 "malloc.h", 1983 "mntent.h", 1984 "mqueue.h", 1985 "net/ethernet.h", 1986 "net/if.h", 1987 "net/if_arp.h", 1988 "net/route.h", 1989 "netdb.h", 1990 "netinet/in.h", 1991 "netinet/ip.h", 1992 "netinet/tcp.h", 1993 "netinet/udp.h", 1994 "netpacket/packet.h", 1995 "poll.h", 1996 "pthread.h", 1997 "pty.h", 1998 "pwd.h", 1999 "resolv.h", 2000 "sched.h", 2001 "sched.h", 2002 "semaphore.h", 2003 "shadow.h", 2004 "signal.h", 2005 "stddef.h", 2006 "stdint.h", 2007 "stdio.h", 2008 "stdlib.h", 2009 "string.h", 2010 "sys/epoll.h", 2011 "sys/eventfd.h", 2012 "sys/file.h", 2013 "sys/ioctl.h", 2014 "sys/ipc.h", 2015 "sys/mman.h", 2016 "sys/mount.h", 2017 "sys/msg.h", 2018 "sys/personality.h", 2019 "sys/prctl.h", 2020 "sys/ptrace.h", 2021 "sys/quota.h", 2022 "sys/reboot.h", 2023 "sys/resource.h", 2024 "sys/sem.h", 2025 "sys/sendfile.h", 2026 "sys/shm.h", 2027 "sys/signalfd.h", 2028 "sys/socket.h", 2029 "sys/stat.h", 2030 "sys/statvfs.h", 2031 "sys/swap.h", 2032 "sys/syscall.h", 2033 "sys/sysctl.h", 2034 "sys/sysinfo.h", 2035 "sys/time.h", 2036 "sys/timerfd.h", 2037 "sys/times.h", 2038 "sys/types.h", 2039 "sys/uio.h", 2040 "sys/un.h", 2041 "sys/user.h", 2042 "sys/utsname.h", 2043 "sys/vfs.h", 2044 "sys/wait.h", 2045 "sys/xattr.h", 2046 "syslog.h", 2047 "termios.h", 2048 "time.h", 2049 "ucontext.h", 2050 "unistd.h", 2051 "utime.h", 2052 "utmp.h", 2053 "utmpx.h", 2054 "wchar.h", 2055 } 2056 2057 cfg.type_name(move |ty, is_struct, is_union| { 2058 match ty { 2059 // Just pass all these through, no need for a "struct" prefix 2060 "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(), 2061 2062 t if is_union => format!("union {}", t), 2063 2064 t if t.ends_with("_t") => t.to_string(), 2065 2066 // put `struct` in front of all structs:. 2067 t if is_struct => format!("struct {}", t), 2068 2069 t => t.to_string(), 2070 } 2071 }); 2072 2073 cfg.field_name(move |struct_, field| { 2074 match field { 2075 // Our stat *_nsec fields normally don't actually exist but are part 2076 // of a timeval struct 2077 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2078 s.replace("e_nsec", ".tv_nsec") 2079 } 2080 // FIXME: appears that `epoll_event.data` is an union 2081 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 2082 s => s.to_string(), 2083 } 2084 }); 2085 2086 cfg.skip_type(move |ty| { 2087 match ty { 2088 // sighandler_t is crazy across platforms 2089 // FIXME: is this necessary? 2090 "sighandler_t" => true, 2091 2092 _ => false, 2093 } 2094 }); 2095 2096 cfg.skip_struct(move |ty| { 2097 match ty { 2098 // This is actually a union, not a struct 2099 // FIXME: is this necessary? 2100 "sigval" => true, 2101 2102 // FIXME: It was removed in 2103 // emscripten-core/emscripten@953e414 2104 "pthread_mutexattr_t" => true, 2105 2106 // FIXME: Investigate why the test fails. 2107 // Skip for now to unblock CI. 2108 "pthread_condattr_t" => true, 2109 2110 _ => false, 2111 } 2112 }); 2113 2114 cfg.skip_fn(move |name| { 2115 match name { 2116 // FIXME: https://github.com/rust-lang/libc/issues/1272 2117 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2118 2119 // FIXME: Investigate why CI is missing it. 2120 "clearenv" => true, 2121 2122 _ => false, 2123 } 2124 }); 2125 2126 cfg.skip_const(move |name| { 2127 match name { 2128 // FIXME: deprecated - SIGNUNUSED was removed in glibc 2.26 2129 // users should use SIGSYS instead 2130 "SIGUNUSED" => true, 2131 2132 // FIXME: emscripten uses different constants to constructs these 2133 n if n.contains("__SIZEOF_PTHREAD") => true, 2134 2135 // FIXME: `SYS_gettid` was removed in 2136 // emscripten-core/emscripten@6d6474e 2137 "SYS_gettid" => true, 2138 2139 _ => false, 2140 } 2141 }); 2142 2143 cfg.skip_field_type(move |struct_, field| { 2144 // This is a weird union, don't check the type. 2145 // FIXME: is this necessary? 2146 (struct_ == "ifaddrs" && field == "ifa_ifu") || 2147 // sighandler_t type is super weird 2148 // FIXME: is this necessary? 2149 (struct_ == "sigaction" && field == "sa_sigaction") || 2150 // sigval is actually a union, but we pretend it's a struct 2151 // FIXME: is this necessary? 2152 (struct_ == "sigevent" && field == "sigev_value") || 2153 // aio_buf is "volatile void*" and Rust doesn't understand volatile 2154 // FIXME: is this necessary? 2155 (struct_ == "aiocb" && field == "aio_buf") 2156 }); 2157 2158 cfg.skip_field(move |struct_, field| { 2159 // this is actually a union on linux, so we can't represent it well and 2160 // just insert some padding. 2161 // FIXME: is this necessary? 2162 (struct_ == "siginfo_t" && field == "_pad") || 2163 // musl names this __dummy1 but it's still there 2164 // FIXME: is this necessary? 2165 (struct_ == "glob_t" && field == "gl_flags") || 2166 // musl seems to define this as an *anonymous* bitfield 2167 // FIXME: is this necessary? 2168 (struct_ == "statvfs" && field == "__f_unused") || 2169 // sigev_notify_thread_id is actually part of a sigev_un union 2170 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 2171 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet. 2172 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 2173 field == "_pad2" || 2174 field == "ssi_syscall" || 2175 field == "ssi_call_addr" || 2176 field == "ssi_arch")) 2177 }); 2178 2179 // FIXME: test linux like 2180 cfg.generate("../src/lib.rs", "main.rs"); 2181 } 2182 2183 fn test_vxworks(target: &str) { 2184 assert!(target.contains("vxworks")); 2185 2186 let mut cfg = ctest::TestGenerator::new(); 2187 headers! { cfg: 2188 "vxWorks.h", 2189 "yvals.h", 2190 "nfs/nfsCommon.h", 2191 "rtpLibCommon.h", 2192 "randomNumGen.h", 2193 "taskLib.h", 2194 "sysLib.h", 2195 "ioLib.h", 2196 "inetLib.h", 2197 "socket.h", 2198 "errnoLib.h", 2199 "ctype.h", 2200 "dirent.h", 2201 "dlfcn.h", 2202 "elf.h", 2203 "fcntl.h", 2204 "grp.h", 2205 "sys/poll.h", 2206 "ifaddrs.h", 2207 "langinfo.h", 2208 "limits.h", 2209 "link.h", 2210 "locale.h", 2211 "sys/stat.h", 2212 "netdb.h", 2213 "pthread.h", 2214 "pwd.h", 2215 "sched.h", 2216 "semaphore.h", 2217 "signal.h", 2218 "stddef.h", 2219 "stdint.h", 2220 "stdio.h", 2221 "stdlib.h", 2222 "string.h", 2223 "sys/file.h", 2224 "sys/ioctl.h", 2225 "sys/socket.h", 2226 "sys/time.h", 2227 "sys/times.h", 2228 "sys/types.h", 2229 "sys/uio.h", 2230 "sys/un.h", 2231 "sys/utsname.h", 2232 "sys/wait.h", 2233 "netinet/tcp.h", 2234 "syslog.h", 2235 "termios.h", 2236 "time.h", 2237 "ucontext.h", 2238 "unistd.h", 2239 "utime.h", 2240 "wchar.h", 2241 "errno.h", 2242 "sys/mman.h", 2243 "pathLib.h", 2244 "mqueue.h", 2245 } 2246 // FIXME 2247 cfg.skip_const(move |name| match name { 2248 // sighandler_t weirdness 2249 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" 2250 // This is not defined in vxWorks 2251 | "RTLD_DEFAULT" => true, 2252 _ => false, 2253 }); 2254 // FIXME 2255 cfg.skip_type(move |ty| match ty { 2256 "stat64" | "sighandler_t" | "off64_t" => true, 2257 _ => false, 2258 }); 2259 2260 cfg.skip_field_type(move |struct_, field| match (struct_, field) { 2261 ("siginfo_t", "si_value") 2262 | ("stat", "st_size") 2263 | ("sigaction", "sa_u") => true, 2264 _ => false, 2265 }); 2266 2267 cfg.skip_roundtrip(move |s| match s { 2268 _ => false, 2269 }); 2270 2271 cfg.type_name(move |ty, is_struct, is_union| match ty { 2272 "DIR" | "FILE" | "Dl_info" | "RTP_DESC" => ty.to_string(), 2273 t if is_union => format!("union {}", t), 2274 t if t.ends_with("_t") => t.to_string(), 2275 t if is_struct => format!("struct {}", t), 2276 t => t.to_string(), 2277 }); 2278 2279 // FIXME 2280 cfg.skip_fn(move |name| match name { 2281 // sigval 2282 "sigqueue" | "_sigqueue" 2283 // sighandler_t 2284 | "signal" 2285 // not used in static linking by default 2286 | "dlerror" => true, 2287 _ => false, 2288 }); 2289 2290 cfg.generate("../src/lib.rs", "main.rs"); 2291 } 2292 2293 fn test_linux(target: &str) { 2294 assert!(target.contains("linux")); 2295 2296 // target_env 2297 let gnu = target.contains("gnu"); 2298 let musl = target.contains("musl"); 2299 let uclibc = target.contains("uclibc"); 2300 2301 match (gnu, musl, uclibc) { 2302 (true, false, false) => (), 2303 (false, true, false) => (), 2304 (false, false, true) => (), 2305 (_, _, _) => panic!( 2306 "linux target lib is gnu: {}, musl: {}, uclibc: {}", 2307 gnu, musl, uclibc 2308 ), 2309 } 2310 2311 let arm = target.contains("arm"); 2312 let i686 = target.contains("i686"); 2313 let mips = target.contains("mips"); 2314 let mips32 = mips && !target.contains("64"); 2315 let mips64 = mips && target.contains("64"); 2316 let ppc64 = target.contains("powerpc64"); 2317 let s390x = target.contains("s390x"); 2318 let sparc64 = target.contains("sparc64"); 2319 let x32 = target.contains("x32"); 2320 let x86_32 = target.contains("i686"); 2321 let x86_64 = target.contains("x86_64"); 2322 let aarch64_musl = target.contains("aarch64") && musl; 2323 let gnuabihf = target.contains("gnueabihf"); 2324 let x86_64_gnux32 = target.contains("gnux32") && x86_64; 2325 let riscv64 = target.contains("riscv64"); 2326 2327 let mut cfg = ctest_cfg(); 2328 cfg.define("_GNU_SOURCE", None); 2329 // This macro re-deifnes fscanf,scanf,sscanf to link to the symbols that are 2330 // deprecated since glibc >= 2.29. This allows Rust binaries to link against 2331 // glibc versions older than 2.29. 2332 cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None); 2333 2334 headers! { cfg: 2335 "ctype.h", 2336 "dirent.h", 2337 "dlfcn.h", 2338 "elf.h", 2339 "fcntl.h", 2340 "glob.h", 2341 "grp.h", 2342 "ifaddrs.h", 2343 "langinfo.h", 2344 "limits.h", 2345 "link.h", 2346 "locale.h", 2347 "malloc.h", 2348 "mntent.h", 2349 "mqueue.h", 2350 "net/ethernet.h", 2351 "net/if.h", 2352 "net/if_arp.h", 2353 "net/route.h", 2354 "netdb.h", 2355 "netinet/in.h", 2356 "netinet/ip.h", 2357 "netinet/tcp.h", 2358 "netinet/udp.h", 2359 "netpacket/packet.h", 2360 "poll.h", 2361 "pthread.h", 2362 "pty.h", 2363 "pwd.h", 2364 "regex.h", 2365 "resolv.h", 2366 "sched.h", 2367 "semaphore.h", 2368 "shadow.h", 2369 "signal.h", 2370 "spawn.h", 2371 "stddef.h", 2372 "stdint.h", 2373 "stdio.h", 2374 "stdlib.h", 2375 "string.h", 2376 "sys/epoll.h", 2377 "sys/eventfd.h", 2378 "sys/file.h", 2379 "sys/fsuid.h", 2380 "sys/inotify.h", 2381 "sys/ioctl.h", 2382 "sys/ipc.h", 2383 "sys/mman.h", 2384 "sys/mount.h", 2385 "sys/msg.h", 2386 "sys/personality.h", 2387 "sys/prctl.h", 2388 "sys/ptrace.h", 2389 "sys/quota.h", 2390 "sys/random.h", 2391 "sys/reboot.h", 2392 "sys/resource.h", 2393 "sys/sem.h", 2394 "sys/sendfile.h", 2395 "sys/shm.h", 2396 "sys/signalfd.h", 2397 "sys/socket.h", 2398 "sys/stat.h", 2399 "sys/statvfs.h", 2400 "sys/swap.h", 2401 "sys/syscall.h", 2402 "sys/time.h", 2403 "sys/timerfd.h", 2404 "sys/times.h", 2405 "sys/timex.h", 2406 "sys/types.h", 2407 "sys/uio.h", 2408 "sys/un.h", 2409 "sys/user.h", 2410 "sys/utsname.h", 2411 "sys/vfs.h", 2412 "sys/wait.h", 2413 "syslog.h", 2414 "termios.h", 2415 "time.h", 2416 "ucontext.h", 2417 "unistd.h", 2418 "utime.h", 2419 "utmp.h", 2420 "utmpx.h", 2421 "wchar.h", 2422 "errno.h", 2423 // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit 2424 // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162 2425 // Also unavailable on gnuabihf with glibc 2.30. 2426 // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6b33f373c7b9199e00ba5fbafd94ac9bfb4337b1 2427 [(x86_64 || x86_32 || arm) && !gnuabihf]: "sys/io.h", 2428 // `sys/reg.h` is only available on x86 and x86_64 2429 [x86_64 || x86_32]: "sys/reg.h", 2430 // sysctl system call is deprecated and not available on musl 2431 // It is also unsupported in x32, deprecated since glibc 2.30: 2432 [!(x32 || musl || gnu)]: "sys/sysctl.h", 2433 // <execinfo.h> is not supported by musl: 2434 // https://www.openwall.com/lists/musl/2015/04/09/3 2435 [!musl]: "execinfo.h", 2436 } 2437 2438 // Include linux headers at the end: 2439 headers! { 2440 cfg: 2441 "asm/mman.h", 2442 "linux/dccp.h", 2443 "linux/errqueue.h", 2444 "linux/falloc.h", 2445 "linux/fs.h", 2446 "linux/futex.h", 2447 "linux/genetlink.h", 2448 "linux/if.h", 2449 "linux/if_addr.h", 2450 "linux/if_alg.h", 2451 "linux/if_ether.h", 2452 "linux/if_tun.h", 2453 "linux/input.h", 2454 "linux/keyctl.h", 2455 "linux/magic.h", 2456 "linux/memfd.h", 2457 "linux/mman.h", 2458 "linux/module.h", 2459 "linux/net_tstamp.h", 2460 "linux/netfilter/nfnetlink.h", 2461 "linux/netfilter/nfnetlink_log.h", 2462 "linux/netfilter/nfnetlink_queue.h", 2463 "linux/netfilter/nf_tables.h", 2464 "linux/netfilter_ipv4.h", 2465 "linux/netfilter_ipv6.h", 2466 "linux/netfilter_ipv6/ip6_tables.h", 2467 "linux/netlink.h", 2468 "linux/quota.h", 2469 "linux/random.h", 2470 "linux/reboot.h", 2471 "linux/rtnetlink.h", 2472 "linux/seccomp.h", 2473 "linux/sockios.h", 2474 "linux/vm_sockets.h", 2475 "linux/wait.h", 2476 "sys/auxv.h", 2477 "sys/fanotify.h", 2478 } 2479 2480 // note: aio.h must be included before sys/mount.h 2481 headers! { 2482 cfg: 2483 "sys/xattr.h", 2484 "sys/sysinfo.h", 2485 "aio.h", 2486 } 2487 2488 cfg.type_name(move |ty, is_struct, is_union| { 2489 match ty { 2490 // Just pass all these through, no need for a "struct" prefix 2491 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" 2492 | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym" 2493 | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr" 2494 | "Elf64_Chdr" => ty.to_string(), 2495 2496 t if is_union => format!("union {}", t), 2497 2498 t if t.ends_with("_t") => t.to_string(), 2499 2500 // In MUSL `flock64` is a typedef to `flock`. 2501 "flock64" if musl => format!("struct {}", ty), 2502 2503 // put `struct` in front of all structs:. 2504 t if is_struct => format!("struct {}", t), 2505 2506 t => t.to_string(), 2507 } 2508 }); 2509 2510 cfg.field_name(move |struct_, field| { 2511 match field { 2512 // Our stat *_nsec fields normally don't actually exist but are part 2513 // of a timeval struct 2514 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2515 s.replace("e_nsec", ".tv_nsec") 2516 } 2517 // FIXME: epoll_event.data is actuall a union in C, but in Rust 2518 // it is only a u64 because we only expose one field 2519 // http://man7.org/linux/man-pages/man2/epoll_wait.2.html 2520 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 2521 // The following structs have a field called `type` in C, 2522 // but `type` is a Rust keyword, so these fields are translated 2523 // to `type_` in Rust. 2524 "type_" 2525 if struct_ == "input_event" 2526 || struct_ == "input_mask" 2527 || struct_ == "ff_effect" => 2528 { 2529 "type".to_string() 2530 } 2531 2532 s => s.to_string(), 2533 } 2534 }); 2535 2536 cfg.skip_type(move |ty| { 2537 match ty { 2538 // FIXME: `sighandler_t` type is incorrect, see: 2539 // https://github.com/rust-lang/libc/issues/1359 2540 "sighandler_t" => true, 2541 2542 // These cannot be tested when "resolv.h" is included and are tested 2543 // in the `linux_elf.rs` file. 2544 "Elf64_Phdr" | "Elf32_Phdr" => true, 2545 2546 // This type is private on Linux. It is implemented as a C `enum` 2547 // (`c_uint`) and this clashes with the type of the `rlimit` APIs 2548 // which expect a `c_int` even though both are ABI compatible. 2549 "__rlimit_resource_t" => true, 2550 2551 _ => false, 2552 } 2553 }); 2554 2555 cfg.skip_struct(move |ty| { 2556 match ty { 2557 // These cannot be tested when "resolv.h" is included and are tested 2558 // in the `linux_elf.rs` file. 2559 "Elf64_Phdr" | "Elf32_Phdr" => true, 2560 2561 // On Linux, the type of `ut_tv` field of `struct utmpx` 2562 // can be an anonymous struct, so an extra struct, 2563 // which is absent in glibc, has to be defined. 2564 "__timeval" => true, 2565 2566 // FIXME: This is actually a union, not a struct 2567 "sigval" => true, 2568 2569 // This type is tested in the `linux_termios.rs` file since there 2570 // are header conflicts when including them with all the other 2571 // structs. 2572 "termios2" => true, 2573 2574 // FIXME: remove once we set minimum supported glibc version. 2575 // ucontext_t added a new field as of glibc 2.28; our struct definition is 2576 // conservative and omits the field, but that means the size doesn't match for newer 2577 // glibcs (see https://github.com/rust-lang/libc/issues/1410) 2578 "ucontext_t" if gnu => true, 2579 2580 // FIXME: Somehow we cannot include headers correctly in glibc 2.30. 2581 // So let's ignore for now and re-visit later. 2582 // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085 2583 "statx" => true, 2584 "statx_timestamp" => true, 2585 2586 // On Linux, the type of `ut_exit` field of struct `utmpx` 2587 // can be an anonymous struct, so an extra struct, 2588 // which is absent in musl, has to be defined. 2589 "__exit_status" if musl => true, 2590 2591 _ => false, 2592 } 2593 }); 2594 2595 cfg.skip_const(move |name| { 2596 match name { 2597 // These constants are not available if gnu headers have been included 2598 // and can therefore not be tested here 2599 // 2600 // The IPV6 constants are tested in the `linux_ipv6.rs` tests: 2601 | "IPV6_FLOWINFO" 2602 | "IPV6_FLOWLABEL_MGR" 2603 | "IPV6_FLOWINFO_SEND" 2604 | "IPV6_FLOWINFO_FLOWLABEL" 2605 | "IPV6_FLOWINFO_PRIORITY" 2606 // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: 2607 | "F_CANCELLK" 2608 | "F_ADD_SEALS" 2609 | "F_GET_SEALS" 2610 | "F_SEAL_SEAL" 2611 | "F_SEAL_SHRINK" 2612 | "F_SEAL_GROW" 2613 | "F_SEAL_WRITE" => true, 2614 2615 // The musl-sanitized kernel headers used in CI 2616 // target the Linux kernel 4.4 and do not contain the 2617 // following constants: 2618 // 2619 // Requires Linux kernel 4.9 2620 | "FALLOC_FL_UNSHARE_RANGE" 2621 // 2622 // Require Linux kernel 5.x: 2623 | "MSG_COPY" 2624 if musl => true, 2625 // Require Linux kernel 5.1: 2626 "F_SEAL_FUTURE_WRITE" => true, 2627 2628 // The musl version 1.1.24 used in CI does not 2629 // contain these glibc constants yet: 2630 | "RLIMIT_RTTIME" // should be in `resource.h` 2631 | "TCP_COOKIE_TRANSACTIONS" // should be in the `netinet/tcp.h` header 2632 if musl => true, 2633 2634 // FIXME: deprecated: not available in any header 2635 // See: https://github.com/rust-lang/libc/issues/1356 2636 "ENOATTR" => true, 2637 2638 // FIXME: SIGUNUSED was removed in glibc 2.26 2639 // Users should use SIGSYS instead. 2640 "SIGUNUSED" => true, 2641 2642 // FIXME: conflicts with glibc headers and is tested in 2643 // `linux_termios.rs` below: 2644 "BOTHER" => true, 2645 2646 // FIXME: on musl the pthread types are defined a little differently 2647 // - these constants are used by the glibc implementation. 2648 n if musl && n.contains("__SIZEOF_PTHREAD") => true, 2649 2650 // FIXME: It was extended to 4096 since glibc 2.31 (Linux 5.4). 2651 // We should do so after a while. 2652 "SOMAXCONN" if gnu => true, 2653 2654 // deprecated: not available from Linux kernel 5.6: 2655 "VMADDR_CID_RESERVED" => true, 2656 2657 // Require Linux kernel 5.6: 2658 "VMADDR_CID_LOCAL" => true, 2659 2660 // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP: 2661 | "IPPROTO_MAX" 2662 | "IPPROTO_MPTCP" => true, 2663 2664 // Defined in kernel headers but musl removes it; need musl 1.2 for definition in musl 2665 // headers. 2666 "P_PIDFD" => true, 2667 2668 // FIXME: Not currently available in headers 2669 "SYS_pidfd_open" if mips => true, 2670 2671 // FIXME: Not currently available in headers on MIPS 2672 // Not yet implemented on sparc64 2673 "SYS_clone3" if mips | sparc64 => true, 2674 2675 _ => false, 2676 } 2677 }); 2678 2679 cfg.skip_fn(move |name| { 2680 // skip those that are manually verified 2681 match name { 2682 // FIXME: https://github.com/rust-lang/libc/issues/1272 2683 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2684 2685 // There are two versions of the sterror_r function, see 2686 // 2687 // https://linux.die.net/man/3/strerror_r 2688 // 2689 // An XSI-compliant version provided if: 2690 // 2691 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) 2692 // && ! _GNU_SOURCE 2693 // 2694 // and a GNU specific version provided if _GNU_SOURCE is defined. 2695 // 2696 // libc provides bindings for the XSI-compliant version, which is 2697 // preferred for portable applications. 2698 // 2699 // We skip the test here since here _GNU_SOURCE is defined, and 2700 // test the XSI version below. 2701 "strerror_r" => true, 2702 2703 // FIXME: Our API is unsound. The Rust API allows aliasing 2704 // pointers, but the C API requires pointers not to alias. 2705 // We should probably be at least using `&`/`&mut` here, see: 2706 // https://github.com/gnzlbg/ctest/issues/68 2707 "lio_listio" if musl => true, 2708 2709 // FIXME: the glibc version used by the Sparc64 build jobs 2710 // which use Debian 10.0 is too old. 2711 "statx" if sparc64 => true, 2712 2713 // FIXME: Deprecated since glibc 2.30. Remove fn once upstream does. 2714 "sysctl" if gnu => true, 2715 2716 // FIXME: It now takes c_void instead of timezone since glibc 2.31. 2717 "gettimeofday" if gnu => true, 2718 2719 _ => false, 2720 } 2721 }); 2722 2723 cfg.skip_field_type(move |struct_, field| { 2724 // This is a weird union, don't check the type. 2725 (struct_ == "ifaddrs" && field == "ifa_ifu") || 2726 // sighandler_t type is super weird 2727 (struct_ == "sigaction" && field == "sa_sigaction") || 2728 // __timeval type is a patch which doesn't exist in glibc 2729 (struct_ == "utmpx" && field == "ut_tv") || 2730 // sigval is actually a union, but we pretend it's a struct 2731 (struct_ == "sigevent" && field == "sigev_value") || 2732 // this one is an anonymous union 2733 (struct_ == "ff_effect" && field == "u") || 2734 // `__exit_status` type is a patch which is absent in musl 2735 (struct_ == "utmpx" && field == "ut_exit" && musl) 2736 }); 2737 2738 cfg.volatile_item(|i| { 2739 use ctest::VolatileItemKind::*; 2740 match i { 2741 // aio_buf is a volatile void** but since we cannot express that in 2742 // Rust types, we have to explicitly tell the checker about it here: 2743 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => { 2744 true 2745 } 2746 _ => false, 2747 } 2748 }); 2749 2750 cfg.skip_field(move |struct_, field| { 2751 // this is actually a union on linux, so we can't represent it well and 2752 // just insert some padding. 2753 (struct_ == "siginfo_t" && field == "_pad") || 2754 // musl names this __dummy1 but it's still there 2755 (musl && struct_ == "glob_t" && field == "gl_flags") || 2756 // musl seems to define this as an *anonymous* bitfield 2757 (musl && struct_ == "statvfs" && field == "__f_unused") || 2758 // sigev_notify_thread_id is actually part of a sigev_un union 2759 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 2760 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release 2761 // has them yet. 2762 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 2763 field == "_pad2" || 2764 field == "ssi_syscall" || 2765 field == "ssi_call_addr" || 2766 field == "ssi_arch")) || 2767 // FIXME: After musl 1.1.24, it have only one field `sched_priority`, 2768 // while other fields become reserved. 2769 (struct_ == "sched_param" && [ 2770 "sched_ss_low_priority", 2771 "sched_ss_repl_period", 2772 "sched_ss_init_budget", 2773 "sched_ss_max_repl", 2774 ].contains(&field) && musl) || 2775 // FIXME: After musl 1.1.24, the type becomes `int` instead of `unsigned short`. 2776 (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) || 2777 // glibc uses unnamed fields here and Rust doesn't support that yet 2778 (struct_ == "timex" && field.starts_with("__unused")) || 2779 // FIXME: It now takes mode_t since glibc 2.31 on some targets. 2780 (struct_ == "ipc_perm" && field == "mode" 2781 && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32) 2782 ) 2783 }); 2784 2785 cfg.skip_roundtrip(move |s| match s { 2786 // FIXME: 2787 "utsname" if mips32 || mips64 => true, 2788 // FIXME: 2789 "mcontext_t" if s390x => true, 2790 // FIXME: This is actually a union. 2791 "fpreg_t" if s390x => true, 2792 2793 "sockaddr_un" | "sembuf" | "ff_constant_effect" 2794 if mips32 && (gnu || musl) => 2795 { 2796 true 2797 } 2798 "ipv6_mreq" 2799 | "ip_mreq_source" 2800 | "sockaddr_in6" 2801 | "sockaddr_ll" 2802 | "in_pktinfo" 2803 | "arpreq" 2804 | "arpreq_old" 2805 | "sockaddr_un" 2806 | "ff_constant_effect" 2807 | "ff_ramp_effect" 2808 | "ff_condition_effect" 2809 | "Elf32_Ehdr" 2810 | "Elf32_Chdr" 2811 | "ucred" 2812 | "in6_pktinfo" 2813 | "sockaddr_nl" 2814 | "termios" 2815 | "nlmsgerr" 2816 if (mips64 || sparc64) && gnu => 2817 { 2818 true 2819 } 2820 2821 // FIXME: the call ABI of max_align_t is incorrect on these platforms: 2822 "max_align_t" if i686 || mips64 || ppc64 => true, 2823 2824 _ => false, 2825 }); 2826 2827 cfg.generate("../src/lib.rs", "main.rs"); 2828 2829 test_linux_like_apis(target); 2830 } 2831 2832 // This function tests APIs that are incompatible to test when other APIs 2833 // are included (e.g. because including both sets of headers clashes) 2834 fn test_linux_like_apis(target: &str) { 2835 let musl = target.contains("musl"); 2836 let linux = target.contains("linux"); 2837 let emscripten = target.contains("emscripten"); 2838 let android = target.contains("android"); 2839 assert!(linux || android || emscripten); 2840 2841 if linux || android || emscripten { 2842 // test strerror_r from the `string.h` header 2843 let mut cfg = ctest_cfg(); 2844 cfg.skip_type(|_| true).skip_static(|_| true); 2845 2846 headers! { cfg: "string.h" } 2847 cfg.skip_fn(|f| match f { 2848 "strerror_r" => false, 2849 _ => true, 2850 }) 2851 .skip_const(|_| true) 2852 .skip_struct(|_| true); 2853 cfg.generate("../src/lib.rs", "linux_strerror_r.rs"); 2854 } 2855 2856 if linux || android || emscripten { 2857 // test fcntl - see: 2858 // http://man7.org/linux/man-pages/man2/fcntl.2.html 2859 let mut cfg = ctest_cfg(); 2860 2861 if musl { 2862 cfg.header("fcntl.h"); 2863 } else { 2864 cfg.header("linux/fcntl.h"); 2865 } 2866 2867 cfg.skip_type(|_| true) 2868 .skip_static(|_| true) 2869 .skip_struct(|_| true) 2870 .skip_fn(|_| true) 2871 .skip_const(move |name| match name { 2872 // test fcntl constants: 2873 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" 2874 | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" 2875 | "F_SEAL_WRITE" => false, 2876 _ => true, 2877 }) 2878 .type_name(move |ty, is_struct, is_union| match ty { 2879 t if is_struct => format!("struct {}", t), 2880 t if is_union => format!("union {}", t), 2881 t => t.to_string(), 2882 }); 2883 2884 cfg.generate("../src/lib.rs", "linux_fcntl.rs"); 2885 } 2886 2887 if linux || android { 2888 // test termios 2889 let mut cfg = ctest_cfg(); 2890 cfg.header("asm/termbits.h"); 2891 cfg.skip_type(|_| true) 2892 .skip_static(|_| true) 2893 .skip_fn(|_| true) 2894 .skip_const(|c| c != "BOTHER") 2895 .skip_struct(|s| s != "termios2") 2896 .type_name(move |ty, is_struct, is_union| match ty { 2897 t if is_struct => format!("struct {}", t), 2898 t if is_union => format!("union {}", t), 2899 t => t.to_string(), 2900 }); 2901 cfg.generate("../src/lib.rs", "linux_termios.rs"); 2902 } 2903 2904 if linux || android { 2905 // test IPV6_ constants: 2906 let mut cfg = ctest_cfg(); 2907 headers! { 2908 cfg: 2909 "linux/in6.h" 2910 } 2911 cfg.skip_type(|_| true) 2912 .skip_static(|_| true) 2913 .skip_fn(|_| true) 2914 .skip_const(|_| true) 2915 .skip_struct(|_| true) 2916 .skip_const(move |name| match name { 2917 "IPV6_FLOWINFO" 2918 | "IPV6_FLOWLABEL_MGR" 2919 | "IPV6_FLOWINFO_SEND" 2920 | "IPV6_FLOWINFO_FLOWLABEL" 2921 | "IPV6_FLOWINFO_PRIORITY" => false, 2922 _ => true, 2923 }) 2924 .type_name(move |ty, is_struct, is_union| match ty { 2925 t if is_struct => format!("struct {}", t), 2926 t if is_union => format!("union {}", t), 2927 t => t.to_string(), 2928 }); 2929 cfg.generate("../src/lib.rs", "linux_ipv6.rs"); 2930 } 2931 2932 if linux || android { 2933 // Test Elf64_Phdr and Elf32_Phdr 2934 // These types have a field called `p_type`, but including 2935 // "resolve.h" defines a `p_type` macro that expands to `__p_type` 2936 // making the tests for these fails when both are included. 2937 let mut cfg = ctest_cfg(); 2938 cfg.header("elf.h"); 2939 cfg.skip_fn(|_| true) 2940 .skip_static(|_| true) 2941 .skip_fn(|_| true) 2942 .skip_const(|_| true) 2943 .type_name(move |ty, _is_struct, _is_union| ty.to_string()) 2944 .skip_struct(move |ty| match ty { 2945 "Elf64_Phdr" | "Elf32_Phdr" => false, 2946 _ => true, 2947 }) 2948 .skip_type(move |ty| match ty { 2949 "Elf64_Phdr" | "Elf32_Phdr" => false, 2950 _ => true, 2951 }); 2952 cfg.generate("../src/lib.rs", "linux_elf.rs"); 2953 } 2954 } 2955 2956 fn which_freebsd() -> Option<i32> { 2957 let output = std::process::Command::new("freebsd-version") 2958 .output() 2959 .ok()?; 2960 if !output.status.success() { 2961 return None; 2962 } 2963 2964 let stdout = String::from_utf8(output.stdout).ok()?; 2965 2966 match &stdout { 2967 s if s.starts_with("10") => Some(10), 2968 s if s.starts_with("11") => Some(11), 2969 s if s.starts_with("12") => Some(12), 2970 s if s.starts_with("13") => Some(13), 2971 _ => None, 2972 } 2973 } 2974