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/epoll.h", 1426 "sys/eventfd.h", 1427 "sys/file.h", 1428 "sys/fsuid.h", 1429 "sys/inotify.h", 1430 "sys/ioctl.h", 1431 "sys/mman.h", 1432 "sys/mount.h", 1433 "sys/personality.h", 1434 "sys/prctl.h", 1435 "sys/ptrace.h", 1436 "sys/random.h", 1437 "sys/reboot.h", 1438 "sys/resource.h", 1439 "sys/sendfile.h", 1440 "sys/signalfd.h", 1441 "sys/socket.h", 1442 "sys/stat.h", 1443 "sys/statvfs.h", 1444 "sys/swap.h", 1445 "sys/syscall.h", 1446 "sys/sysinfo.h", 1447 "sys/time.h", 1448 "sys/times.h", 1449 "sys/timerfd.h", 1450 "sys/types.h", 1451 "sys/ucontext.h", 1452 "sys/uio.h", 1453 "sys/un.h", 1454 "sys/utsname.h", 1455 "sys/vfs.h", 1456 "sys/xattr.h", 1457 "sys/wait.h", 1458 "syslog.h", 1459 "termios.h", 1460 "time.h", 1461 "unistd.h", 1462 "utime.h", 1463 "utmp.h", 1464 "wchar.h", 1465 "xlocale.h", 1466 // time64_t is not defined for 64-bit targets If included it will 1467 // generate the error 'Your time_t is already 64-bit' 1468 [target_pointer_width == 32]: "time64.h", 1469 [x86]: "sys/reg.h", 1470 } 1471 1472 // Include linux headers at the end: 1473 headers! { cfg: 1474 "asm/mman.h", 1475 "linux/dccp.h", 1476 "linux/errqueue.h", 1477 "linux/falloc.h", 1478 "linux/futex.h", 1479 "linux/fs.h", 1480 "linux/genetlink.h", 1481 "linux/if_alg.h", 1482 "linux/if_ether.h", 1483 "linux/if_tun.h", 1484 "linux/magic.h", 1485 "linux/memfd.h", 1486 "linux/module.h", 1487 "linux/net_tstamp.h", 1488 "linux/netfilter/nfnetlink.h", 1489 "linux/netfilter/nfnetlink_log.h", 1490 "linux/netfilter/nfnetlink_queue.h", 1491 "linux/netfilter/nf_tables.h", 1492 "linux/netfilter_ipv4.h", 1493 "linux/netfilter_ipv6.h", 1494 "linux/netfilter_ipv6/ip6_tables.h", 1495 "linux/netlink.h", 1496 "linux/quota.h", 1497 "linux/reboot.h", 1498 "linux/seccomp.h", 1499 "linux/sched.h", 1500 "linux/sockios.h", 1501 "linux/vm_sockets.h", 1502 "linux/wait.h", 1503 1504 } 1505 1506 cfg.type_name(move |ty, is_struct, is_union| { 1507 match ty { 1508 // Just pass all these through, no need for a "struct" prefix 1509 "FILE" | "fd_set" | "Dl_info" => ty.to_string(), 1510 1511 t if is_union => format!("union {}", t), 1512 1513 t if t.ends_with("_t") => t.to_string(), 1514 1515 // sigval is a struct in Rust, but a union in C: 1516 "sigval" => format!("union sigval"), 1517 1518 // put `struct` in front of all structs:. 1519 t if is_struct => format!("struct {}", t), 1520 1521 t => t.to_string(), 1522 } 1523 }); 1524 1525 cfg.field_name(move |struct_, field| { 1526 match field { 1527 // Our stat *_nsec fields normally don't actually exist but are part 1528 // of a timeval struct 1529 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 1530 s.to_string() 1531 } 1532 // FIXME: appears that `epoll_event.data` is an union 1533 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 1534 s => s.to_string(), 1535 } 1536 }); 1537 1538 cfg.skip_type(move |ty| { 1539 match ty { 1540 // FIXME: `sighandler_t` type is incorrect, see: 1541 // https://github.com/rust-lang/libc/issues/1359 1542 "sighandler_t" => true, 1543 _ => false, 1544 } 1545 }); 1546 1547 cfg.skip_struct(move |ty| { 1548 if ty.starts_with("__c_anonymous_") { 1549 return true; 1550 } 1551 match ty { 1552 // These are tested as part of the linux_fcntl tests since there are 1553 // header conflicts when including them with all the other structs. 1554 "termios2" => true, 1555 // uc_sigmask and uc_sigmask64 of ucontext_t are an anonymous union 1556 "ucontext_t" => true, 1557 1558 _ => false, 1559 } 1560 }); 1561 1562 cfg.skip_const(move |name| { 1563 match name { 1564 // FIXME: deprecated: not available in any header 1565 // See: https://github.com/rust-lang/libc/issues/1356 1566 "ENOATTR" => true, 1567 1568 // FIXME: still necessary? 1569 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 1570 // FIXME: deprecated - removed in glibc 2.26 1571 "SIGUNUSED" => true, 1572 1573 // Needs a newer Android SDK for the definition 1574 "P_PIDFD" => true, 1575 1576 // Requires Linux kernel 5.6 1577 "VMADDR_CID_LOCAL" => true, 1578 1579 _ => false, 1580 } 1581 }); 1582 1583 cfg.skip_fn(move |name| { 1584 // skip those that are manually verified 1585 match name { 1586 // FIXME: https://github.com/rust-lang/libc/issues/1272 1587 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 1588 1589 // There are two versions of the sterror_r function, see 1590 // 1591 // https://linux.die.net/man/3/strerror_r 1592 // 1593 // An XSI-compliant version provided if: 1594 // 1595 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE 1596 // 1597 // and a GNU specific version provided if _GNU_SOURCE is defined. 1598 // 1599 // libc provides bindings for the XSI-compliant version, which is 1600 // preferred for portable applications. 1601 // 1602 // We skip the test here since here _GNU_SOURCE is defined, and 1603 // test the XSI version below. 1604 "strerror_r" => true, 1605 1606 _ => false, 1607 } 1608 }); 1609 1610 cfg.skip_field_type(move |struct_, field| { 1611 // This is a weird union, don't check the type. 1612 (struct_ == "ifaddrs" && field == "ifa_ifu") || 1613 // sigval is actually a union, but we pretend it's a struct 1614 (struct_ == "sigevent" && field == "sigev_value") 1615 }); 1616 1617 cfg.skip_field(move |struct_, field| { 1618 // this is actually a union on linux, so we can't represent it well and 1619 // just insert some padding. 1620 (struct_ == "siginfo_t" && field == "_pad") || 1621 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 1622 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 1623 (struct_ == "sigaction" && field == "sa_sigaction") || 1624 // sigev_notify_thread_id is actually part of a sigev_un union 1625 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 1626 // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet. 1627 (struct_ == "signalfd_siginfo" && (field == "ssi_syscall" || 1628 field == "ssi_call_addr" || 1629 field == "ssi_arch")) 1630 }); 1631 1632 cfg.generate("../src/lib.rs", "main.rs"); 1633 1634 test_linux_like_apis(target); 1635 } 1636 1637 fn test_freebsd(target: &str) { 1638 assert!(target.contains("freebsd")); 1639 let mut cfg = ctest_cfg(); 1640 1641 let freebsd_ver = which_freebsd(); 1642 1643 match freebsd_ver { 1644 Some(10) => cfg.cfg("freebsd10", None), 1645 Some(11) => cfg.cfg("freebsd11", None), 1646 Some(12) => cfg.cfg("freebsd12", None), 1647 Some(13) => cfg.cfg("freebsd13", None), 1648 _ => &mut cfg, 1649 }; 1650 1651 // Required for `getline`: 1652 cfg.define("_WITH_GETLINE", None); 1653 // Required for making freebsd11_stat available in the headers 1654 match freebsd_ver { 1655 Some(10) => &mut cfg, 1656 _ => cfg.define("_WANT_FREEBSD11_STAT", None), 1657 }; 1658 1659 headers! { cfg: 1660 "aio.h", 1661 "arpa/inet.h", 1662 "ctype.h", 1663 "dirent.h", 1664 "dlfcn.h", 1665 "elf.h", 1666 "errno.h", 1667 "fcntl.h", 1668 "glob.h", 1669 "grp.h", 1670 "ifaddrs.h", 1671 "langinfo.h", 1672 "libutil.h", 1673 "limits.h", 1674 "link.h", 1675 "locale.h", 1676 "machine/reg.h", 1677 "mqueue.h", 1678 "net/bpf.h", 1679 "net/if.h", 1680 "net/if_arp.h", 1681 "net/if_dl.h", 1682 "net/route.h", 1683 "netdb.h", 1684 "netinet/ip.h", 1685 "netinet/in.h", 1686 "netinet/tcp.h", 1687 "netinet/udp.h", 1688 "poll.h", 1689 "pthread.h", 1690 "pthread_np.h", 1691 "pwd.h", 1692 "regex.h", 1693 "resolv.h", 1694 "sched.h", 1695 "semaphore.h", 1696 "signal.h", 1697 "spawn.h", 1698 "stddef.h", 1699 "stdint.h", 1700 "stdio.h", 1701 "stdlib.h", 1702 "string.h", 1703 "sys/event.h", 1704 "sys/extattr.h", 1705 "sys/file.h", 1706 "sys/ioctl.h", 1707 "sys/ipc.h", 1708 "sys/jail.h", 1709 "sys/mman.h", 1710 "sys/mount.h", 1711 "sys/msg.h", 1712 "sys/procdesc.h", 1713 "sys/ptrace.h", 1714 "sys/random.h", 1715 "sys/resource.h", 1716 "sys/rtprio.h", 1717 "sys/shm.h", 1718 "sys/socket.h", 1719 "sys/stat.h", 1720 "sys/statvfs.h", 1721 "sys/sysctl.h", 1722 "sys/time.h", 1723 "sys/times.h", 1724 "sys/timex.h", 1725 "sys/types.h", 1726 "sys/ucontext.h", 1727 "sys/uio.h", 1728 "sys/un.h", 1729 "sys/utsname.h", 1730 "sys/wait.h", 1731 "syslog.h", 1732 "termios.h", 1733 "time.h", 1734 "ufs/ufs/quota.h", 1735 "unistd.h", 1736 "utime.h", 1737 "utmpx.h", 1738 "wchar.h", 1739 } 1740 1741 cfg.type_name(move |ty, is_struct, is_union| { 1742 match ty { 1743 // Just pass all these through, no need for a "struct" prefix 1744 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" 1745 | "Elf64_Phdr" => ty.to_string(), 1746 1747 // FIXME: https://github.com/rust-lang/libc/issues/1273 1748 "sighandler_t" => "sig_t".to_string(), 1749 1750 t if is_union => format!("union {}", t), 1751 1752 t if t.ends_with("_t") => t.to_string(), 1753 1754 // sigval is a struct in Rust, but a union in C: 1755 "sigval" => format!("union sigval"), 1756 1757 // put `struct` in front of all structs:. 1758 t if is_struct => format!("struct {}", t), 1759 1760 t => t.to_string(), 1761 } 1762 }); 1763 1764 cfg.field_name(move |struct_, field| { 1765 match field { 1766 // Our stat *_nsec fields normally don't actually exist but are part 1767 // of a timeval struct 1768 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 1769 s.replace("e_nsec", ".tv_nsec") 1770 } 1771 // Field is named `type` in C but that is a Rust keyword, 1772 // so these fields are translated to `type_` in the bindings. 1773 "type_" if struct_ == "rtprio" => "type".to_string(), 1774 s => s.to_string(), 1775 } 1776 }); 1777 1778 cfg.skip_const(move |name| { 1779 match name { 1780 // These constants are to be introduced in yet-unreleased FreeBSD 12.2. 1781 "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" 1782 | "F_SEAL_SHRINK" | "F_SEAL_GROW" | "F_SEAL_WRITE" 1783 if Some(12) <= freebsd_ver => 1784 { 1785 true 1786 } 1787 1788 // These constants were introduced in FreeBSD 12: 1789 "SF_USER_READAHEAD" 1790 | "EVFILT_EMPTY" 1791 | "SO_REUSEPORT_LB" 1792 | "IP_ORIGDSTADDR" 1793 | "IP_RECVORIGDSTADDR" 1794 | "IPV6_ORIGDSTADDR" 1795 | "IPV6_RECVORIGDSTADDR" 1796 | "NI_NUMERICSCOPE" 1797 if Some(11) == freebsd_ver => 1798 { 1799 true 1800 } 1801 1802 // These constants were introduced in FreeBSD 11: 1803 "SF_USER_READAHEAD" 1804 | "SF_NOCACHE" 1805 | "RLIMIT_KQUEUES" 1806 | "RLIMIT_UMTXP" 1807 | "EVFILT_PROCDESC" 1808 | "EVFILT_SENDFILE" 1809 | "EVFILT_EMPTY" 1810 | "SO_REUSEPORT_LB" 1811 | "TCP_CCALGOOPT" 1812 | "TCP_PCAP_OUT" 1813 | "TCP_PCAP_IN" 1814 | "IP_BINDMULTI" 1815 | "IP_ORIGDSTADDR" 1816 | "IP_RECVORIGDSTADDR" 1817 | "IPV6_ORIGDSTADDR" 1818 | "IPV6_RECVORIGDSTADDR" 1819 | "PD_CLOEXEC" 1820 | "PD_ALLOWED_AT_FORK" 1821 | "IP_RSS_LISTEN_BUCKET" 1822 | "NI_NUMERICSCOPE" 1823 if Some(10) == freebsd_ver => 1824 { 1825 true 1826 } 1827 1828 // FIXME: This constant has a different value in FreeBSD 10: 1829 "RLIM_NLIMITS" if Some(10) == freebsd_ver => true, 1830 1831 // FIXME: There are deprecated - remove in a couple of releases. 1832 // These constants were removed in FreeBSD 11 (svn r273250) but will 1833 // still be accepted and ignored at runtime. 1834 "MAP_RENAME" | "MAP_NORESERVE" 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 r262489), 1838 // and they've never had any legitimate use outside of the 1839 // base system anyway. 1840 "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "USER_MAXID" => true, 1841 1842 // This constant was removed in FreeBSD 13 (svn r363622), and never 1843 // had any legitimate use outside of the base system anyway. 1844 "CTL_P1003_1B_MAXID" => true, 1845 1846 // This was renamed in FreeBSD 12.2 and 13 (r352486). 1847 "CTL_UNSPEC" | "CTL_SYSCTL" => true, 1848 1849 // These were added in FreeBSD 12.2 and 13 (r352486), 1850 // but they are just names for magic numbers that existed for ages. 1851 "CTL_SYSCTL_DEBUG" 1852 | "CTL_SYSCTL_NAME" 1853 | "CTL_SYSCTL_NEXT" 1854 | "CTL_SYSCTL_NAME2OID" 1855 | "CTL_SYSCTL_OIDFMT" 1856 | "CTL_SYSCTL_OIDDESCR" 1857 | "CTL_SYSCTL_OIDLABEL" => true, 1858 1859 // This was renamed in FreeBSD 12.2 and 13 (r350749). 1860 "IPPROTO_SEP" | "IPPROTO_DCCP" => true, 1861 1862 // This was changed to 96(0x60) in FreeBSD 13: 1863 // https://github.com/freebsd/freebsd/ 1864 // commit/06b00ceaa914a3907e4e27bad924f44612bae1d7 1865 "MINCORE_SUPER" if Some(13) == freebsd_ver => true, 1866 1867 // This was increased to 97 in FreeBSD 12.2 and 13. 1868 // https://github.com/freebsd/freebsd/ 1869 // commit/72a21ba0f62da5e86a1c0b462aeb3f5ff849a1b7 1870 "ELAST" if Some(12) == freebsd_ver => true, 1871 1872 _ => false, 1873 } 1874 }); 1875 1876 cfg.skip_struct(move |ty| { 1877 match ty { 1878 // `mmsghdr` is not available in FreeBSD 10 1879 "mmsghdr" if Some(10) == freebsd_ver => true, 1880 1881 // `max_align_t` is not available in FreeBSD 10 1882 "max_align_t" if Some(10) == freebsd_ver => true, 1883 1884 _ => false, 1885 } 1886 }); 1887 1888 cfg.skip_fn(move |name| { 1889 // skip those that are manually verified 1890 match name { 1891 // FIXME: https://github.com/rust-lang/libc/issues/1272 1892 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 1893 1894 // These functions were added in FreeBSD 11: 1895 "fdatasync" | "mq_getfd_np" | "sendmmsg" | "recvmmsg" 1896 if Some(10) == freebsd_ver => 1897 { 1898 true 1899 } 1900 1901 // This function changed its return type from `int` in FreeBSD10 to 1902 // `ssize_t` in FreeBSD11: 1903 "aio_waitcomplete" if Some(10) == freebsd_ver => true, 1904 1905 // The `uname` function in the `utsname.h` FreeBSD header is a C 1906 // inline function (has no symbol) that calls the `__xuname` symbol. 1907 // Therefore the function pointer comparison does not make sense for it. 1908 "uname" => true, 1909 1910 // FIXME: Our API is unsound. The Rust API allows aliasing 1911 // pointers, but the C API requires pointers not to alias. 1912 // We should probably be at least using `&`/`&mut` here, see: 1913 // https://github.com/gnzlbg/ctest/issues/68 1914 "lio_listio" => true, 1915 1916 _ => false, 1917 } 1918 }); 1919 1920 cfg.skip_signededness(move |c| { 1921 match c { 1922 // FIXME: has a different sign in FreeBSD10 1923 "blksize_t" if Some(10) == freebsd_ver => true, 1924 _ => false, 1925 } 1926 }); 1927 1928 cfg.volatile_item(|i| { 1929 use ctest::VolatileItemKind::*; 1930 match i { 1931 // aio_buf is a volatile void** but since we cannot express that in 1932 // Rust types, we have to explicitly tell the checker about it here: 1933 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => { 1934 true 1935 } 1936 _ => false, 1937 } 1938 }); 1939 1940 cfg.skip_field(move |struct_, field| { 1941 match (struct_, field) { 1942 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 1943 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 1944 ("sigaction", "sa_sigaction") => true, 1945 1946 // FIXME: in FreeBSD10 this field has type `char*` instead of 1947 // `void*`: 1948 ("stack_t", "ss_sp") if Some(10) == freebsd_ver => true, 1949 1950 // conflicting with `p_type` macro from <resolve.h>. 1951 ("Elf32_Phdr", "p_type") => true, 1952 ("Elf64_Phdr", "p_type") => true, 1953 1954 _ => false, 1955 } 1956 }); 1957 1958 cfg.generate("../src/lib.rs", "main.rs"); 1959 } 1960 1961 fn test_emscripten(target: &str) { 1962 assert!(target.contains("emscripten")); 1963 1964 let mut cfg = ctest_cfg(); 1965 cfg.define("_GNU_SOURCE", None); // FIXME: ?? 1966 1967 headers! { cfg: 1968 "aio.h", 1969 "ctype.h", 1970 "dirent.h", 1971 "dlfcn.h", 1972 "errno.h", 1973 "fcntl.h", 1974 "glob.h", 1975 "grp.h", 1976 "ifaddrs.h", 1977 "langinfo.h", 1978 "limits.h", 1979 "locale.h", 1980 "malloc.h", 1981 "mntent.h", 1982 "mqueue.h", 1983 "net/ethernet.h", 1984 "net/if.h", 1985 "net/if_arp.h", 1986 "net/route.h", 1987 "netdb.h", 1988 "netinet/in.h", 1989 "netinet/ip.h", 1990 "netinet/tcp.h", 1991 "netinet/udp.h", 1992 "netpacket/packet.h", 1993 "poll.h", 1994 "pthread.h", 1995 "pty.h", 1996 "pwd.h", 1997 "resolv.h", 1998 "sched.h", 1999 "sched.h", 2000 "semaphore.h", 2001 "shadow.h", 2002 "signal.h", 2003 "stddef.h", 2004 "stdint.h", 2005 "stdio.h", 2006 "stdlib.h", 2007 "string.h", 2008 "sys/epoll.h", 2009 "sys/eventfd.h", 2010 "sys/file.h", 2011 "sys/ioctl.h", 2012 "sys/ipc.h", 2013 "sys/mman.h", 2014 "sys/mount.h", 2015 "sys/msg.h", 2016 "sys/personality.h", 2017 "sys/prctl.h", 2018 "sys/ptrace.h", 2019 "sys/quota.h", 2020 "sys/reboot.h", 2021 "sys/resource.h", 2022 "sys/sem.h", 2023 "sys/sendfile.h", 2024 "sys/shm.h", 2025 "sys/signalfd.h", 2026 "sys/socket.h", 2027 "sys/stat.h", 2028 "sys/statvfs.h", 2029 "sys/swap.h", 2030 "sys/syscall.h", 2031 "sys/sysctl.h", 2032 "sys/sysinfo.h", 2033 "sys/time.h", 2034 "sys/timerfd.h", 2035 "sys/times.h", 2036 "sys/types.h", 2037 "sys/uio.h", 2038 "sys/un.h", 2039 "sys/user.h", 2040 "sys/utsname.h", 2041 "sys/vfs.h", 2042 "sys/wait.h", 2043 "sys/xattr.h", 2044 "syslog.h", 2045 "termios.h", 2046 "time.h", 2047 "ucontext.h", 2048 "unistd.h", 2049 "utime.h", 2050 "utmp.h", 2051 "utmpx.h", 2052 "wchar.h", 2053 } 2054 2055 cfg.type_name(move |ty, is_struct, is_union| { 2056 match ty { 2057 // Just pass all these through, no need for a "struct" prefix 2058 "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(), 2059 2060 t if is_union => format!("union {}", t), 2061 2062 t if t.ends_with("_t") => t.to_string(), 2063 2064 // put `struct` in front of all structs:. 2065 t if is_struct => format!("struct {}", t), 2066 2067 t => t.to_string(), 2068 } 2069 }); 2070 2071 cfg.field_name(move |struct_, field| { 2072 match field { 2073 // Our stat *_nsec fields normally don't actually exist but are part 2074 // of a timeval struct 2075 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2076 s.replace("e_nsec", ".tv_nsec") 2077 } 2078 // FIXME: appears that `epoll_event.data` is an union 2079 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 2080 s => s.to_string(), 2081 } 2082 }); 2083 2084 cfg.skip_type(move |ty| { 2085 match ty { 2086 // sighandler_t is crazy across platforms 2087 // FIXME: is this necessary? 2088 "sighandler_t" => true, 2089 2090 _ => false, 2091 } 2092 }); 2093 2094 cfg.skip_struct(move |ty| { 2095 match ty { 2096 // This is actually a union, not a struct 2097 // FIXME: is this necessary? 2098 "sigval" => true, 2099 2100 // FIXME: It was removed in 2101 // emscripten-core/emscripten@953e414 2102 "pthread_mutexattr_t" => true, 2103 2104 // FIXME: Investigate why the test fails. 2105 // Skip for now to unblock CI. 2106 "pthread_condattr_t" => true, 2107 2108 _ => false, 2109 } 2110 }); 2111 2112 cfg.skip_fn(move |name| { 2113 match name { 2114 // FIXME: https://github.com/rust-lang/libc/issues/1272 2115 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2116 2117 // FIXME: Investigate why CI is missing it. 2118 "clearenv" => true, 2119 2120 _ => false, 2121 } 2122 }); 2123 2124 cfg.skip_const(move |name| { 2125 match name { 2126 // FIXME: deprecated - SIGNUNUSED was removed in glibc 2.26 2127 // users should use SIGSYS instead 2128 "SIGUNUSED" => true, 2129 2130 // FIXME: emscripten uses different constants to constructs these 2131 n if n.contains("__SIZEOF_PTHREAD") => true, 2132 2133 // FIXME: `SYS_gettid` was removed in 2134 // emscripten-core/emscripten@6d6474e 2135 "SYS_gettid" => true, 2136 2137 _ => false, 2138 } 2139 }); 2140 2141 cfg.skip_field_type(move |struct_, field| { 2142 // This is a weird union, don't check the type. 2143 // FIXME: is this necessary? 2144 (struct_ == "ifaddrs" && field == "ifa_ifu") || 2145 // sighandler_t type is super weird 2146 // FIXME: is this necessary? 2147 (struct_ == "sigaction" && field == "sa_sigaction") || 2148 // sigval is actually a union, but we pretend it's a struct 2149 // FIXME: is this necessary? 2150 (struct_ == "sigevent" && field == "sigev_value") || 2151 // aio_buf is "volatile void*" and Rust doesn't understand volatile 2152 // FIXME: is this necessary? 2153 (struct_ == "aiocb" && field == "aio_buf") 2154 }); 2155 2156 cfg.skip_field(move |struct_, field| { 2157 // this is actually a union on linux, so we can't represent it well and 2158 // just insert some padding. 2159 // FIXME: is this necessary? 2160 (struct_ == "siginfo_t" && field == "_pad") || 2161 // musl names this __dummy1 but it's still there 2162 // FIXME: is this necessary? 2163 (struct_ == "glob_t" && field == "gl_flags") || 2164 // musl seems to define this as an *anonymous* bitfield 2165 // FIXME: is this necessary? 2166 (struct_ == "statvfs" && field == "__f_unused") || 2167 // sigev_notify_thread_id is actually part of a sigev_un union 2168 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 2169 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet. 2170 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 2171 field == "_pad2" || 2172 field == "ssi_syscall" || 2173 field == "ssi_call_addr" || 2174 field == "ssi_arch")) 2175 }); 2176 2177 // FIXME: test linux like 2178 cfg.generate("../src/lib.rs", "main.rs"); 2179 } 2180 2181 fn test_vxworks(target: &str) { 2182 assert!(target.contains("vxworks")); 2183 2184 let mut cfg = ctest::TestGenerator::new(); 2185 headers! { cfg: 2186 "vxWorks.h", 2187 "yvals.h", 2188 "nfs/nfsCommon.h", 2189 "rtpLibCommon.h", 2190 "randomNumGen.h", 2191 "taskLib.h", 2192 "sysLib.h", 2193 "ioLib.h", 2194 "inetLib.h", 2195 "socket.h", 2196 "errnoLib.h", 2197 "ctype.h", 2198 "dirent.h", 2199 "dlfcn.h", 2200 "elf.h", 2201 "fcntl.h", 2202 "grp.h", 2203 "sys/poll.h", 2204 "ifaddrs.h", 2205 "langinfo.h", 2206 "limits.h", 2207 "link.h", 2208 "locale.h", 2209 "sys/stat.h", 2210 "netdb.h", 2211 "pthread.h", 2212 "pwd.h", 2213 "sched.h", 2214 "semaphore.h", 2215 "signal.h", 2216 "stddef.h", 2217 "stdint.h", 2218 "stdio.h", 2219 "stdlib.h", 2220 "string.h", 2221 "sys/file.h", 2222 "sys/ioctl.h", 2223 "sys/socket.h", 2224 "sys/time.h", 2225 "sys/times.h", 2226 "sys/types.h", 2227 "sys/uio.h", 2228 "sys/un.h", 2229 "sys/utsname.h", 2230 "sys/wait.h", 2231 "netinet/tcp.h", 2232 "syslog.h", 2233 "termios.h", 2234 "time.h", 2235 "ucontext.h", 2236 "unistd.h", 2237 "utime.h", 2238 "wchar.h", 2239 "errno.h", 2240 "sys/mman.h", 2241 "pathLib.h", 2242 "mqueue.h", 2243 } 2244 // FIXME 2245 cfg.skip_const(move |name| match name { 2246 // sighandler_t weirdness 2247 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" 2248 // This is not defined in vxWorks 2249 | "RTLD_DEFAULT" => true, 2250 _ => false, 2251 }); 2252 // FIXME 2253 cfg.skip_type(move |ty| match ty { 2254 "stat64" | "sighandler_t" | "off64_t" => true, 2255 _ => false, 2256 }); 2257 2258 cfg.skip_field_type(move |struct_, field| match (struct_, field) { 2259 ("siginfo_t", "si_value") 2260 | ("stat", "st_size") 2261 | ("sigaction", "sa_u") => true, 2262 _ => false, 2263 }); 2264 2265 cfg.skip_roundtrip(move |s| match s { 2266 _ => false, 2267 }); 2268 2269 cfg.type_name(move |ty, is_struct, is_union| match ty { 2270 "DIR" | "FILE" | "Dl_info" | "RTP_DESC" => ty.to_string(), 2271 t if is_union => format!("union {}", t), 2272 t if t.ends_with("_t") => t.to_string(), 2273 t if is_struct => format!("struct {}", t), 2274 t => t.to_string(), 2275 }); 2276 2277 // FIXME 2278 cfg.skip_fn(move |name| match name { 2279 // sigval 2280 "sigqueue" | "_sigqueue" 2281 // sighandler_t 2282 | "signal" 2283 // not used in static linking by default 2284 | "dlerror" => true, 2285 _ => false, 2286 }); 2287 2288 cfg.generate("../src/lib.rs", "main.rs"); 2289 } 2290 2291 fn test_linux(target: &str) { 2292 assert!(target.contains("linux")); 2293 2294 // target_env 2295 let gnu = target.contains("gnu"); 2296 let musl = target.contains("musl"); 2297 let uclibc = target.contains("uclibc"); 2298 2299 match (gnu, musl, uclibc) { 2300 (true, false, false) => (), 2301 (false, true, false) => (), 2302 (false, false, true) => (), 2303 (_, _, _) => panic!( 2304 "linux target lib is gnu: {}, musl: {}, uclibc: {}", 2305 gnu, musl, uclibc 2306 ), 2307 } 2308 2309 let arm = target.contains("arm"); 2310 let i686 = target.contains("i686"); 2311 let mips = target.contains("mips"); 2312 let mips32 = mips && !target.contains("64"); 2313 let mips64 = mips && target.contains("64"); 2314 let ppc64 = target.contains("powerpc64"); 2315 let s390x = target.contains("s390x"); 2316 let sparc64 = target.contains("sparc64"); 2317 let x32 = target.contains("x32"); 2318 let x86_32 = target.contains("i686"); 2319 let x86_64 = target.contains("x86_64"); 2320 let aarch64_musl = target.contains("aarch64") && musl; 2321 let gnuabihf = target.contains("gnueabihf"); 2322 let x86_64_gnux32 = target.contains("gnux32") && x86_64; 2323 let riscv64 = target.contains("riscv64"); 2324 2325 let mut cfg = ctest_cfg(); 2326 cfg.define("_GNU_SOURCE", None); 2327 // This macro re-deifnes fscanf,scanf,sscanf to link to the symbols that are 2328 // deprecated since glibc >= 2.29. This allows Rust binaries to link against 2329 // glibc versions older than 2.29. 2330 cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None); 2331 2332 headers! { cfg: 2333 "ctype.h", 2334 "dirent.h", 2335 "dlfcn.h", 2336 "elf.h", 2337 "fcntl.h", 2338 "glob.h", 2339 "grp.h", 2340 "ifaddrs.h", 2341 "langinfo.h", 2342 "limits.h", 2343 "link.h", 2344 "locale.h", 2345 "malloc.h", 2346 "mntent.h", 2347 "mqueue.h", 2348 "net/ethernet.h", 2349 "net/if.h", 2350 "net/if_arp.h", 2351 "net/route.h", 2352 "netdb.h", 2353 "netinet/in.h", 2354 "netinet/ip.h", 2355 "netinet/tcp.h", 2356 "netinet/udp.h", 2357 "netpacket/packet.h", 2358 "poll.h", 2359 "pthread.h", 2360 "pty.h", 2361 "pwd.h", 2362 "regex.h", 2363 "resolv.h", 2364 "sched.h", 2365 "semaphore.h", 2366 "shadow.h", 2367 "signal.h", 2368 "spawn.h", 2369 "stddef.h", 2370 "stdint.h", 2371 "stdio.h", 2372 "stdlib.h", 2373 "string.h", 2374 "sys/epoll.h", 2375 "sys/eventfd.h", 2376 "sys/file.h", 2377 "sys/fsuid.h", 2378 "sys/inotify.h", 2379 "sys/ioctl.h", 2380 "sys/ipc.h", 2381 "sys/mman.h", 2382 "sys/mount.h", 2383 "sys/msg.h", 2384 "sys/personality.h", 2385 "sys/prctl.h", 2386 "sys/ptrace.h", 2387 "sys/quota.h", 2388 "sys/random.h", 2389 "sys/reboot.h", 2390 "sys/resource.h", 2391 "sys/sem.h", 2392 "sys/sendfile.h", 2393 "sys/shm.h", 2394 "sys/signalfd.h", 2395 "sys/socket.h", 2396 "sys/stat.h", 2397 "sys/statvfs.h", 2398 "sys/swap.h", 2399 "sys/syscall.h", 2400 "sys/time.h", 2401 "sys/timerfd.h", 2402 "sys/times.h", 2403 "sys/timex.h", 2404 "sys/types.h", 2405 "sys/uio.h", 2406 "sys/un.h", 2407 "sys/user.h", 2408 "sys/utsname.h", 2409 "sys/vfs.h", 2410 "sys/wait.h", 2411 "syslog.h", 2412 "termios.h", 2413 "time.h", 2414 "ucontext.h", 2415 "unistd.h", 2416 "utime.h", 2417 "utmp.h", 2418 "utmpx.h", 2419 "wchar.h", 2420 "errno.h", 2421 // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit 2422 // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162 2423 // Also unavailable on gnuabihf with glibc 2.30. 2424 // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6b33f373c7b9199e00ba5fbafd94ac9bfb4337b1 2425 [(x86_64 || x86_32 || arm) && !gnuabihf]: "sys/io.h", 2426 // `sys/reg.h` is only available on x86 and x86_64 2427 [x86_64 || x86_32]: "sys/reg.h", 2428 // sysctl system call is deprecated and not available on musl 2429 // It is also unsupported in x32, deprecated since glibc 2.30: 2430 [!(x32 || musl || gnu)]: "sys/sysctl.h", 2431 // <execinfo.h> is not supported by musl: 2432 // https://www.openwall.com/lists/musl/2015/04/09/3 2433 [!musl]: "execinfo.h", 2434 } 2435 2436 // Include linux headers at the end: 2437 headers! { 2438 cfg: 2439 "asm/mman.h", 2440 "linux/dccp.h", 2441 "linux/errqueue.h", 2442 "linux/falloc.h", 2443 "linux/fs.h", 2444 "linux/futex.h", 2445 "linux/genetlink.h", 2446 "linux/if.h", 2447 "linux/if_addr.h", 2448 "linux/if_alg.h", 2449 "linux/if_ether.h", 2450 "linux/if_tun.h", 2451 "linux/input.h", 2452 "linux/keyctl.h", 2453 "linux/magic.h", 2454 "linux/memfd.h", 2455 "linux/mman.h", 2456 "linux/module.h", 2457 "linux/net_tstamp.h", 2458 "linux/netfilter/nfnetlink.h", 2459 "linux/netfilter/nfnetlink_log.h", 2460 "linux/netfilter/nfnetlink_queue.h", 2461 "linux/netfilter/nf_tables.h", 2462 "linux/netfilter_ipv4.h", 2463 "linux/netfilter_ipv6.h", 2464 "linux/netfilter_ipv6/ip6_tables.h", 2465 "linux/netlink.h", 2466 "linux/quota.h", 2467 "linux/random.h", 2468 "linux/reboot.h", 2469 "linux/rtnetlink.h", 2470 "linux/seccomp.h", 2471 "linux/sockios.h", 2472 "linux/vm_sockets.h", 2473 "linux/wait.h", 2474 "sys/auxv.h", 2475 "sys/fanotify.h", 2476 } 2477 2478 // note: aio.h must be included before sys/mount.h 2479 headers! { 2480 cfg: 2481 "sys/xattr.h", 2482 "sys/sysinfo.h", 2483 "aio.h", 2484 } 2485 2486 cfg.type_name(move |ty, is_struct, is_union| { 2487 match ty { 2488 // Just pass all these through, no need for a "struct" prefix 2489 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" 2490 | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym" 2491 | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr" 2492 | "Elf64_Chdr" => ty.to_string(), 2493 2494 t if is_union => format!("union {}", t), 2495 2496 t if t.ends_with("_t") => t.to_string(), 2497 2498 // In MUSL `flock64` is a typedef to `flock`. 2499 "flock64" if musl => format!("struct {}", ty), 2500 2501 // put `struct` in front of all structs:. 2502 t if is_struct => format!("struct {}", t), 2503 2504 t => t.to_string(), 2505 } 2506 }); 2507 2508 cfg.field_name(move |struct_, field| { 2509 match field { 2510 // Our stat *_nsec fields normally don't actually exist but are part 2511 // of a timeval struct 2512 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2513 s.replace("e_nsec", ".tv_nsec") 2514 } 2515 // FIXME: epoll_event.data is actuall a union in C, but in Rust 2516 // it is only a u64 because we only expose one field 2517 // http://man7.org/linux/man-pages/man2/epoll_wait.2.html 2518 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 2519 // The following structs have a field called `type` in C, 2520 // but `type` is a Rust keyword, so these fields are translated 2521 // to `type_` in Rust. 2522 "type_" 2523 if struct_ == "input_event" 2524 || struct_ == "input_mask" 2525 || struct_ == "ff_effect" => 2526 { 2527 "type".to_string() 2528 } 2529 2530 s => s.to_string(), 2531 } 2532 }); 2533 2534 cfg.skip_type(move |ty| { 2535 match ty { 2536 // FIXME: `sighandler_t` type is incorrect, see: 2537 // https://github.com/rust-lang/libc/issues/1359 2538 "sighandler_t" => true, 2539 2540 // These cannot be tested when "resolv.h" is included and are tested 2541 // in the `linux_elf.rs` file. 2542 "Elf64_Phdr" | "Elf32_Phdr" => true, 2543 2544 // This type is private on Linux. It is implemented as a C `enum` 2545 // (`c_uint`) and this clashes with the type of the `rlimit` APIs 2546 // which expect a `c_int` even though both are ABI compatible. 2547 "__rlimit_resource_t" => true, 2548 2549 _ => false, 2550 } 2551 }); 2552 2553 cfg.skip_struct(move |ty| { 2554 match ty { 2555 // These cannot be tested when "resolv.h" is included and are tested 2556 // in the `linux_elf.rs` file. 2557 "Elf64_Phdr" | "Elf32_Phdr" => true, 2558 2559 // On Linux, the type of `ut_tv` field of `struct utmpx` 2560 // can be an anonymous struct, so an extra struct, 2561 // which is absent in glibc, has to be defined. 2562 "__timeval" => true, 2563 2564 // FIXME: This is actually a union, not a struct 2565 "sigval" => true, 2566 2567 // This type is tested in the `linux_termios.rs` file since there 2568 // are header conflicts when including them with all the other 2569 // structs. 2570 "termios2" => true, 2571 2572 // FIXME: remove once we set minimum supported glibc version. 2573 // ucontext_t added a new field as of glibc 2.28; our struct definition is 2574 // conservative and omits the field, but that means the size doesn't match for newer 2575 // glibcs (see https://github.com/rust-lang/libc/issues/1410) 2576 "ucontext_t" if gnu => true, 2577 2578 // FIXME: Somehow we cannot include headers correctly in glibc 2.30. 2579 // So let's ignore for now and re-visit later. 2580 // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085 2581 "statx" => true, 2582 "statx_timestamp" => true, 2583 2584 // On Linux, the type of `ut_exit` field of struct `utmpx` 2585 // can be an anonymous struct, so an extra struct, 2586 // which is absent in musl, has to be defined. 2587 "__exit_status" if musl => true, 2588 2589 _ => false, 2590 } 2591 }); 2592 2593 cfg.skip_const(move |name| { 2594 match name { 2595 // These constants are not available if gnu headers have been included 2596 // and can therefore not be tested here 2597 // 2598 // The IPV6 constants are tested in the `linux_ipv6.rs` tests: 2599 | "IPV6_FLOWINFO" 2600 | "IPV6_FLOWLABEL_MGR" 2601 | "IPV6_FLOWINFO_SEND" 2602 | "IPV6_FLOWINFO_FLOWLABEL" 2603 | "IPV6_FLOWINFO_PRIORITY" 2604 // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: 2605 | "F_CANCELLK" 2606 | "F_ADD_SEALS" 2607 | "F_GET_SEALS" 2608 | "F_SEAL_SEAL" 2609 | "F_SEAL_SHRINK" 2610 | "F_SEAL_GROW" 2611 | "F_SEAL_WRITE" => true, 2612 2613 // The musl-sanitized kernel headers used in CI 2614 // target the Linux kernel 4.4 and do not contain the 2615 // following constants: 2616 // 2617 // Requires Linux kernel 4.9 2618 | "FALLOC_FL_UNSHARE_RANGE" 2619 // 2620 // Require Linux kernel 5.x: 2621 | "MSG_COPY" 2622 if musl => true, 2623 // Require Linux kernel 5.1: 2624 "F_SEAL_FUTURE_WRITE" => true, 2625 2626 // The musl version 1.1.24 used in CI does not 2627 // contain these glibc constants yet: 2628 | "RLIMIT_RTTIME" // should be in `resource.h` 2629 | "TCP_COOKIE_TRANSACTIONS" // should be in the `netinet/tcp.h` header 2630 if musl => true, 2631 2632 // FIXME: deprecated: not available in any header 2633 // See: https://github.com/rust-lang/libc/issues/1356 2634 "ENOATTR" => true, 2635 2636 // FIXME: SIGUNUSED was removed in glibc 2.26 2637 // Users should use SIGSYS instead. 2638 "SIGUNUSED" => true, 2639 2640 // FIXME: conflicts with glibc headers and is tested in 2641 // `linux_termios.rs` below: 2642 "BOTHER" => true, 2643 2644 // FIXME: on musl the pthread types are defined a little differently 2645 // - these constants are used by the glibc implementation. 2646 n if musl && n.contains("__SIZEOF_PTHREAD") => true, 2647 2648 // FIXME: It was extended to 4096 since glibc 2.31 (Linux 5.4). 2649 // We should do so after a while. 2650 "SOMAXCONN" if gnu => true, 2651 2652 // deprecated: not available from Linux kernel 5.6: 2653 "VMADDR_CID_RESERVED" => true, 2654 2655 // Require Linux kernel 5.6: 2656 "VMADDR_CID_LOCAL" => true, 2657 2658 // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP: 2659 | "IPPROTO_MAX" 2660 | "IPPROTO_MPTCP" => true, 2661 2662 // Defined in kernel headers but musl removes it; need musl 1.2 for definition in musl 2663 // headers. 2664 "P_PIDFD" => true, 2665 2666 // FIXME: Not currently available in headers 2667 "SYS_pidfd_open" if mips => true, 2668 2669 // FIXME: Not currently available in headers on MIPS 2670 // Not yet implemented on sparc64 2671 "SYS_clone3" if mips | sparc64 => true, 2672 2673 _ => false, 2674 } 2675 }); 2676 2677 cfg.skip_fn(move |name| { 2678 // skip those that are manually verified 2679 match name { 2680 // FIXME: https://github.com/rust-lang/libc/issues/1272 2681 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2682 2683 // There are two versions of the sterror_r function, see 2684 // 2685 // https://linux.die.net/man/3/strerror_r 2686 // 2687 // An XSI-compliant version provided if: 2688 // 2689 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) 2690 // && ! _GNU_SOURCE 2691 // 2692 // and a GNU specific version provided if _GNU_SOURCE is defined. 2693 // 2694 // libc provides bindings for the XSI-compliant version, which is 2695 // preferred for portable applications. 2696 // 2697 // We skip the test here since here _GNU_SOURCE is defined, and 2698 // test the XSI version below. 2699 "strerror_r" => true, 2700 2701 // FIXME: Our API is unsound. The Rust API allows aliasing 2702 // pointers, but the C API requires pointers not to alias. 2703 // We should probably be at least using `&`/`&mut` here, see: 2704 // https://github.com/gnzlbg/ctest/issues/68 2705 "lio_listio" if musl => true, 2706 2707 // FIXME: the glibc version used by the Sparc64 build jobs 2708 // which use Debian 10.0 is too old. 2709 "statx" if sparc64 => true, 2710 2711 // FIXME: Deprecated since glibc 2.30. Remove fn once upstream does. 2712 "sysctl" if gnu => true, 2713 2714 // FIXME: It now takes c_void instead of timezone since glibc 2.31. 2715 "gettimeofday" if gnu => true, 2716 2717 _ => false, 2718 } 2719 }); 2720 2721 cfg.skip_field_type(move |struct_, field| { 2722 // This is a weird union, don't check the type. 2723 (struct_ == "ifaddrs" && field == "ifa_ifu") || 2724 // sighandler_t type is super weird 2725 (struct_ == "sigaction" && field == "sa_sigaction") || 2726 // __timeval type is a patch which doesn't exist in glibc 2727 (struct_ == "utmpx" && field == "ut_tv") || 2728 // sigval is actually a union, but we pretend it's a struct 2729 (struct_ == "sigevent" && field == "sigev_value") || 2730 // this one is an anonymous union 2731 (struct_ == "ff_effect" && field == "u") || 2732 // `__exit_status` type is a patch which is absent in musl 2733 (struct_ == "utmpx" && field == "ut_exit" && musl) 2734 }); 2735 2736 cfg.volatile_item(|i| { 2737 use ctest::VolatileItemKind::*; 2738 match i { 2739 // aio_buf is a volatile void** but since we cannot express that in 2740 // Rust types, we have to explicitly tell the checker about it here: 2741 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => { 2742 true 2743 } 2744 _ => false, 2745 } 2746 }); 2747 2748 cfg.skip_field(move |struct_, field| { 2749 // this is actually a union on linux, so we can't represent it well and 2750 // just insert some padding. 2751 (struct_ == "siginfo_t" && field == "_pad") || 2752 // musl names this __dummy1 but it's still there 2753 (musl && struct_ == "glob_t" && field == "gl_flags") || 2754 // musl seems to define this as an *anonymous* bitfield 2755 (musl && struct_ == "statvfs" && field == "__f_unused") || 2756 // sigev_notify_thread_id is actually part of a sigev_un union 2757 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 2758 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release 2759 // has them yet. 2760 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 2761 field == "_pad2" || 2762 field == "ssi_syscall" || 2763 field == "ssi_call_addr" || 2764 field == "ssi_arch")) || 2765 // FIXME: After musl 1.1.24, it have only one field `sched_priority`, 2766 // while other fields become reserved. 2767 (struct_ == "sched_param" && [ 2768 "sched_ss_low_priority", 2769 "sched_ss_repl_period", 2770 "sched_ss_init_budget", 2771 "sched_ss_max_repl", 2772 ].contains(&field) && musl) || 2773 // FIXME: After musl 1.1.24, the type becomes `int` instead of `unsigned short`. 2774 (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) || 2775 // glibc uses unnamed fields here and Rust doesn't support that yet 2776 (struct_ == "timex" && field.starts_with("__unused")) || 2777 // FIXME: It now takes mode_t since glibc 2.31 on some targets. 2778 (struct_ == "ipc_perm" && field == "mode" 2779 && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32) 2780 ) 2781 }); 2782 2783 cfg.skip_roundtrip(move |s| match s { 2784 // FIXME: 2785 "utsname" if mips32 || mips64 => true, 2786 // FIXME: 2787 "mcontext_t" if s390x => true, 2788 // FIXME: This is actually a union. 2789 "fpreg_t" if s390x => true, 2790 2791 "sockaddr_un" | "sembuf" | "ff_constant_effect" 2792 if mips32 && (gnu || musl) => 2793 { 2794 true 2795 } 2796 "ipv6_mreq" 2797 | "ip_mreq_source" 2798 | "sockaddr_in6" 2799 | "sockaddr_ll" 2800 | "in_pktinfo" 2801 | "arpreq" 2802 | "arpreq_old" 2803 | "sockaddr_un" 2804 | "ff_constant_effect" 2805 | "ff_ramp_effect" 2806 | "ff_condition_effect" 2807 | "Elf32_Ehdr" 2808 | "Elf32_Chdr" 2809 | "ucred" 2810 | "in6_pktinfo" 2811 | "sockaddr_nl" 2812 | "termios" 2813 | "nlmsgerr" 2814 if (mips64 || sparc64) && gnu => 2815 { 2816 true 2817 } 2818 2819 // FIXME: the call ABI of max_align_t is incorrect on these platforms: 2820 "max_align_t" if i686 || mips64 || ppc64 => true, 2821 2822 _ => false, 2823 }); 2824 2825 cfg.generate("../src/lib.rs", "main.rs"); 2826 2827 test_linux_like_apis(target); 2828 } 2829 2830 // This function tests APIs that are incompatible to test when other APIs 2831 // are included (e.g. because including both sets of headers clashes) 2832 fn test_linux_like_apis(target: &str) { 2833 let musl = target.contains("musl"); 2834 let linux = target.contains("linux"); 2835 let emscripten = target.contains("emscripten"); 2836 let android = target.contains("android"); 2837 assert!(linux || android || emscripten); 2838 2839 if linux || android || emscripten { 2840 // test strerror_r from the `string.h` header 2841 let mut cfg = ctest_cfg(); 2842 cfg.skip_type(|_| true).skip_static(|_| true); 2843 2844 headers! { cfg: "string.h" } 2845 cfg.skip_fn(|f| match f { 2846 "strerror_r" => false, 2847 _ => true, 2848 }) 2849 .skip_const(|_| true) 2850 .skip_struct(|_| true); 2851 cfg.generate("../src/lib.rs", "linux_strerror_r.rs"); 2852 } 2853 2854 if linux || android || emscripten { 2855 // test fcntl - see: 2856 // http://man7.org/linux/man-pages/man2/fcntl.2.html 2857 let mut cfg = ctest_cfg(); 2858 2859 if musl { 2860 cfg.header("fcntl.h"); 2861 } else { 2862 cfg.header("linux/fcntl.h"); 2863 } 2864 2865 cfg.skip_type(|_| true) 2866 .skip_static(|_| true) 2867 .skip_struct(|_| true) 2868 .skip_fn(|_| true) 2869 .skip_const(move |name| match name { 2870 // test fcntl constants: 2871 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" 2872 | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" 2873 | "F_SEAL_WRITE" => false, 2874 _ => true, 2875 }) 2876 .type_name(move |ty, is_struct, is_union| match ty { 2877 t if is_struct => format!("struct {}", t), 2878 t if is_union => format!("union {}", t), 2879 t => t.to_string(), 2880 }); 2881 2882 cfg.generate("../src/lib.rs", "linux_fcntl.rs"); 2883 } 2884 2885 if linux || android { 2886 // test termios 2887 let mut cfg = ctest_cfg(); 2888 cfg.header("asm/termbits.h"); 2889 cfg.skip_type(|_| true) 2890 .skip_static(|_| true) 2891 .skip_fn(|_| true) 2892 .skip_const(|c| c != "BOTHER") 2893 .skip_struct(|s| s != "termios2") 2894 .type_name(move |ty, is_struct, is_union| match ty { 2895 t if is_struct => format!("struct {}", t), 2896 t if is_union => format!("union {}", t), 2897 t => t.to_string(), 2898 }); 2899 cfg.generate("../src/lib.rs", "linux_termios.rs"); 2900 } 2901 2902 if linux || android { 2903 // test IPV6_ constants: 2904 let mut cfg = ctest_cfg(); 2905 headers! { 2906 cfg: 2907 "linux/in6.h" 2908 } 2909 cfg.skip_type(|_| true) 2910 .skip_static(|_| true) 2911 .skip_fn(|_| true) 2912 .skip_const(|_| true) 2913 .skip_struct(|_| true) 2914 .skip_const(move |name| match name { 2915 "IPV6_FLOWINFO" 2916 | "IPV6_FLOWLABEL_MGR" 2917 | "IPV6_FLOWINFO_SEND" 2918 | "IPV6_FLOWINFO_FLOWLABEL" 2919 | "IPV6_FLOWINFO_PRIORITY" => false, 2920 _ => true, 2921 }) 2922 .type_name(move |ty, is_struct, is_union| match ty { 2923 t if is_struct => format!("struct {}", t), 2924 t if is_union => format!("union {}", t), 2925 t => t.to_string(), 2926 }); 2927 cfg.generate("../src/lib.rs", "linux_ipv6.rs"); 2928 } 2929 2930 if linux || android { 2931 // Test Elf64_Phdr and Elf32_Phdr 2932 // These types have a field called `p_type`, but including 2933 // "resolve.h" defines a `p_type` macro that expands to `__p_type` 2934 // making the tests for these fails when both are included. 2935 let mut cfg = ctest_cfg(); 2936 cfg.header("elf.h"); 2937 cfg.skip_fn(|_| true) 2938 .skip_static(|_| true) 2939 .skip_fn(|_| true) 2940 .skip_const(|_| true) 2941 .type_name(move |ty, _is_struct, _is_union| ty.to_string()) 2942 .skip_struct(move |ty| match ty { 2943 "Elf64_Phdr" | "Elf32_Phdr" => false, 2944 _ => true, 2945 }) 2946 .skip_type(move |ty| match ty { 2947 "Elf64_Phdr" | "Elf32_Phdr" => false, 2948 _ => true, 2949 }); 2950 cfg.generate("../src/lib.rs", "linux_elf.rs"); 2951 } 2952 } 2953 2954 fn which_freebsd() -> Option<i32> { 2955 let output = std::process::Command::new("freebsd-version") 2956 .output() 2957 .ok()?; 2958 if !output.status.success() { 2959 return None; 2960 } 2961 2962 let stdout = String::from_utf8(output.stdout).ok()?; 2963 2964 match &stdout { 2965 s if s.starts_with("10") => Some(10), 2966 s if s.starts_with("11") => Some(11), 2967 s if s.starts_with("12") => Some(12), 2968 s if s.starts_with("13") => Some(13), 2969 _ => None, 2970 } 2971 } 2972