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