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