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