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