1 #![deny(warnings)] 2 3 extern crate cc; 4 extern crate ctest2 as ctest; 5 6 use std::fs::File; 7 use std::io::{BufRead, BufReader, BufWriter, Write}; 8 use std::path::{Path, PathBuf}; 9 use std::{env, io}; 10 11 fn do_cc() { 12 let target = env::var("TARGET").unwrap(); 13 if cfg!(unix) { 14 let exclude = ["redox", "wasi"]; 15 if !exclude.iter().any(|x| target.contains(x)) { 16 let mut cmsg = cc::Build::new(); 17 18 cmsg.file("src/cmsg.c"); 19 20 if target.contains("solaris") || target.contains("illumos") { 21 cmsg.define("_XOPEN_SOURCE", "700"); 22 } 23 cmsg.compile("cmsg"); 24 } 25 } 26 if target.contains("android") || target.contains("linux") { 27 cc::Build::new().file("src/errqueue.c").compile("errqueue"); 28 } 29 if target.contains("linux") 30 || target.contains("l4re") 31 || target.contains("android") 32 || target.contains("emscripten") 33 { 34 cc::Build::new().file("src/sigrt.c").compile("sigrt"); 35 } 36 } 37 38 fn do_ctest() { 39 match &env::var("TARGET").unwrap() { 40 t if t.contains("android") => return test_android(t), 41 t if t.contains("apple") => return test_apple(t), 42 t if t.contains("dragonfly") => return test_dragonflybsd(t), 43 t if t.contains("emscripten") => return test_emscripten(t), 44 t if t.contains("freebsd") => return test_freebsd(t), 45 t if t.contains("haiku") => return test_haiku(t), 46 t if t.contains("linux") => return test_linux(t), 47 t if t.contains("netbsd") => return test_netbsd(t), 48 t if t.contains("openbsd") => return test_openbsd(t), 49 t if t.contains("redox") => return test_redox(t), 50 t if t.contains("solaris") => return test_solarish(t), 51 t if t.contains("illumos") => return test_solarish(t), 52 t if t.contains("wasi") => return test_wasi(t), 53 t if t.contains("windows") => return test_windows(t), 54 t if t.contains("vxworks") => return test_vxworks(t), 55 t => panic!("unknown target {}", t), 56 } 57 } 58 59 fn ctest_cfg() -> ctest::TestGenerator { 60 let mut cfg = ctest::TestGenerator::new(); 61 let libc_cfgs = [ 62 "libc_priv_mod_use", 63 "libc_union", 64 "libc_const_size_of", 65 "libc_align", 66 "libc_core_cvoid", 67 "libc_packedN", 68 "libc_thread_local", 69 ]; 70 for f in &libc_cfgs { 71 cfg.cfg(f, None); 72 } 73 cfg 74 } 75 76 fn do_semver() { 77 let mut out = PathBuf::from(env::var("OUT_DIR").unwrap()); 78 out.push("semver.rs"); 79 let mut output = BufWriter::new(File::create(&out).unwrap()); 80 81 let family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap(); 82 let vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); 83 let os = env::var("CARGO_CFG_TARGET_OS").unwrap(); 84 let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); 85 let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); 86 87 // `libc-test/semver` dir. 88 let mut semver_root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); 89 semver_root.push("semver"); 90 91 // NOTE: Windows has the same `family` as `os`, no point in including it 92 // twice. 93 // NOTE: Android doesn't include the unix file (or the Linux file) because 94 // there are some many definitions missing it's actually easier just to 95 // maintain a file for Android. 96 if family != os && os != "android" { 97 process_semver_file(&mut output, &mut semver_root, &family); 98 } 99 process_semver_file(&mut output, &mut semver_root, &vendor); 100 process_semver_file(&mut output, &mut semver_root, &os); 101 let os_arch = format!("{}-{}", os, arch); 102 process_semver_file(&mut output, &mut semver_root, &os_arch); 103 if target_env != "" { 104 let os_env = format!("{}-{}", os, target_env); 105 process_semver_file(&mut output, &mut semver_root, &os_env); 106 107 let os_env_arch = format!("{}-{}-{}", os, target_env, arch); 108 process_semver_file(&mut output, &mut semver_root, &os_env_arch); 109 } 110 } 111 112 fn process_semver_file<W: Write, P: AsRef<Path>>(output: &mut W, path: &mut PathBuf, file: P) { 113 // NOTE: `path` is reused between calls, so always remove the file again. 114 path.push(file); 115 path.set_extension("txt"); 116 117 println!("cargo:rerun-if-changed={}", path.display()); 118 let input_file = match File::open(&*path) { 119 Ok(file) => file, 120 Err(ref err) if err.kind() == io::ErrorKind::NotFound => { 121 path.pop(); 122 return; 123 } 124 Err(err) => panic!("unexpected error opening file: {}", err), 125 }; 126 let input = BufReader::new(input_file); 127 128 write!(output, "// Source: {}.\n", path.display()).unwrap(); 129 output.write(b"use libc::{\n").unwrap(); 130 for line in input.lines() { 131 let line = line.unwrap().into_bytes(); 132 match line.first() { 133 // Ignore comments and empty lines. 134 Some(b'#') | None => continue, 135 _ => { 136 output.write(b" ").unwrap(); 137 output.write(&line).unwrap(); 138 output.write(b",\n").unwrap(); 139 } 140 } 141 } 142 output.write(b"};\n\n").unwrap(); 143 path.pop(); 144 } 145 146 fn main() { 147 do_cc(); 148 do_ctest(); 149 do_semver(); 150 } 151 152 macro_rules! headers { 153 ($cfg:ident: [$m:expr]: $header:literal) => { 154 if $m { 155 $cfg.header($header); 156 } 157 }; 158 ($cfg:ident: $header:literal) => { 159 $cfg.header($header); 160 }; 161 ($($cfg:ident: $([$c:expr]:)* $header:literal,)*) => { 162 $(headers!($cfg: $([$c]:)* $header);)* 163 }; 164 ($cfg:ident: $( $([$c:expr]:)* $header:literal,)*) => { 165 headers!($($cfg: $([$c]:)* $header,)*); 166 }; 167 ($cfg:ident: $( $([$c:expr]:)* $header:literal),*) => { 168 headers!($($cfg: $([$c]:)* $header,)*); 169 }; 170 } 171 172 fn test_apple(target: &str) { 173 assert!(target.contains("apple")); 174 let x86_64 = target.contains("x86_64"); 175 let i686 = target.contains("i686"); 176 177 let mut cfg = ctest_cfg(); 178 cfg.flag("-Wno-deprecated-declarations"); 179 cfg.define("__APPLE_USE_RFC_3542", None); 180 181 headers! { cfg: 182 "aio.h", 183 "CommonCrypto/CommonCrypto.h", 184 "CommonCrypto/CommonRandom.h", 185 "copyfile.h", 186 "crt_externs.h", 187 "ctype.h", 188 "dirent.h", 189 "dlfcn.h", 190 "errno.h", 191 "execinfo.h", 192 "fcntl.h", 193 "glob.h", 194 "grp.h", 195 "iconv.h", 196 "ifaddrs.h", 197 "langinfo.h", 198 "libproc.h", 199 "limits.h", 200 "locale.h", 201 "mach-o/dyld.h", 202 "mach/mach_init.h", 203 "mach/mach.h", 204 "mach/mach_time.h", 205 "mach/mach_types.h", 206 "mach/mach_vm.h", 207 "mach/thread_act.h", 208 "mach/thread_policy.h", 209 "malloc/malloc.h", 210 "net/bpf.h", 211 "net/if.h", 212 "net/if_arp.h", 213 "net/if_dl.h", 214 "net/if_utun.h", 215 "net/route.h", 216 "netdb.h", 217 "netinet/if_ether.h", 218 "netinet/in.h", 219 "netinet/ip.h", 220 "netinet/tcp.h", 221 "netinet/udp.h", 222 "poll.h", 223 "pthread.h", 224 "pthread_spis.h", 225 "pthread/introspection.h", 226 "pwd.h", 227 "regex.h", 228 "resolv.h", 229 "sched.h", 230 "semaphore.h", 231 "signal.h", 232 "spawn.h", 233 "stddef.h", 234 "stdint.h", 235 "stdio.h", 236 "stdlib.h", 237 "string.h", 238 "sysdir.h", 239 "sys/attr.h", 240 "sys/clonefile.h", 241 "sys/event.h", 242 "sys/file.h", 243 "sys/ioctl.h", 244 "sys/ipc.h", 245 "sys/kern_control.h", 246 "sys/mman.h", 247 "sys/mount.h", 248 "sys/proc_info.h", 249 "sys/ptrace.h", 250 "sys/quota.h", 251 "sys/resource.h", 252 "sys/sem.h", 253 "sys/shm.h", 254 "sys/socket.h", 255 "sys/stat.h", 256 "sys/statvfs.h", 257 "sys/sys_domain.h", 258 "sys/sysctl.h", 259 "sys/time.h", 260 "sys/times.h", 261 "sys/timex.h", 262 "sys/types.h", 263 "sys/uio.h", 264 "sys/un.h", 265 "sys/utsname.h", 266 "sys/wait.h", 267 "sys/xattr.h", 268 "syslog.h", 269 "termios.h", 270 "time.h", 271 "unistd.h", 272 "util.h", 273 "utime.h", 274 "utmpx.h", 275 "wchar.h", 276 "xlocale.h", 277 [x86_64]: "crt_externs.h", 278 } 279 280 cfg.skip_struct(move |ty| { 281 match ty { 282 // FIXME: actually a union 283 "sigval" => true, 284 285 _ => false, 286 } 287 }); 288 289 cfg.skip_type(move |ty| match ty { 290 _ => false, 291 }); 292 293 cfg.skip_const(move |name| { 294 // They're declared via `deprecated_mach` and we don't support it anymore. 295 if name.starts_with("VM_FLAGS_") { 296 return true; 297 } 298 match name { 299 // These OSX constants are removed in Sierra. 300 // https://developer.apple.com/library/content/releasenotes/General/APIDiffsMacOS10_12/Swift/Darwin.html 301 "KERN_KDENABLE_BG_TRACE" | "KERN_KDDISABLE_BG_TRACE" => true, 302 // FIXME: the value has been changed since Catalina (0xffff0000 -> 0x3fff0000). 303 "SF_SETTABLE" => true, 304 305 // FIXME: XCode 13.1 doesn't have it. 306 "TIOCREMOTE" => true, 307 _ => false, 308 } 309 }); 310 311 cfg.skip_fn(move |name| { 312 // skip those that are manually verified 313 match name { 314 // FIXME: https://github.com/rust-lang/libc/issues/1272 315 "execv" | "execve" | "execvp" => true, 316 317 // close calls the close_nocancel system call 318 "close" => true, 319 320 // macOs 12 minimum 321 "backtrace_async" => true, 322 323 _ => false, 324 } 325 }); 326 327 cfg.skip_field(move |struct_, field| { 328 match (struct_, field) { 329 // FIXME: the array size has been changed since macOS 10.15 ([8] -> [7]). 330 ("statfs", "f_reserved") => true, 331 ("__darwin_arm_neon_state64", "__v") => true, 332 // MAXPATHLEN is too big for auto-derive traits on arrays. 333 ("vnode_info_path", "vip_path") => true, 334 _ => false, 335 } 336 }); 337 338 cfg.skip_field_type(move |struct_, field| { 339 match (struct_, field) { 340 // FIXME: actually a union 341 ("sigevent", "sigev_value") => true, 342 _ => false, 343 } 344 }); 345 346 cfg.volatile_item(|i| { 347 use ctest::VolatileItemKind::*; 348 match i { 349 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 350 _ => false, 351 } 352 }); 353 354 cfg.type_name(move |ty, is_struct, is_union| { 355 match ty { 356 // Just pass all these through, no need for a "struct" prefix 357 "FILE" | "DIR" | "Dl_info" => ty.to_string(), 358 359 // OSX calls this something else 360 "sighandler_t" => "sig_t".to_string(), 361 362 t if is_union => format!("union {}", t), 363 t if t.ends_with("_t") => t.to_string(), 364 t if is_struct => format!("struct {}", t), 365 t => t.to_string(), 366 } 367 }); 368 369 cfg.field_name(move |struct_, field| { 370 match field { 371 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 372 s.replace("e_nsec", "espec.tv_nsec") 373 } 374 // FIXME: sigaction actually contains a union with two variants: 375 // a sa_sigaction with type: (*)(int, struct __siginfo *, void *) 376 // a sa_handler with type sig_t 377 "sa_sigaction" if struct_ == "sigaction" => "sa_handler".to_string(), 378 s => s.to_string(), 379 } 380 }); 381 382 cfg.skip_roundtrip(move |s| match s { 383 // FIXME: this type has the wrong ABI 384 "max_align_t" if i686 => true, 385 // Can't return an array from a C function. 386 "uuid_t" => true, 387 _ => false, 388 }); 389 cfg.generate("../src/lib.rs", "main.rs"); 390 } 391 392 fn test_openbsd(target: &str) { 393 assert!(target.contains("openbsd")); 394 395 let mut cfg = ctest_cfg(); 396 cfg.flag("-Wno-deprecated-declarations"); 397 398 let x86_64 = target.contains("x86_64"); 399 400 headers! { cfg: 401 "elf.h", 402 "errno.h", 403 "execinfo.h", 404 "fcntl.h", 405 "limits.h", 406 "link.h", 407 "locale.h", 408 "stddef.h", 409 "stdint.h", 410 "stdio.h", 411 "stdlib.h", 412 "sys/stat.h", 413 "sys/types.h", 414 "time.h", 415 "wchar.h", 416 "ctype.h", 417 "dirent.h", 418 "sys/socket.h", 419 [x86_64]:"machine/fpu.h", 420 "net/if.h", 421 "net/route.h", 422 "net/if_arp.h", 423 "netdb.h", 424 "netinet/in.h", 425 "netinet/ip.h", 426 "netinet/tcp.h", 427 "netinet/udp.h", 428 "net/bpf.h", 429 "regex.h", 430 "resolv.h", 431 "pthread.h", 432 "dlfcn.h", 433 "search.h", 434 "signal.h", 435 "string.h", 436 "sys/file.h", 437 "sys/ioctl.h", 438 "sys/ipc.h", 439 "sys/mman.h", 440 "sys/param.h", 441 "sys/resource.h", 442 "sys/shm.h", 443 "sys/socket.h", 444 "sys/time.h", 445 "sys/uio.h", 446 "sys/ktrace.h", 447 "sys/un.h", 448 "sys/wait.h", 449 "unistd.h", 450 "utime.h", 451 "pwd.h", 452 "grp.h", 453 "sys/utsname.h", 454 "sys/ptrace.h", 455 "sys/mount.h", 456 "sys/uio.h", 457 "sched.h", 458 "termios.h", 459 "poll.h", 460 "syslog.h", 461 "semaphore.h", 462 "sys/statvfs.h", 463 "sys/times.h", 464 "glob.h", 465 "ifaddrs.h", 466 "langinfo.h", 467 "sys/sysctl.h", 468 "utmp.h", 469 "sys/event.h", 470 "net/if_dl.h", 471 "util.h", 472 "ufs/ufs/quota.h", 473 "pthread_np.h", 474 "sys/syscall.h", 475 "sys/shm.h", 476 "sys/param.h", 477 } 478 479 cfg.skip_struct(move |ty| { 480 match ty { 481 // FIXME: actually a union 482 "sigval" => true, 483 484 _ => false, 485 } 486 }); 487 488 cfg.skip_const(move |name| { 489 match name { 490 // Removed in OpenBSD 6.0 491 "KERN_USERMOUNT" | "KERN_ARND" => true, 492 // Good chance it's going to be wrong depending on the host release 493 "KERN_MAXID" | "NET_RT_MAXID" => true, 494 "EV_SYSFLAGS" => true, 495 _ => false, 496 } 497 }); 498 499 cfg.skip_fn(move |name| { 500 match name { 501 // FIXME: https://github.com/rust-lang/libc/issues/1272 502 "execv" | "execve" | "execvp" | "execvpe" => true, 503 504 // Removed in OpenBSD 6.5 505 // https://marc.info/?l=openbsd-cvs&m=154723400730318 506 "mincore" => true, 507 508 _ => false, 509 } 510 }); 511 512 cfg.type_name(move |ty, is_struct, is_union| { 513 match ty { 514 // Just pass all these through, no need for a "struct" prefix 515 "FILE" | "DIR" | "Dl_info" | "Elf32_Phdr" | "Elf64_Phdr" => ty.to_string(), 516 517 // OSX calls this something else 518 "sighandler_t" => "sig_t".to_string(), 519 520 t if is_union => format!("union {}", t), 521 t if t.ends_with("_t") => t.to_string(), 522 t if is_struct => format!("struct {}", t), 523 t => t.to_string(), 524 } 525 }); 526 527 cfg.field_name(move |struct_, field| match field { 528 "st_birthtime" if struct_.starts_with("stat") => "__st_birthtime".to_string(), 529 "st_birthtime_nsec" if struct_.starts_with("stat") => "__st_birthtimensec".to_string(), 530 s if s.ends_with("_nsec") && struct_.starts_with("stat") => s.replace("e_nsec", ".tv_nsec"), 531 "sa_sigaction" if struct_ == "sigaction" => "sa_handler".to_string(), 532 s => s.to_string(), 533 }); 534 535 cfg.skip_field_type(move |struct_, field| { 536 // type siginfo_t.si_addr changed from OpenBSD 6.0 to 6.1 537 struct_ == "siginfo_t" && field == "si_addr" 538 }); 539 540 cfg.skip_field(|struct_, field| { 541 match (struct_, field) { 542 // conflicting with `p_type` macro from <resolve.h>. 543 ("Elf32_Phdr", "p_type") => true, 544 ("Elf64_Phdr", "p_type") => true, 545 _ => false, 546 } 547 }); 548 549 cfg.generate("../src/lib.rs", "main.rs"); 550 } 551 552 fn test_windows(target: &str) { 553 assert!(target.contains("windows")); 554 let gnu = target.contains("gnu"); 555 556 let mut cfg = ctest_cfg(); 557 if target.contains("msvc") { 558 cfg.flag("/wd4324"); 559 } 560 cfg.define("_WIN32_WINNT", Some("0x8000")); 561 562 headers! { cfg: 563 "direct.h", 564 "errno.h", 565 "fcntl.h", 566 "io.h", 567 "limits.h", 568 "locale.h", 569 "process.h", 570 "signal.h", 571 "stddef.h", 572 "stdint.h", 573 "stdio.h", 574 "stdlib.h", 575 "sys/stat.h", 576 "sys/types.h", 577 "sys/utime.h", 578 "time.h", 579 "wchar.h", 580 [gnu]: "ws2tcpip.h", 581 [!gnu]: "Winsock2.h", 582 } 583 584 cfg.type_name(move |ty, is_struct, is_union| { 585 match ty { 586 // Just pass all these through, no need for a "struct" prefix 587 "FILE" | "DIR" | "Dl_info" => ty.to_string(), 588 589 // FIXME: these don't exist: 590 "time64_t" => "__time64_t".to_string(), 591 "ssize_t" => "SSIZE_T".to_string(), 592 593 "sighandler_t" if !gnu => "_crt_signal_t".to_string(), 594 "sighandler_t" if gnu => "__p_sig_fn_t".to_string(), 595 596 t if is_union => format!("union {}", t), 597 t if t.ends_with("_t") => t.to_string(), 598 599 // Windows uppercase structs don't have `struct` in front: 600 t if is_struct => { 601 if ty.clone().chars().next().unwrap().is_uppercase() { 602 t.to_string() 603 } else if t == "stat" { 604 "struct __stat64".to_string() 605 } else if t == "utimbuf" { 606 "struct __utimbuf64".to_string() 607 } else { 608 // put `struct` in front of all structs: 609 format!("struct {}", t) 610 } 611 } 612 t => t.to_string(), 613 } 614 }); 615 616 cfg.fn_cname(move |name, cname| cname.unwrap_or(name).to_string()); 617 618 cfg.skip_type(move |name| match name { 619 "SSIZE_T" if !gnu => true, 620 "ssize_t" if !gnu => true, 621 _ => false, 622 }); 623 624 cfg.skip_struct(move |ty| { 625 if ty.starts_with("__c_anonymous_") { 626 return true; 627 } 628 return false; 629 }); 630 631 cfg.skip_const(move |name| { 632 match name { 633 // FIXME: API error: 634 // SIG_ERR type is "void (*)(int)", not "int" 635 "SIG_ERR" | 636 // Similar for SIG_DFL/IGN/GET/SGE/ACK 637 "SIG_DFL" | "SIG_IGN" | "SIG_GET" | "SIG_SGE" | "SIG_ACK" => true, 638 // FIXME: newer windows-gnu environment on CI? 639 "_O_OBTAIN_DIR" if gnu => true, 640 _ => false, 641 } 642 }); 643 644 cfg.skip_field(move |s, field| match s { 645 "CONTEXT" if field == "Fp" => true, 646 _ => false, 647 }); 648 // FIXME: All functions point to the wrong addresses? 649 cfg.skip_fn_ptrcheck(|_| true); 650 651 cfg.skip_signededness(move |c| { 652 match c { 653 // windows-isms 654 n if n.starts_with("P") => true, 655 n if n.starts_with("H") => true, 656 n if n.starts_with("LP") => true, 657 "sighandler_t" if gnu => true, 658 _ => false, 659 } 660 }); 661 662 cfg.skip_fn(move |name| { 663 match name { 664 // FIXME: https://github.com/rust-lang/libc/issues/1272 665 "execv" | "execve" | "execvp" | "execvpe" => true, 666 667 _ => false, 668 } 669 }); 670 671 cfg.generate("../src/lib.rs", "main.rs"); 672 } 673 674 fn test_redox(target: &str) { 675 assert!(target.contains("redox")); 676 677 let mut cfg = ctest_cfg(); 678 cfg.flag("-Wno-deprecated-declarations"); 679 680 headers! { 681 cfg: 682 "ctype.h", 683 "dirent.h", 684 "dlfcn.h", 685 "errno.h", 686 "fcntl.h", 687 "grp.h", 688 "limits.h", 689 "locale.h", 690 "netdb.h", 691 "netinet/in.h", 692 "netinet/ip.h", 693 "netinet/tcp.h", 694 "poll.h", 695 "pwd.h", 696 "semaphore.h", 697 "string.h", 698 "strings.h", 699 "sys/file.h", 700 "sys/ioctl.h", 701 "sys/mman.h", 702 "sys/ptrace.h", 703 "sys/resource.h", 704 "sys/socket.h", 705 "sys/stat.h", 706 "sys/statvfs.h", 707 "sys/time.h", 708 "sys/types.h", 709 "sys/uio.h", 710 "sys/un.h", 711 "sys/utsname.h", 712 "sys/wait.h", 713 "termios.h", 714 "time.h", 715 "unistd.h", 716 "utime.h", 717 "wchar.h", 718 } 719 720 cfg.generate("../src/lib.rs", "main.rs"); 721 } 722 723 fn test_solarish(target: &str) { 724 let is_solaris = target.contains("solaris"); 725 let is_illumos = target.contains("illumos"); 726 assert!(is_solaris || is_illumos); 727 728 // ctest generates arguments supported only by clang, so make sure to run with CC=clang. 729 // While debugging, "CFLAGS=-ferror-limit=<large num>" is useful to get more error output. 730 let mut cfg = ctest_cfg(); 731 cfg.flag("-Wno-deprecated-declarations"); 732 733 cfg.define("_XOPEN_SOURCE", Some("700")); 734 cfg.define("__EXTENSIONS__", None); 735 cfg.define("_LCONV_C99", None); 736 737 headers! { 738 cfg: 739 "ctype.h", 740 "dirent.h", 741 "dlfcn.h", 742 "door.h", 743 "errno.h", 744 "execinfo.h", 745 "fcntl.h", 746 "glob.h", 747 "grp.h", 748 "ifaddrs.h", 749 "langinfo.h", 750 "limits.h", 751 "link.h", 752 "locale.h", 753 "mqueue.h", 754 "net/if.h", 755 "net/if_arp.h", 756 "net/route.h", 757 "netdb.h", 758 "netinet/in.h", 759 "netinet/ip.h", 760 "netinet/tcp.h", 761 "netinet/udp.h", 762 "poll.h", 763 "port.h", 764 "pthread.h", 765 "pwd.h", 766 "resolv.h", 767 "sched.h", 768 "semaphore.h", 769 "signal.h", 770 "stddef.h", 771 "stdint.h", 772 "stdio.h", 773 "stdlib.h", 774 "string.h", 775 "sys/auxv.h", 776 "sys/epoll.h", 777 "sys/eventfd.h", 778 "sys/file.h", 779 "sys/filio.h", 780 "sys/ioctl.h", 781 "sys/lgrp_user.h", 782 "sys/loadavg.h", 783 "sys/mman.h", 784 "sys/mount.h", 785 "sys/priv.h", 786 "sys/pset.h", 787 "sys/random.h", 788 "sys/resource.h", 789 "sys/sendfile.h", 790 "sys/socket.h", 791 "sys/stat.h", 792 "sys/statvfs.h", 793 "sys/stropts.h", 794 "sys/shm.h", 795 "sys/systeminfo.h", 796 "sys/time.h", 797 "sys/times.h", 798 "sys/timex.h", 799 "sys/types.h", 800 "sys/uio.h", 801 "sys/un.h", 802 "sys/utsname.h", 803 "sys/wait.h", 804 "syslog.h", 805 "termios.h", 806 "thread.h", 807 "time.h", 808 "priv.h", 809 "ucontext.h", 810 "unistd.h", 811 "utime.h", 812 "utmpx.h", 813 "wchar.h", 814 } 815 816 cfg.skip_type(move |ty| match ty { 817 "sighandler_t" => true, 818 _ => false, 819 }); 820 821 cfg.type_name(move |ty, is_struct, is_union| match ty { 822 "FILE" => "__FILE".to_string(), 823 "DIR" | "Dl_info" => ty.to_string(), 824 t if t.ends_with("_t") => t.to_string(), 825 t if is_struct => format!("struct {}", t), 826 t if is_union => format!("union {}", t), 827 t => t.to_string(), 828 }); 829 830 cfg.field_name(move |struct_, field| { 831 match struct_ { 832 // rust struct uses raw u64, rather than union 833 "epoll_event" if field == "u64" => "data.u64".to_string(), 834 // rust struct was committed with typo for Solaris 835 "door_arg_t" if field == "dec_num" => "desc_num".to_string(), 836 "stat" if field.ends_with("_nsec") => { 837 // expose stat.Xtim.tv_nsec fields 838 field.trim_end_matches("e_nsec").to_string() + ".tv_nsec" 839 } 840 _ => field.to_string(), 841 } 842 }); 843 844 cfg.skip_const(move |name| match name { 845 "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" | "DT_SOCK" 846 | "USRQUOTA" | "GRPQUOTA" | "PRIO_MIN" | "PRIO_MAX" => true, 847 848 // skip sighandler_t assignments 849 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, 850 851 "DT_UNKNOWN" => true, 852 853 "_UTX_LINESIZE" | "_UTX_USERSIZE" | "_UTX_PADSIZE" | "_UTX_IDSIZE" | "_UTX_HOSTSIZE" => { 854 true 855 } 856 857 "EADI" | "EXTPROC" | "IPC_SEAT" => true, 858 859 // This evaluates to a sysconf() call rather than a constant 860 "PTHREAD_STACK_MIN" => true, 861 862 // EPOLLEXCLUSIVE is a relatively recent addition to the epoll interface and may not be 863 // defined on older systems. It is, however, safe to use on systems which do not 864 // explicitly support it. (A no-op is an acceptable implementation of EPOLLEXCLUSIVE.) 865 "EPOLLEXCLUSIVE" => true, 866 867 _ => false, 868 }); 869 870 cfg.skip_struct(move |ty| { 871 if ty.starts_with("__c_anonymous_") { 872 return true; 873 } 874 // the union handling is a mess 875 if ty.contains("door_desc_t_") { 876 return true; 877 } 878 match ty { 879 // union, not a struct 880 "sigval" => true, 881 // a bunch of solaris-only fields 882 "utmpx" if is_illumos => true, 883 _ => false, 884 } 885 }); 886 887 cfg.skip_field(move |s, field| { 888 match s { 889 // C99 sizing on this is tough 890 "dirent" if field == "d_name" => true, 891 // the union/macro makes this rough 892 "sigaction" if field == "sa_sigaction" => true, 893 // Missing in illumos 894 "sigevent" if field == "ss_sp" => true, 895 // Avoid sigval union issues 896 "sigevent" if field == "sigev_value" => true, 897 // const issues 898 "sigevent" if field == "sigev_notify_attributes" => true, 899 900 // Avoid const and union issues 901 "door_arg" if field == "desc_ptr" => true, 902 "door_desc_t" if field == "d_data" => true, 903 "door_arg_t" if field.ends_with("_ptr") => true, 904 "door_arg_t" if field.ends_with("rbuf") => true, 905 906 // anonymous union challenges 907 "fpregset_t" if field == "fp_reg_set" => true, 908 909 // The LX brand (integrated into some illumos distros) commandeered several of the 910 // `uc_filler` fields to use for brand-specific state. 911 "ucontext_t" if is_illumos && (field == "uc_filler" || field == "uc_brand_data") => { 912 true 913 } 914 915 _ => false, 916 } 917 }); 918 919 cfg.skip_fn(move |name| { 920 // skip those that are manually verified 921 match name { 922 // const-ness only added recently 923 "dladdr" => true, 924 925 // Definition of those functions as changed since unified headers 926 // from NDK r14b These changes imply some API breaking changes but 927 // are still ABI compatible. We can wait for the next major release 928 // to be compliant with the new API. 929 // 930 // FIXME: unskip these for next major release 931 "setpriority" | "personality" => true, 932 933 // signal is defined in terms of sighandler_t, so ignore 934 "signal" => true, 935 936 // Currently missing 937 "cfmakeraw" | "cfsetspeed" => true, 938 939 // const-ness issues 940 "execv" | "execve" | "execvp" | "settimeofday" | "sethostname" => true, 941 942 // Solaris-different 943 "getpwent_r" | "getgrent_r" | "updwtmpx" if is_illumos => true, 944 "madvise" | "mprotect" if is_illumos => true, 945 "door_call" | "door_return" | "door_create" if is_illumos => true, 946 947 // Not visible when build with _XOPEN_SOURCE=700 948 "mmapobj" | "mmap64" | "meminfo" | "getpagesizes" | "getpagesizes2" => true, 949 950 // These functions may return int or void depending on the exact 951 // configuration of the compilation environment, but the return 952 // value is not useful (always 0) so we can ignore it: 953 "setservent" | "endservent" if is_illumos => true, 954 955 _ => false, 956 } 957 }); 958 959 cfg.generate("../src/lib.rs", "main.rs"); 960 } 961 962 fn test_netbsd(target: &str) { 963 assert!(target.contains("netbsd")); 964 let rumprun = target.contains("rumprun"); 965 let mut cfg = ctest_cfg(); 966 967 cfg.flag("-Wno-deprecated-declarations"); 968 cfg.define("_NETBSD_SOURCE", Some("1")); 969 970 headers! { 971 cfg: 972 "elf.h", 973 "errno.h", 974 "fcntl.h", 975 "limits.h", 976 "link.h", 977 "locale.h", 978 "stddef.h", 979 "stdint.h", 980 "stdio.h", 981 "stdlib.h", 982 "sys/stat.h", 983 "sys/types.h", 984 "time.h", 985 "wchar.h", 986 "aio.h", 987 "ctype.h", 988 "dirent.h", 989 "dlfcn.h", 990 "glob.h", 991 "grp.h", 992 "ifaddrs.h", 993 "langinfo.h", 994 "net/bpf.h", 995 "net/if.h", 996 "net/if_arp.h", 997 "net/if_dl.h", 998 "net/route.h", 999 "netdb.h", 1000 "netinet/in.h", 1001 "netinet/ip.h", 1002 "netinet/tcp.h", 1003 "netinet/udp.h", 1004 "poll.h", 1005 "pthread.h", 1006 "pwd.h", 1007 "regex.h", 1008 "resolv.h", 1009 "sched.h", 1010 "semaphore.h", 1011 "signal.h", 1012 "string.h", 1013 "sys/endian.h", 1014 "sys/exec_elf.h", 1015 "sys/extattr.h", 1016 "sys/file.h", 1017 "sys/ioctl.h", 1018 "sys/ioctl_compat.h", 1019 "sys/ipc.h", 1020 "sys/ktrace.h", 1021 "sys/mman.h", 1022 "sys/mount.h", 1023 "sys/ptrace.h", 1024 "sys/resource.h", 1025 "sys/shm.h", 1026 "sys/socket.h", 1027 "sys/statvfs.h", 1028 "sys/sysctl.h", 1029 "sys/time.h", 1030 "sys/times.h", 1031 "sys/timex.h", 1032 "sys/ucontext.h", 1033 "sys/ucred.h", 1034 "sys/uio.h", 1035 "sys/un.h", 1036 "sys/utsname.h", 1037 "sys/wait.h", 1038 "syslog.h", 1039 "termios.h", 1040 "ufs/ufs/quota.h", 1041 "ufs/ufs/quota1.h", 1042 "unistd.h", 1043 "util.h", 1044 "utime.h", 1045 "mqueue.h", 1046 "netinet/dccp.h", 1047 "sys/event.h", 1048 "sys/quota.h", 1049 "sys/shm.h", 1050 "iconv.h", 1051 } 1052 1053 cfg.type_name(move |ty, is_struct, is_union| { 1054 match ty { 1055 // Just pass all these through, no need for a "struct" prefix 1056 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 1057 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 1058 | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(), 1059 1060 // OSX calls this something else 1061 "sighandler_t" => "sig_t".to_string(), 1062 1063 t if is_union => format!("union {}", t), 1064 1065 t if t.ends_with("_t") => t.to_string(), 1066 1067 // put `struct` in front of all structs:. 1068 t if is_struct => format!("struct {}", t), 1069 1070 t => t.to_string(), 1071 } 1072 }); 1073 1074 cfg.field_name(move |struct_, field| { 1075 match field { 1076 // Our stat *_nsec fields normally don't actually exist but are part 1077 // of a timeval struct 1078 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 1079 s.replace("e_nsec", ".tv_nsec") 1080 } 1081 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 1082 s => s.to_string(), 1083 } 1084 }); 1085 1086 cfg.skip_type(move |ty| { 1087 if ty.starts_with("__c_anonymous_") { 1088 return true; 1089 } 1090 match ty { 1091 // FIXME: sighandler_t is crazy across platforms 1092 "sighandler_t" => true, 1093 _ => false, 1094 } 1095 }); 1096 1097 cfg.skip_struct(move |ty| { 1098 match ty { 1099 // This is actually a union, not a struct 1100 "sigval" => true, 1101 // These are tested as part of the linux_fcntl tests since there are 1102 // header conflicts when including them with all the other structs. 1103 "termios2" => true, 1104 _ => false, 1105 } 1106 }); 1107 1108 cfg.skip_signededness(move |c| { 1109 match c { 1110 "LARGE_INTEGER" | "float" | "double" => true, 1111 n if n.starts_with("pthread") => true, 1112 // sem_t is a struct or pointer 1113 "sem_t" => true, 1114 _ => false, 1115 } 1116 }); 1117 1118 cfg.skip_const(move |name| { 1119 match name { 1120 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 1121 "SIGUNUSED" => true, // removed in glibc 2.26 1122 1123 // weird signed extension or something like that? 1124 "MS_NOUSER" => true, 1125 "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 1126 "BOTHER" => true, 1127 1128 _ => false, 1129 } 1130 }); 1131 1132 cfg.skip_fn(move |name| { 1133 match name { 1134 // FIXME: https://github.com/rust-lang/libc/issues/1272 1135 "execv" | "execve" | "execvp" => true, 1136 1137 "getrlimit" | "getrlimit64" | // non-int in 1st arg 1138 "setrlimit" | "setrlimit64" | // non-int in 1st arg 1139 "prlimit" | "prlimit64" | // non-int in 2nd arg 1140 1141 // These functions presumably exist on netbsd but don't look like 1142 // they're implemented on rumprun yet, just let them slide for now. 1143 // Some of them look like they have headers but then don't have 1144 // corresponding actual definitions either... 1145 "shm_open" | 1146 "shm_unlink" | 1147 "syscall" | 1148 "mq_open" | 1149 "mq_close" | 1150 "mq_getattr" | 1151 "mq_notify" | 1152 "mq_receive" | 1153 "mq_send" | 1154 "mq_setattr" | 1155 "mq_timedreceive" | 1156 "mq_timedsend" | 1157 "mq_unlink" | 1158 "ptrace" | 1159 "sigaltstack" if rumprun => true, 1160 1161 _ => false, 1162 } 1163 }); 1164 1165 cfg.skip_field_type(move |struct_, field| { 1166 // This is a weird union, don't check the type. 1167 (struct_ == "ifaddrs" && field == "ifa_ifu") || 1168 // sighandler_t type is super weird 1169 (struct_ == "sigaction" && field == "sa_sigaction") || 1170 // sigval is actually a union, but we pretend it's a struct 1171 (struct_ == "sigevent" && field == "sigev_value") || 1172 // aio_buf is "volatile void*" and Rust doesn't understand volatile 1173 (struct_ == "aiocb" && field == "aio_buf") 1174 }); 1175 1176 cfg.skip_field(|struct_, field| { 1177 match (struct_, field) { 1178 // conflicting with `p_type` macro from <resolve.h>. 1179 ("Elf32_Phdr", "p_type") => true, 1180 ("Elf64_Phdr", "p_type") => true, 1181 // pthread_spin_t is a volatile uchar 1182 ("pthread_spinlock_t", "pts_spin") => true, 1183 _ => false, 1184 } 1185 }); 1186 1187 cfg.generate("../src/lib.rs", "main.rs"); 1188 } 1189 1190 fn test_dragonflybsd(target: &str) { 1191 assert!(target.contains("dragonfly")); 1192 let mut cfg = ctest_cfg(); 1193 cfg.flag("-Wno-deprecated-declarations"); 1194 1195 headers! { 1196 cfg: 1197 "aio.h", 1198 "ctype.h", 1199 "dirent.h", 1200 "dlfcn.h", 1201 "errno.h", 1202 "execinfo.h", 1203 "fcntl.h", 1204 "glob.h", 1205 "grp.h", 1206 "ifaddrs.h", 1207 "langinfo.h", 1208 "limits.h", 1209 "link.h", 1210 "locale.h", 1211 "mqueue.h", 1212 "net/bpf.h", 1213 "net/if.h", 1214 "net/if_arp.h", 1215 "net/if_dl.h", 1216 "net/route.h", 1217 "netdb.h", 1218 "netinet/in.h", 1219 "netinet/ip.h", 1220 "netinet/tcp.h", 1221 "netinet/udp.h", 1222 "poll.h", 1223 "pthread.h", 1224 "pthread_np.h", 1225 "pwd.h", 1226 "regex.h", 1227 "resolv.h", 1228 "sched.h", 1229 "semaphore.h", 1230 "signal.h", 1231 "stddef.h", 1232 "stdint.h", 1233 "stdio.h", 1234 "stdlib.h", 1235 "string.h", 1236 "sys/event.h", 1237 "sys/file.h", 1238 "sys/ioctl.h", 1239 "sys/cpuctl.h", 1240 "sys/ipc.h", 1241 "sys/kinfo.h", 1242 "sys/ktrace.h", 1243 "sys/malloc.h", 1244 "sys/mman.h", 1245 "sys/mount.h", 1246 "sys/procctl.h", 1247 "sys/ptrace.h", 1248 "sys/resource.h", 1249 "sys/rtprio.h", 1250 "sys/sched.h", 1251 "sys/shm.h", 1252 "sys/socket.h", 1253 "sys/stat.h", 1254 "sys/statvfs.h", 1255 "sys/sysctl.h", 1256 "sys/time.h", 1257 "sys/times.h", 1258 "sys/timex.h", 1259 "sys/types.h", 1260 "sys/checkpoint.h", 1261 "sys/uio.h", 1262 "sys/un.h", 1263 "sys/utsname.h", 1264 "sys/wait.h", 1265 "syslog.h", 1266 "termios.h", 1267 "time.h", 1268 "ucontext.h", 1269 "unistd.h", 1270 "util.h", 1271 "utime.h", 1272 "utmpx.h", 1273 "vfs/ufs/quota.h", 1274 "wchar.h", 1275 "iconv.h", 1276 } 1277 1278 cfg.type_name(move |ty, is_struct, is_union| { 1279 match ty { 1280 // Just pass all these through, no need for a "struct" prefix 1281 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 1282 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 1283 | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(), 1284 1285 // FIXME: OSX calls this something else 1286 "sighandler_t" => "sig_t".to_string(), 1287 1288 t if is_union => format!("union {}", t), 1289 1290 t if t.ends_with("_t") => t.to_string(), 1291 1292 // sigval is a struct in Rust, but a union in C: 1293 "sigval" => format!("union sigval"), 1294 1295 // put `struct` in front of all structs:. 1296 t if is_struct => format!("struct {}", t), 1297 1298 t => t.to_string(), 1299 } 1300 }); 1301 1302 cfg.field_name(move |struct_, field| { 1303 match field { 1304 // Our stat *_nsec fields normally don't actually exist but are part 1305 // of a timeval struct 1306 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 1307 s.replace("e_nsec", ".tv_nsec") 1308 } 1309 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 1310 // Field is named `type` in C but that is a Rust keyword, 1311 // so these fields are translated to `type_` in the bindings. 1312 "type_" if struct_ == "rtprio" => "type".to_string(), 1313 s => s.to_string(), 1314 } 1315 }); 1316 1317 cfg.skip_type(move |ty| { 1318 match ty { 1319 // sighandler_t is crazy across platforms 1320 "sighandler_t" => true, 1321 1322 _ => false, 1323 } 1324 }); 1325 1326 cfg.skip_struct(move |ty| { 1327 match ty { 1328 // FIXME: These are tested as part of the linux_fcntl tests since 1329 // there are header conflicts when including them with all the other 1330 // structs. 1331 "termios2" => true, 1332 1333 _ => false, 1334 } 1335 }); 1336 1337 cfg.skip_signededness(move |c| { 1338 match c { 1339 "LARGE_INTEGER" | "float" | "double" => true, 1340 // uuid_t is a struct, not an integer. 1341 "uuid_t" => true, 1342 n if n.starts_with("pthread") => true, 1343 // sem_t is a struct or pointer 1344 "sem_t" => true, 1345 // mqd_t is a pointer on DragonFly 1346 "mqd_t" => true, 1347 1348 _ => false, 1349 } 1350 }); 1351 1352 cfg.skip_const(move |name| { 1353 match name { 1354 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 1355 1356 // weird signed extension or something like that? 1357 "MS_NOUSER" => true, 1358 "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 1359 1360 // These are defined for Solaris 11, but the crate is tested on 1361 // illumos, where they are currently not defined 1362 "EADI" | "PORT_SOURCE_POSTWAIT" | "PORT_SOURCE_SIGNAL" | "PTHREAD_STACK_MIN" => true, 1363 1364 _ => false, 1365 } 1366 }); 1367 1368 cfg.skip_fn(move |name| { 1369 // skip those that are manually verified 1370 match name { 1371 // FIXME: https://github.com/rust-lang/libc/issues/1272 1372 "execv" | "execve" | "execvp" | "fexecve" => true, 1373 1374 "getrlimit" | "getrlimit64" | // non-int in 1st arg 1375 "setrlimit" | "setrlimit64" | // non-int in 1st arg 1376 "prlimit" | "prlimit64" // non-int in 2nd arg 1377 => true, 1378 1379 _ => false, 1380 } 1381 }); 1382 1383 cfg.skip_field_type(move |struct_, field| { 1384 // This is a weird union, don't check the type. 1385 (struct_ == "ifaddrs" && field == "ifa_ifu") || 1386 // sighandler_t type is super weird 1387 (struct_ == "sigaction" && field == "sa_sigaction") || 1388 // sigval is actually a union, but we pretend it's a struct 1389 (struct_ == "sigevent" && field == "sigev_value") || 1390 // aio_buf is "volatile void*" and Rust doesn't understand volatile 1391 (struct_ == "aiocb" && field == "aio_buf") 1392 }); 1393 1394 cfg.skip_field(move |struct_, field| { 1395 // this is actually a union on linux, so we can't represent it well and 1396 // just insert some padding. 1397 (struct_ == "siginfo_t" && field == "_pad") || 1398 // sigev_notify_thread_id is actually part of a sigev_un union 1399 (struct_ == "sigevent" && field == "sigev_notify_thread_id") 1400 }); 1401 1402 cfg.generate("../src/lib.rs", "main.rs"); 1403 } 1404 1405 fn test_wasi(target: &str) { 1406 assert!(target.contains("wasi")); 1407 1408 let mut cfg = ctest_cfg(); 1409 cfg.define("_GNU_SOURCE", None); 1410 1411 headers! { cfg: 1412 "ctype.h", 1413 "dirent.h", 1414 "errno.h", 1415 "fcntl.h", 1416 "limits.h", 1417 "locale.h", 1418 "malloc.h", 1419 "poll.h", 1420 "sched.h", 1421 "stdbool.h", 1422 "stddef.h", 1423 "stdint.h", 1424 "stdio.h", 1425 "stdlib.h", 1426 "string.h", 1427 "sys/resource.h", 1428 "sys/select.h", 1429 "sys/socket.h", 1430 "sys/stat.h", 1431 "sys/times.h", 1432 "sys/types.h", 1433 "sys/uio.h", 1434 "sys/utsname.h", 1435 "sys/ioctl.h", 1436 "time.h", 1437 "unistd.h", 1438 "wasi/api.h", 1439 "wasi/libc.h", 1440 "wasi/libc-find-relpath.h", 1441 "wasi/libc-nocwd.h", 1442 "wchar.h", 1443 } 1444 1445 cfg.type_name(move |ty, is_struct, is_union| match ty { 1446 "FILE" | "fd_set" | "DIR" => ty.to_string(), 1447 t if is_union => format!("union {}", t), 1448 t if t.starts_with("__wasi") && t.ends_with("_u") => format!("union {}", t), 1449 t if t.starts_with("__wasi") && is_struct => format!("struct {}", t), 1450 t if t.ends_with("_t") => t.to_string(), 1451 t if is_struct => format!("struct {}", t), 1452 t => t.to_string(), 1453 }); 1454 1455 cfg.field_name(move |_struct, field| { 1456 match field { 1457 // deal with fields as rust keywords 1458 "type_" => "type".to_string(), 1459 s => s.to_string(), 1460 } 1461 }); 1462 1463 // Looks like LLD doesn't merge duplicate imports, so if the Rust 1464 // code imports from a module and the C code also imports from a 1465 // module we end up with two imports of function pointers which 1466 // import the same thing but have different function pointers 1467 cfg.skip_fn_ptrcheck(|f| f.starts_with("__wasi")); 1468 1469 // d_name is declared as a flexible array in WASI libc, so it 1470 // doesn't support sizeof. 1471 cfg.skip_field(|s, field| s == "dirent" && field == "d_name"); 1472 1473 // Currently Rust/clang disagree on function argument ABI, so skip these 1474 // tests. For more info see WebAssembly/tool-conventions#88 1475 cfg.skip_roundtrip(|_| true); 1476 1477 cfg.generate("../src/lib.rs", "main.rs"); 1478 } 1479 1480 fn test_android(target: &str) { 1481 assert!(target.contains("android")); 1482 let target_pointer_width = match target { 1483 t if t.contains("aarch64") || t.contains("x86_64") => 64, 1484 t if t.contains("i686") || t.contains("arm") => 32, 1485 t => panic!("unsupported target: {}", t), 1486 }; 1487 let x86 = target.contains("i686") || target.contains("x86_64"); 1488 1489 let mut cfg = ctest_cfg(); 1490 cfg.define("_GNU_SOURCE", None); 1491 1492 headers! { cfg: 1493 "arpa/inet.h", 1494 "ctype.h", 1495 "dirent.h", 1496 "dlfcn.h", 1497 "elf.h", 1498 "errno.h", 1499 "fcntl.h", 1500 "grp.h", 1501 "ifaddrs.h", 1502 "limits.h", 1503 "link.h", 1504 "locale.h", 1505 "malloc.h", 1506 "net/ethernet.h", 1507 "net/if.h", 1508 "net/if_arp.h", 1509 "net/route.h", 1510 "netdb.h", 1511 "netinet/in.h", 1512 "netinet/ip.h", 1513 "netinet/tcp.h", 1514 "netinet/udp.h", 1515 "netpacket/packet.h", 1516 "poll.h", 1517 "pthread.h", 1518 "pty.h", 1519 "pwd.h", 1520 "regex.h", 1521 "resolv.h", 1522 "sched.h", 1523 "semaphore.h", 1524 "signal.h", 1525 "stddef.h", 1526 "stdint.h", 1527 "stdio.h", 1528 "stdlib.h", 1529 "string.h", 1530 "sys/auxv.h", 1531 "sys/epoll.h", 1532 "sys/eventfd.h", 1533 "sys/file.h", 1534 "sys/fsuid.h", 1535 "sys/inotify.h", 1536 "sys/ioctl.h", 1537 "sys/mman.h", 1538 "sys/mount.h", 1539 "sys/personality.h", 1540 "sys/prctl.h", 1541 "sys/ptrace.h", 1542 "sys/random.h", 1543 "sys/reboot.h", 1544 "sys/resource.h", 1545 "sys/sendfile.h", 1546 "sys/signalfd.h", 1547 "sys/socket.h", 1548 "sys/stat.h", 1549 "sys/statvfs.h", 1550 "sys/swap.h", 1551 "sys/syscall.h", 1552 "sys/sysinfo.h", 1553 "sys/system_properties.h", 1554 "sys/time.h", 1555 "sys/timerfd.h", 1556 "sys/times.h", 1557 "sys/types.h", 1558 "sys/ucontext.h", 1559 "sys/uio.h", 1560 "sys/un.h", 1561 "sys/user.h", 1562 "sys/utsname.h", 1563 "sys/vfs.h", 1564 "sys/xattr.h", 1565 "sys/wait.h", 1566 "syslog.h", 1567 "termios.h", 1568 "time.h", 1569 "unistd.h", 1570 "utime.h", 1571 "utmp.h", 1572 "wchar.h", 1573 "xlocale.h", 1574 // time64_t is not defined for 64-bit targets If included it will 1575 // generate the error 'Your time_t is already 64-bit' 1576 [target_pointer_width == 32]: "time64.h", 1577 [x86]: "sys/reg.h", 1578 } 1579 1580 // Include linux headers at the end: 1581 headers! { cfg: 1582 "asm/mman.h", 1583 "linux/auxvec.h", 1584 "linux/dccp.h", 1585 "linux/elf.h", 1586 "linux/errqueue.h", 1587 "linux/falloc.h", 1588 "linux/filter.h", 1589 "linux/futex.h", 1590 "linux/fs.h", 1591 "linux/genetlink.h", 1592 "linux/if_alg.h", 1593 "linux/if_ether.h", 1594 "linux/if_tun.h", 1595 "linux/magic.h", 1596 "linux/memfd.h", 1597 "linux/mempolicy.h", 1598 "linux/module.h", 1599 "linux/net_tstamp.h", 1600 "linux/netfilter/nfnetlink.h", 1601 "linux/netfilter/nfnetlink_log.h", 1602 "linux/netfilter/nfnetlink_queue.h", 1603 "linux/netfilter/nf_tables.h", 1604 "linux/netfilter_ipv4.h", 1605 "linux/netfilter_ipv6.h", 1606 "linux/netfilter_ipv6/ip6_tables.h", 1607 "linux/netlink.h", 1608 "linux/quota.h", 1609 "linux/reboot.h", 1610 "linux/seccomp.h", 1611 "linux/sched.h", 1612 "linux/sockios.h", 1613 "linux/vm_sockets.h", 1614 "linux/wait.h", 1615 1616 } 1617 1618 // Include Android-specific headers: 1619 headers! { cfg: 1620 "android/set_abort_message.h" 1621 } 1622 1623 cfg.type_name(move |ty, is_struct, is_union| { 1624 match ty { 1625 // Just pass all these through, no need for a "struct" prefix 1626 "FILE" | "fd_set" | "Dl_info" | "Elf32_Phdr" | "Elf64_Phdr" => ty.to_string(), 1627 1628 t if is_union => format!("union {}", t), 1629 1630 t if t.ends_with("_t") => t.to_string(), 1631 1632 // sigval is a struct in Rust, but a union in C: 1633 "sigval" => format!("union sigval"), 1634 1635 // put `struct` in front of all structs:. 1636 t if is_struct => format!("struct {}", t), 1637 1638 t => t.to_string(), 1639 } 1640 }); 1641 1642 cfg.field_name(move |struct_, field| { 1643 match field { 1644 // Our stat *_nsec fields normally don't actually exist but are part 1645 // of a timeval struct 1646 s if s.ends_with("_nsec") && struct_.starts_with("stat") => s.to_string(), 1647 // FIXME: appears that `epoll_event.data` is an union 1648 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 1649 s => s.to_string(), 1650 } 1651 }); 1652 1653 cfg.skip_type(move |ty| { 1654 match ty { 1655 // FIXME: `sighandler_t` type is incorrect, see: 1656 // https://github.com/rust-lang/libc/issues/1359 1657 "sighandler_t" => true, 1658 1659 // These are tested in the `linux_elf.rs` file. 1660 "Elf64_Phdr" | "Elf32_Phdr" => true, 1661 _ => false, 1662 } 1663 }); 1664 1665 cfg.skip_struct(move |ty| { 1666 if ty.starts_with("__c_anonymous_") { 1667 return true; 1668 } 1669 match ty { 1670 // These are tested as part of the linux_fcntl tests since there are 1671 // header conflicts when including them with all the other structs. 1672 "termios2" => true, 1673 // uc_sigmask and uc_sigmask64 of ucontext_t are an anonymous union 1674 "ucontext_t" => true, 1675 // 'private' type 1676 "prop_info" => true, 1677 1678 // These are tested in the `linux_elf.rs` file. 1679 "Elf64_Phdr" | "Elf32_Phdr" => true, 1680 1681 _ => false, 1682 } 1683 }); 1684 1685 cfg.skip_const(move |name| { 1686 match name { 1687 // The IPV6 constants are tested in the `linux_ipv6.rs` tests: 1688 | "IPV6_FLOWINFO" 1689 | "IPV6_FLOWLABEL_MGR" 1690 | "IPV6_FLOWINFO_SEND" 1691 | "IPV6_FLOWINFO_FLOWLABEL" 1692 | "IPV6_FLOWINFO_PRIORITY" 1693 // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: 1694 | "F_CANCELLK" 1695 | "F_ADD_SEALS" 1696 | "F_GET_SEALS" 1697 | "F_SEAL_SEAL" 1698 | "F_SEAL_SHRINK" 1699 | "F_SEAL_GROW" 1700 | "F_SEAL_WRITE" => true, 1701 1702 // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests: 1703 "ARPHRD_CAN" => true, 1704 1705 // FIXME: deprecated: not available in any header 1706 // See: https://github.com/rust-lang/libc/issues/1356 1707 "ENOATTR" => true, 1708 1709 // FIXME: still necessary? 1710 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 1711 // FIXME: deprecated - removed in glibc 2.26 1712 "SIGUNUSED" => true, 1713 1714 // Needs a newer Android SDK for the definition 1715 "P_PIDFD" => true, 1716 1717 // Requires Linux kernel 5.6 1718 "VMADDR_CID_LOCAL" => true, 1719 1720 // FIXME: conflicts with standard C headers and is tested in 1721 // `linux_termios.rs` below: 1722 "BOTHER" => true, 1723 "IBSHIFT" => true, 1724 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => true, 1725 1726 // is a private value for kernel usage normally 1727 "FUSE_SUPER_MAGIC" => true, 1728 // linux 5.12 min 1729 "MPOL_F_NUMA_BALANCING" => true, 1730 1731 _ => false, 1732 } 1733 }); 1734 1735 cfg.skip_fn(move |name| { 1736 // skip those that are manually verified 1737 match name { 1738 // FIXME: https://github.com/rust-lang/libc/issues/1272 1739 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 1740 1741 // There are two versions of the sterror_r function, see 1742 // 1743 // https://linux.die.net/man/3/strerror_r 1744 // 1745 // An XSI-compliant version provided if: 1746 // 1747 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE 1748 // 1749 // and a GNU specific version provided if _GNU_SOURCE is defined. 1750 // 1751 // libc provides bindings for the XSI-compliant version, which is 1752 // preferred for portable applications. 1753 // 1754 // We skip the test here since here _GNU_SOURCE is defined, and 1755 // test the XSI version below. 1756 "strerror_r" => true, 1757 "reallocarray" => true, 1758 "__system_property_wait" => true, 1759 1760 // Added in API level 30, but tests use level 28. 1761 "mlock2" => true, 1762 1763 // Added in glibc 2.25. 1764 "getentropy" => true, 1765 1766 _ => false, 1767 } 1768 }); 1769 1770 cfg.skip_field_type(move |struct_, field| { 1771 // This is a weird union, don't check the type. 1772 (struct_ == "ifaddrs" && field == "ifa_ifu") || 1773 // sigval is actually a union, but we pretend it's a struct 1774 (struct_ == "sigevent" && field == "sigev_value") || 1775 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 1776 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 1777 (struct_ == "sigaction" && field == "sa_sigaction") || 1778 // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet. 1779 (struct_ == "signalfd_siginfo" && field == "ssi_call_addr") 1780 }); 1781 1782 cfg.skip_field(move |struct_, field| { 1783 // this is actually a union on linux, so we can't represent it well and 1784 // just insert some padding. 1785 (struct_ == "siginfo_t" && field == "_pad") || 1786 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 1787 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 1788 (struct_ == "sigaction" && field == "sa_sigaction") || 1789 // sigev_notify_thread_id is actually part of a sigev_un union 1790 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 1791 // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet. 1792 (struct_ == "signalfd_siginfo" && (field == "ssi_syscall" || 1793 field == "ssi_call_addr" || 1794 field == "ssi_arch")) 1795 }); 1796 1797 cfg.skip_field(|struct_, field| { 1798 match (struct_, field) { 1799 // conflicting with `p_type` macro from <resolve.h>. 1800 ("Elf32_Phdr", "p_type") => true, 1801 ("Elf64_Phdr", "p_type") => true, 1802 1803 // this is actually a union on linux, so we can't represent it well and 1804 // just insert some padding. 1805 ("siginfo_t", "_pad") => true, 1806 1807 _ => false, 1808 } 1809 }); 1810 1811 cfg.generate("../src/lib.rs", "main.rs"); 1812 1813 test_linux_like_apis(target); 1814 } 1815 1816 fn test_freebsd(target: &str) { 1817 assert!(target.contains("freebsd")); 1818 let mut cfg = ctest_cfg(); 1819 1820 let freebsd_ver = which_freebsd(); 1821 1822 match freebsd_ver { 1823 Some(10) => cfg.cfg("freebsd10", None), 1824 Some(11) => cfg.cfg("freebsd11", None), 1825 Some(12) => cfg.cfg("freebsd12", None), 1826 Some(13) => cfg.cfg("freebsd13", None), 1827 Some(14) => cfg.cfg("freebsd14", None), 1828 _ => &mut cfg, 1829 }; 1830 1831 // For sched linux compat fn 1832 cfg.define("_WITH_CPU_SET_T", None); 1833 // Required for `getline`: 1834 cfg.define("_WITH_GETLINE", None); 1835 // Required for making freebsd11_stat available in the headers 1836 match freebsd_ver { 1837 Some(10) => &mut cfg, 1838 _ => cfg.define("_WANT_FREEBSD11_STAT", None), 1839 }; 1840 1841 let freebsd12 = match freebsd_ver { 1842 Some(n) if n >= 12 => true, 1843 _ => false, 1844 }; 1845 1846 let freebsd13 = match freebsd_ver { 1847 Some(n) if n >= 13 => true, 1848 _ => false, 1849 }; 1850 1851 headers! { cfg: 1852 "aio.h", 1853 "arpa/inet.h", 1854 "bsm/audit.h", 1855 "ctype.h", 1856 "dirent.h", 1857 "dlfcn.h", 1858 "elf.h", 1859 "errno.h", 1860 "execinfo.h", 1861 "fcntl.h", 1862 "glob.h", 1863 "grp.h", 1864 "iconv.h", 1865 "ifaddrs.h", 1866 "langinfo.h", 1867 "libutil.h", 1868 "limits.h", 1869 "link.h", 1870 "locale.h", 1871 "machine/elf.h", 1872 "machine/reg.h", 1873 "malloc_np.h", 1874 "mqueue.h", 1875 "net/bpf.h", 1876 "net/if.h", 1877 "net/if_arp.h", 1878 "net/if_dl.h", 1879 "net/if_mib.h", 1880 "net/route.h", 1881 "netdb.h", 1882 "netinet/ip.h", 1883 "netinet/in.h", 1884 "netinet/tcp.h", 1885 "netinet/udp.h", 1886 "poll.h", 1887 "pthread.h", 1888 "pthread_np.h", 1889 "pwd.h", 1890 "regex.h", 1891 "resolv.h", 1892 "sched.h", 1893 "semaphore.h", 1894 "signal.h", 1895 "spawn.h", 1896 "stddef.h", 1897 "stdint.h", 1898 "stdio.h", 1899 "stdlib.h", 1900 "string.h", 1901 "sys/capsicum.h", 1902 [freebsd12]:"sys/auxv.h", 1903 "sys/cpuset.h", 1904 [freebsd12]:"sys/domainset.h", 1905 "sys/event.h", 1906 [freebsd13]:"sys/eventfd.h", 1907 "sys/extattr.h", 1908 "sys/file.h", 1909 "sys/ioctl.h", 1910 "sys/ipc.h", 1911 "sys/jail.h", 1912 "sys/mman.h", 1913 "sys/mount.h", 1914 "sys/msg.h", 1915 "sys/procctl.h", 1916 "sys/procdesc.h", 1917 "sys/ptrace.h", 1918 "sys/queue.h", 1919 "sys/random.h", 1920 "sys/resource.h", 1921 "sys/rtprio.h", 1922 "sys/sem.h", 1923 "sys/shm.h", 1924 "sys/socket.h", 1925 "sys/stat.h", 1926 "sys/statvfs.h", 1927 "sys/sysctl.h", 1928 "sys/thr.h", 1929 "sys/time.h", 1930 "sys/times.h", 1931 "sys/timex.h", 1932 "sys/types.h", 1933 "sys/proc.h", 1934 "kvm.h", // must be after "sys/types.h" 1935 "sys/ucontext.h", 1936 "sys/uio.h", 1937 "sys/ktrace.h", 1938 "sys/un.h", 1939 "sys/user.h", 1940 "sys/utsname.h", 1941 "sys/uuid.h", 1942 "sys/vmmeter.h", 1943 "sys/wait.h", 1944 "libprocstat.h", 1945 "devstat.h", 1946 "syslog.h", 1947 "termios.h", 1948 "time.h", 1949 "ufs/ufs/quota.h", 1950 "unistd.h", 1951 "utime.h", 1952 "utmpx.h", 1953 "wchar.h", 1954 } 1955 1956 cfg.type_name(move |ty, is_struct, is_union| { 1957 match ty { 1958 // Just pass all these through, no need for a "struct" prefix 1959 "FILE" 1960 | "fd_set" 1961 | "Dl_info" 1962 | "DIR" 1963 | "Elf32_Phdr" 1964 | "Elf64_Phdr" 1965 | "Elf32_Auxinfo" 1966 | "Elf64_Auxinfo" 1967 | "devstat_select_mode" 1968 | "devstat_support_flags" 1969 | "devstat_type_flags" 1970 | "devstat_match_flags" 1971 | "devstat_priority" => ty.to_string(), 1972 1973 // FIXME: https://github.com/rust-lang/libc/issues/1273 1974 "sighandler_t" => "sig_t".to_string(), 1975 1976 t if is_union => format!("union {}", t), 1977 1978 t if t.ends_with("_t") => t.to_string(), 1979 1980 // sigval is a struct in Rust, but a union in C: 1981 "sigval" => format!("union sigval"), 1982 1983 // put `struct` in front of all structs:. 1984 t if is_struct => format!("struct {}", t), 1985 1986 t => t.to_string(), 1987 } 1988 }); 1989 1990 cfg.field_name(move |struct_, field| { 1991 match field { 1992 // Our stat *_nsec fields normally don't actually exist but are part 1993 // of a timeval struct 1994 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 1995 s.replace("e_nsec", ".tv_nsec") 1996 } 1997 // Field is named `type` in C but that is a Rust keyword, 1998 // so these fields are translated to `type_` in the bindings. 1999 "type_" if struct_ == "rtprio" => "type".to_string(), 2000 "type_" if struct_ == "sockstat" => "type".to_string(), 2001 "type_" if struct_ == "devstat_match_table" => "type".to_string(), 2002 s => s.to_string(), 2003 } 2004 }); 2005 2006 cfg.skip_const(move |name| { 2007 match name { 2008 // These constants were introduced in FreeBSD 13: 2009 "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" 2010 | "F_SEAL_WRITE" 2011 if Some(13) > freebsd_ver => 2012 { 2013 true 2014 } 2015 2016 // These constants were introduced in FreeBSD 13: 2017 "EFD_CLOEXEC" | "EFD_NONBLOCK" | "EFD_SEMAPHORE" if Some(13) > freebsd_ver => true, 2018 2019 // These constants were introduced in FreeBSD 12: 2020 "SF_USER_READAHEAD" 2021 | "EVFILT_EMPTY" 2022 | "SO_REUSEPORT_LB" 2023 | "IP_ORIGDSTADDR" 2024 | "IP_RECVORIGDSTADDR" 2025 | "IPV6_ORIGDSTADDR" 2026 | "IPV6_RECVORIGDSTADDR" 2027 | "NI_NUMERICSCOPE" 2028 | "SO_DOMAIN" 2029 if Some(11) == freebsd_ver => 2030 { 2031 true 2032 } 2033 2034 // These constants were introduced in FreeBSD 11: 2035 "SF_USER_READAHEAD" 2036 | "SF_NOCACHE" 2037 | "RLIMIT_KQUEUES" 2038 | "RLIMIT_UMTXP" 2039 | "EVFILT_PROCDESC" 2040 | "EVFILT_SENDFILE" 2041 | "EVFILT_EMPTY" 2042 | "SO_REUSEPORT_LB" 2043 | "TCP_CCALGOOPT" 2044 | "TCP_PCAP_OUT" 2045 | "TCP_PCAP_IN" 2046 | "IP_BINDMULTI" 2047 | "IP_ORIGDSTADDR" 2048 | "IP_RECVORIGDSTADDR" 2049 | "IPV6_ORIGDSTADDR" 2050 | "IPV6_RECVORIGDSTADDR" 2051 | "PD_CLOEXEC" 2052 | "PD_ALLOWED_AT_FORK" 2053 | "IP_RSS_LISTEN_BUCKET" 2054 | "NI_NUMERICSCOPE" 2055 if Some(10) == freebsd_ver => 2056 { 2057 true 2058 } 2059 2060 // FIXME: This constant has a different value in FreeBSD 10: 2061 "RLIM_NLIMITS" if Some(10) == freebsd_ver => true, 2062 2063 // FIXME: There are deprecated - remove in a couple of releases. 2064 // These constants were removed in FreeBSD 11 (svn r273250) but will 2065 // still be accepted and ignored at runtime. 2066 "MAP_RENAME" | "MAP_NORESERVE" if Some(10) != freebsd_ver => true, 2067 2068 // FIXME: There are deprecated - remove in a couple of releases. 2069 // These constants were removed in FreeBSD 11 (svn r262489), 2070 // and they've never had any legitimate use outside of the 2071 // base system anyway. 2072 "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "USER_MAXID" => true, 2073 2074 // This constant was removed in FreeBSD 13 (svn r363622), and never 2075 // had any legitimate use outside of the base system anyway. 2076 "CTL_P1003_1B_MAXID" => true, 2077 2078 // This was renamed in FreeBSD 12.2 and 13 (r352486). 2079 "CTL_UNSPEC" | "CTL_SYSCTL" => true, 2080 2081 // These were added in FreeBSD 12.2 and 13 (r352486), 2082 // but they are just names for magic numbers that existed for ages. 2083 "CTL_SYSCTL_DEBUG" 2084 | "CTL_SYSCTL_NAME" 2085 | "CTL_SYSCTL_NEXT" 2086 | "CTL_SYSCTL_NAME2OID" 2087 | "CTL_SYSCTL_OIDFMT" 2088 | "CTL_SYSCTL_OIDDESCR" 2089 | "CTL_SYSCTL_OIDLABEL" => true, 2090 2091 // This was renamed in FreeBSD 12.2 and 13 (r350749). 2092 "IPPROTO_SEP" | "IPPROTO_DCCP" => true, 2093 2094 // This was changed to 96(0x60) in FreeBSD 13: 2095 // https://github.com/freebsd/freebsd/ 2096 // commit/06b00ceaa914a3907e4e27bad924f44612bae1d7 2097 "MINCORE_SUPER" if Some(13) <= freebsd_ver => true, 2098 2099 // Added in FreeBSD 12.0 2100 "EINTEGRITY" if Some(11) == freebsd_ver => true, 2101 2102 // This was increased to 97 in FreeBSD 12.2 and 13. 2103 // https://github.com/freebsd/freebsd/ 2104 // commit/72a21ba0f62da5e86a1c0b462aeb3f5ff849a1b7 2105 "ELAST" if Some(12) == freebsd_ver => true, 2106 2107 // Added in FreeBSD 12.0 (r331279) 2108 "GRND_NONBLOCK" | "GRND_RANDOM" if Some(11) == freebsd_ver => true, 2109 // Added in FreeBSD 13.0 (r356667) 2110 "GRND_INSECURE" if Some(13) > freebsd_ver => true, 2111 2112 // Added in FreeBSD 12.1 (r343964) 2113 "PROC_ASLR_CTL" 2114 | "PROC_ASLR_STATUS" 2115 | "PROC_ASLR_FORCE_ENABLE" 2116 | "PROC_ASLR_FORCE_DISABLE" 2117 | "PROC_ASLR_NOFORCE" 2118 | "PROC_ASLR_ACTIVE" 2119 if Some(11) == freebsd_ver => 2120 { 2121 true 2122 } 2123 2124 // Added in FreeBSD 12.1 (r345228) 2125 "PROC_PROCCTL_MD_MIN" if Some(11) == freebsd_ver => true, 2126 2127 // Added in FreeBSD 13.0 (r349609) 2128 "PROC_PROTMAX_CTL" 2129 | "PROC_PROTMAX_STATUS" 2130 | "PROC_PROTMAX_FORCE_ENABLE" 2131 | "PROC_PROTMAX_FORCE_DISABLE" 2132 | "PROC_PROTMAX_NOFORCE" 2133 | "PROC_PROTMAX_ACTIVE" 2134 if Some(13) > freebsd_ver => 2135 { 2136 true 2137 } 2138 2139 // Added in FreeBSD 12.1 2140 "PT_GET_SC_RET" | "PT_GET_SC_ARGS" if Some(11) == freebsd_ver => true, 2141 2142 // Added in in FreeBSD 13.0 (r367776 and r367287) 2143 "SCM_CREDS2" | "LOCAL_CREDS_PERSISTENT" if Some(13) > freebsd_ver => true, 2144 2145 // Added in FreeBSD 14 2146 "SPACECTL_DEALLOC" if Some(14) > freebsd_ver => true, 2147 2148 "VM_TOTAL" if Some(11) == freebsd_ver => true, 2149 2150 // Added in FreeBSD 13. 2151 "KERN_PROC_SIGFASTBLK" 2152 | "USER_LOCALBASE" 2153 | "TDP_SIGFASTBLOCK" 2154 | "TDP_UIOHELD" 2155 | "TDP_SIGFASTPENDING" 2156 | "TDP2_COMPAT32RB" 2157 | "P2_PROTMAX_ENABLE" 2158 | "P2_PROTMAX_DISABLE" 2159 | "CTLFLAG_NEEDGIANT" 2160 | "CTL_SYSCTL_NEXTNOSKIP" 2161 if Some(13) > freebsd_ver => 2162 { 2163 true 2164 } 2165 // Added in FreeBSD 12. 2166 "KERN_MAXPHYS" 2167 | "KVME_FLAG_USER_WIRED" 2168 | "TDP2_SBPAGES" 2169 | "P2_ASLR_ENABLE" 2170 | "P2_ASLR_DISABLE" 2171 | "P2_ASLR_IGNSTART" 2172 | "P_TREE_GRPEXITED" 2173 if Some(12) > freebsd_ver => 2174 { 2175 true 2176 } 2177 2178 // Added in freebsd 14. 2179 "IFCAP_MEXTPG" if Some(14) > freebsd_ver => true, 2180 // Added in freebsd 13. 2181 "IFF_KNOWSEPOCH" | "IFCAP_TXTLS4" | "IFCAP_TXTLS6" | "IFCAP_VXLAN_HWCSUM" 2182 | "IFCAP_VXLAN_HWTSO" | "IFCAP_TXTLS_RTLMT" | "IFCAP_TXTLS" 2183 if Some(13) > freebsd_ver => 2184 { 2185 true 2186 } 2187 // Added in freebsd 12. 2188 "IFF_NOGROUP" | "IFCAP_TXRTLMT" | "IFCAP_HWRXTSTMP" if Some(12) > freebsd_ver => true, 2189 // Added in FreeBSD 13. 2190 "PS_FST_TYPE_EVENTFD" if Some(13) > freebsd_ver => true, 2191 2192 // Added in FreeBSD 14. 2193 "MNT_RECURSE" | "MNT_DEFERRED" if Some(14) > freebsd_ver => true, 2194 2195 // Added in FreeBSD 13. 2196 "MNT_EXTLS" | "MNT_EXTLSCERT" | "MNT_EXTLSCERTUSER" | "MNT_NOCOVER" 2197 | "MNT_EMPTYDIR" 2198 if Some(13) > freebsd_ver => 2199 { 2200 true 2201 } 2202 2203 // Added in FreeBSD 12. 2204 "MNT_UNTRUSTED" | "MNT_VERIFIED" if Some(12) > freebsd_ver => true, 2205 2206 // Added in FreeBSD 14. 2207 "PT_COREDUMP" | "PC_ALL" | "PC_COMPRESS" | "PT_GETREGSET" | "PT_SETREGSET" 2208 if Some(14) > freebsd_ver => 2209 { 2210 true 2211 } 2212 2213 // Added in FreeBSD 14. 2214 "F_KINFO" => true, // FIXME: depends how frequent freebsd 14 is updated on CI, this addition went this week only. 2215 "SHM_RENAME_NOREPLACE" 2216 | "SHM_RENAME_EXCHANGE" 2217 | "SHM_LARGEPAGE_ALLOC_DEFAULT" 2218 | "SHM_LARGEPAGE_ALLOC_NOWAIT" 2219 | "SHM_LARGEPAGE_ALLOC_HARD" 2220 | "MFD_CLOEXEC" 2221 | "MFD_ALLOW_SEALING" 2222 | "MFD_HUGETLB" 2223 if Some(13) > freebsd_ver => 2224 { 2225 true 2226 } 2227 2228 // Those were introduced in FreeBSD 12. 2229 "TCP_FUNCTION_NAME_LEN_MAX" | "TCP_FASTOPEN_PSK_LEN" if Some(11) == freebsd_ver => true, 2230 2231 // Flags introduced in FreeBSD 14. 2232 "TCP_MAXUNACKTIME" 2233 | "TCP_MAXPEAKRATE" 2234 | "TCP_IDLE_REDUCE" 2235 | "TCP_REMOTE_UDP_ENCAPS_PORT" 2236 | "TCP_DELACK" 2237 | "TCP_FIN_IS_RST" 2238 | "TCP_LOG_LIMIT" 2239 | "TCP_SHARED_CWND_ALLOWED" 2240 | "TCP_PROC_ACCOUNTING" 2241 | "TCP_USE_CMP_ACKS" 2242 | "TCP_PERF_INFO" 2243 | "TCP_LRD" 2244 if Some(14) > freebsd_ver => 2245 { 2246 true 2247 } 2248 2249 _ => false, 2250 } 2251 }); 2252 2253 cfg.skip_type(move |ty| { 2254 match ty { 2255 // the struct "__kvm" is quite tricky to bind so since we only use a pointer to it 2256 // for now, it doesn't matter too much... 2257 "kvm_t" => true, 2258 2259 _ => false, 2260 } 2261 }); 2262 2263 cfg.skip_struct(move |ty| { 2264 if ty.starts_with("__c_anonymous_") { 2265 return true; 2266 } 2267 match ty { 2268 // `mmsghdr` is not available in FreeBSD 10 2269 "mmsghdr" if Some(10) == freebsd_ver => true, 2270 2271 // `max_align_t` is not available in FreeBSD 10 2272 "max_align_t" if Some(10) == freebsd_ver => true, 2273 2274 // `procstat` is a private struct 2275 "procstat" => true, 2276 2277 // `ptrace_sc_ret` is not available in FreeBSD 11 2278 "ptrace_sc_ret" if Some(11) == freebsd_ver => true, 2279 2280 // `spacectl_range` was introduced in FreeBSD 14 2281 "spacectl_range" if Some(14) > freebsd_ver => true, 2282 2283 // obsolete version 2284 "vmtotal" if Some(11) == freebsd_ver => true, 2285 2286 // `ptrace_coredump` introduced in FreeBSD 14. 2287 "ptrace_coredump" if Some(14) > freebsd_ver => true, 2288 2289 // `sockcred2` is not available in FreeBSD 12. 2290 "sockcred2" if Some(13) > freebsd_ver => true, 2291 2292 // `tcp_fastopen` introduced in FreeBSD 12. 2293 "tcp_fastopen" if Some(11) == freebsd_ver => true, 2294 // `tcp_function_set` introduced in FreeBSD 12. 2295 "tcp_function_set" if Some(11) == freebsd_ver => true, 2296 2297 _ => false, 2298 } 2299 }); 2300 2301 cfg.skip_fn(move |name| { 2302 // skip those that are manually verified 2303 match name { 2304 // FIXME: https://github.com/rust-lang/libc/issues/1272 2305 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2306 2307 // These functions were added in FreeBSD 11: 2308 "fdatasync" | "mq_getfd_np" | "sendmmsg" | "recvmmsg" if Some(10) == freebsd_ver => { 2309 true 2310 } 2311 2312 // This function changed its return type from `int` in FreeBSD10 to 2313 // `ssize_t` in FreeBSD11: 2314 "aio_waitcomplete" if Some(10) == freebsd_ver => true, 2315 2316 // `fspacectl` was introduced in FreeBSD 14 2317 "fspacectl" if Some(14) > freebsd_ver => true, 2318 2319 // The `uname` function in the `utsname.h` FreeBSD header is a C 2320 // inline function (has no symbol) that calls the `__xuname` symbol. 2321 // Therefore the function pointer comparison does not make sense for it. 2322 "uname" => true, 2323 2324 // FIXME: Our API is unsound. The Rust API allows aliasing 2325 // pointers, but the C API requires pointers not to alias. 2326 // We should probably be at least using `&`/`&mut` here, see: 2327 // https://github.com/gnzlbg/ctest/issues/68 2328 "lio_listio" => true, 2329 2330 // Those are introduced in FreeBSD 14. 2331 "sched_getaffinity" | "sched_setaffinity" | "sched_getcpu" 2332 if Some(14) > freebsd_ver => 2333 { 2334 true 2335 } 2336 2337 // This is not available in FreeBSD 12. 2338 "SOCKCRED2SIZE" if Some(13) > freebsd_ver => true, 2339 2340 // Those are not available in FreeBSD 12. 2341 "memfd_create" | "shm_create_largepage" | "shm_rename" if Some(13) > freebsd_ver => { 2342 true 2343 } 2344 2345 // Those were introduced in FreeBSD 12. 2346 "flopen" | "flopenat" if Some(12) > freebsd_ver => true, 2347 2348 // Added in FreeBSD 13. 2349 "getlocalbase" if Some(13) > freebsd_ver => true, 2350 2351 _ => false, 2352 } 2353 }); 2354 2355 cfg.skip_signededness(move |c| { 2356 match c { 2357 // FIXME: has a different sign in FreeBSD10 2358 "blksize_t" if Some(10) == freebsd_ver => true, 2359 _ => false, 2360 } 2361 }); 2362 2363 cfg.volatile_item(|i| { 2364 use ctest::VolatileItemKind::*; 2365 match i { 2366 // aio_buf is a volatile void** but since we cannot express that in 2367 // Rust types, we have to explicitly tell the checker about it here: 2368 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 2369 _ => false, 2370 } 2371 }); 2372 2373 cfg.skip_field(move |struct_, field| { 2374 match (struct_, field) { 2375 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 2376 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 2377 ("sigaction", "sa_sigaction") => true, 2378 2379 // FIXME: in FreeBSD10 this field has type `char*` instead of 2380 // `void*`: 2381 ("stack_t", "ss_sp") if Some(10) == freebsd_ver => true, 2382 2383 // conflicting with `p_type` macro from <resolve.h>. 2384 ("Elf32_Phdr", "p_type") => true, 2385 ("Elf64_Phdr", "p_type") => true, 2386 2387 // not available until FreeBSD 12, and is an anonymous union there. 2388 ("xucred", "cr_pid__c_anonymous_union") => true, 2389 2390 // m_owner field is a volatile __lwpid_t 2391 ("umutex", "m_owner") => true, 2392 // c_has_waiters field is a volatile int32_t 2393 ("ucond", "c_has_waiters") => true, 2394 // is PATH_MAX long but tests can't accept multi array as equivalent. 2395 ("kinfo_vmentry", "kve_path") => true, 2396 2397 // a_un field is a union 2398 ("Elf32_Auxinfo", "a_un") => true, 2399 ("Elf64_Auxinfo", "a_un") => true, 2400 2401 // union fields 2402 ("if_data", "__ifi_epoch") => true, 2403 ("if_data", "__ifi_lastchange") => true, 2404 ("ifreq", "ifr_ifru") => true, 2405 ("ifconf", "ifc_ifcu") => true, 2406 2407 // anonymous struct 2408 ("devstat", "dev_links") => true, 2409 2410 // FIXME: structs too complicated to bind for now... 2411 ("kinfo_proc", "ki_paddr") => true, 2412 ("kinfo_proc", "ki_addr") => true, 2413 ("kinfo_proc", "ki_tracep") => true, 2414 ("kinfo_proc", "ki_textvp") => true, 2415 ("kinfo_proc", "ki_fd") => true, 2416 ("kinfo_proc", "ki_vmspace") => true, 2417 ("kinfo_proc", "ki_pcb") => true, 2418 ("kinfo_proc", "ki_tdaddr") => true, 2419 ("kinfo_proc", "ki_pd") => true, 2420 2421 // Anonymous type. 2422 ("filestat", "next") => true, 2423 2424 // We ignore this field because we needed to use a hack in order to make rust 1.19 2425 // happy... 2426 ("kinfo_proc", "ki_sparestrings") => true, 2427 2428 // `__sem_base` is a private struct field 2429 ("semid_ds", "__sem_base") => true, 2430 2431 // `snap_time` is a `long double`, but it's a nightmare to bind correctly in rust 2432 // for the moment, so it's a best effort thing... 2433 ("statinfo", "snap_time") => true, 2434 2435 _ => false, 2436 } 2437 }); 2438 2439 cfg.generate("../src/lib.rs", "main.rs"); 2440 } 2441 2442 fn test_emscripten(target: &str) { 2443 assert!(target.contains("emscripten")); 2444 2445 let mut cfg = ctest_cfg(); 2446 cfg.define("_GNU_SOURCE", None); // FIXME: ?? 2447 2448 headers! { cfg: 2449 "aio.h", 2450 "ctype.h", 2451 "dirent.h", 2452 "dlfcn.h", 2453 "errno.h", 2454 "fcntl.h", 2455 "glob.h", 2456 "grp.h", 2457 "ifaddrs.h", 2458 "langinfo.h", 2459 "limits.h", 2460 "locale.h", 2461 "malloc.h", 2462 "mntent.h", 2463 "mqueue.h", 2464 "net/ethernet.h", 2465 "net/if.h", 2466 "net/if_arp.h", 2467 "net/route.h", 2468 "netdb.h", 2469 "netinet/in.h", 2470 "netinet/ip.h", 2471 "netinet/tcp.h", 2472 "netinet/udp.h", 2473 "netpacket/packet.h", 2474 "poll.h", 2475 "pthread.h", 2476 "pty.h", 2477 "pwd.h", 2478 "resolv.h", 2479 "sched.h", 2480 "sched.h", 2481 "semaphore.h", 2482 "shadow.h", 2483 "signal.h", 2484 "stddef.h", 2485 "stdint.h", 2486 "stdio.h", 2487 "stdlib.h", 2488 "string.h", 2489 "sys/epoll.h", 2490 "sys/eventfd.h", 2491 "sys/file.h", 2492 "sys/ioctl.h", 2493 "sys/ipc.h", 2494 "sys/mman.h", 2495 "sys/mount.h", 2496 "sys/msg.h", 2497 "sys/personality.h", 2498 "sys/prctl.h", 2499 "sys/ptrace.h", 2500 "sys/quota.h", 2501 "sys/reboot.h", 2502 "sys/resource.h", 2503 "sys/sem.h", 2504 "sys/sendfile.h", 2505 "sys/shm.h", 2506 "sys/signalfd.h", 2507 "sys/socket.h", 2508 "sys/stat.h", 2509 "sys/statvfs.h", 2510 "sys/swap.h", 2511 "sys/syscall.h", 2512 "sys/sysctl.h", 2513 "sys/sysinfo.h", 2514 "sys/time.h", 2515 "sys/timerfd.h", 2516 "sys/times.h", 2517 "sys/types.h", 2518 "sys/uio.h", 2519 "sys/un.h", 2520 "sys/user.h", 2521 "sys/utsname.h", 2522 "sys/vfs.h", 2523 "sys/wait.h", 2524 "sys/xattr.h", 2525 "syslog.h", 2526 "termios.h", 2527 "time.h", 2528 "ucontext.h", 2529 "unistd.h", 2530 "utime.h", 2531 "utmp.h", 2532 "utmpx.h", 2533 "wchar.h", 2534 } 2535 2536 cfg.type_name(move |ty, is_struct, is_union| { 2537 match ty { 2538 // Just pass all these through, no need for a "struct" prefix 2539 "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(), 2540 2541 t if is_union => format!("union {}", t), 2542 2543 t if t.ends_with("_t") => t.to_string(), 2544 2545 // put `struct` in front of all structs:. 2546 t if is_struct => format!("struct {}", t), 2547 2548 t => t.to_string(), 2549 } 2550 }); 2551 2552 cfg.field_name(move |struct_, field| { 2553 match field { 2554 // Our stat *_nsec fields normally don't actually exist but are part 2555 // of a timeval struct 2556 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2557 s.replace("e_nsec", ".tv_nsec") 2558 } 2559 // FIXME: appears that `epoll_event.data` is an union 2560 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 2561 s => s.to_string(), 2562 } 2563 }); 2564 2565 cfg.skip_type(move |ty| { 2566 match ty { 2567 // sighandler_t is crazy across platforms 2568 // FIXME: is this necessary? 2569 "sighandler_t" => true, 2570 2571 _ => false, 2572 } 2573 }); 2574 2575 cfg.skip_struct(move |ty| { 2576 match ty { 2577 // This is actually a union, not a struct 2578 // FIXME: is this necessary? 2579 "sigval" => true, 2580 2581 // FIXME: It was removed in 2582 // emscripten-core/emscripten@953e414 2583 "pthread_mutexattr_t" => true, 2584 2585 // FIXME: Investigate why the test fails. 2586 // Skip for now to unblock CI. 2587 "pthread_condattr_t" => true, 2588 2589 _ => false, 2590 } 2591 }); 2592 2593 cfg.skip_fn(move |name| { 2594 match name { 2595 // FIXME: https://github.com/rust-lang/libc/issues/1272 2596 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2597 2598 // FIXME: Investigate why CI is missing it. 2599 "clearenv" => true, 2600 2601 _ => false, 2602 } 2603 }); 2604 2605 cfg.skip_const(move |name| { 2606 match name { 2607 // FIXME: deprecated - SIGNUNUSED was removed in glibc 2.26 2608 // users should use SIGSYS instead 2609 "SIGUNUSED" => true, 2610 2611 // FIXME: emscripten uses different constants to constructs these 2612 n if n.contains("__SIZEOF_PTHREAD") => true, 2613 2614 // FIXME: `SYS_gettid` was removed in 2615 // emscripten-core/emscripten@6d6474e 2616 "SYS_gettid" => true, 2617 2618 _ => false, 2619 } 2620 }); 2621 2622 cfg.skip_field_type(move |struct_, field| { 2623 // This is a weird union, don't check the type. 2624 // FIXME: is this necessary? 2625 (struct_ == "ifaddrs" && field == "ifa_ifu") || 2626 // sighandler_t type is super weird 2627 // FIXME: is this necessary? 2628 (struct_ == "sigaction" && field == "sa_sigaction") || 2629 // sigval is actually a union, but we pretend it's a struct 2630 // FIXME: is this necessary? 2631 (struct_ == "sigevent" && field == "sigev_value") || 2632 // aio_buf is "volatile void*" and Rust doesn't understand volatile 2633 // FIXME: is this necessary? 2634 (struct_ == "aiocb" && field == "aio_buf") 2635 }); 2636 2637 cfg.skip_field(move |struct_, field| { 2638 // this is actually a union on linux, so we can't represent it well and 2639 // just insert some padding. 2640 // FIXME: is this necessary? 2641 (struct_ == "siginfo_t" && field == "_pad") || 2642 // musl names this __dummy1 but it's still there 2643 // FIXME: is this necessary? 2644 (struct_ == "glob_t" && field == "gl_flags") || 2645 // musl seems to define this as an *anonymous* bitfield 2646 // FIXME: is this necessary? 2647 (struct_ == "statvfs" && field == "__f_unused") || 2648 // sigev_notify_thread_id is actually part of a sigev_un union 2649 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 2650 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet. 2651 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 2652 field == "_pad2" || 2653 field == "ssi_syscall" || 2654 field == "ssi_call_addr" || 2655 field == "ssi_arch")) 2656 }); 2657 2658 // FIXME: test linux like 2659 cfg.generate("../src/lib.rs", "main.rs"); 2660 } 2661 2662 fn test_vxworks(target: &str) { 2663 assert!(target.contains("vxworks")); 2664 2665 let mut cfg = ctest::TestGenerator::new(); 2666 headers! { cfg: 2667 "vxWorks.h", 2668 "yvals.h", 2669 "nfs/nfsCommon.h", 2670 "rtpLibCommon.h", 2671 "randomNumGen.h", 2672 "taskLib.h", 2673 "sysLib.h", 2674 "ioLib.h", 2675 "inetLib.h", 2676 "socket.h", 2677 "errnoLib.h", 2678 "ctype.h", 2679 "dirent.h", 2680 "dlfcn.h", 2681 "elf.h", 2682 "fcntl.h", 2683 "grp.h", 2684 "sys/poll.h", 2685 "ifaddrs.h", 2686 "langinfo.h", 2687 "limits.h", 2688 "link.h", 2689 "locale.h", 2690 "sys/stat.h", 2691 "netdb.h", 2692 "pthread.h", 2693 "pwd.h", 2694 "sched.h", 2695 "semaphore.h", 2696 "signal.h", 2697 "stddef.h", 2698 "stdint.h", 2699 "stdio.h", 2700 "stdlib.h", 2701 "string.h", 2702 "sys/file.h", 2703 "sys/ioctl.h", 2704 "sys/socket.h", 2705 "sys/time.h", 2706 "sys/times.h", 2707 "sys/types.h", 2708 "sys/uio.h", 2709 "sys/un.h", 2710 "sys/utsname.h", 2711 "sys/wait.h", 2712 "netinet/tcp.h", 2713 "syslog.h", 2714 "termios.h", 2715 "time.h", 2716 "ucontext.h", 2717 "unistd.h", 2718 "utime.h", 2719 "wchar.h", 2720 "errno.h", 2721 "sys/mman.h", 2722 "pathLib.h", 2723 "mqueue.h", 2724 } 2725 // FIXME 2726 cfg.skip_const(move |name| match name { 2727 // sighandler_t weirdness 2728 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" 2729 // This is not defined in vxWorks 2730 | "RTLD_DEFAULT" => true, 2731 _ => false, 2732 }); 2733 // FIXME 2734 cfg.skip_type(move |ty| match ty { 2735 "stat64" | "sighandler_t" | "off64_t" => true, 2736 _ => false, 2737 }); 2738 2739 cfg.skip_field_type(move |struct_, field| match (struct_, field) { 2740 ("siginfo_t", "si_value") | ("stat", "st_size") | ("sigaction", "sa_u") => true, 2741 _ => false, 2742 }); 2743 2744 cfg.skip_roundtrip(move |s| match s { 2745 _ => false, 2746 }); 2747 2748 cfg.type_name(move |ty, is_struct, is_union| match ty { 2749 "DIR" | "FILE" | "Dl_info" | "RTP_DESC" => ty.to_string(), 2750 t if is_union => format!("union {}", t), 2751 t if t.ends_with("_t") => t.to_string(), 2752 t if is_struct => format!("struct {}", t), 2753 t => t.to_string(), 2754 }); 2755 2756 // FIXME 2757 cfg.skip_fn(move |name| match name { 2758 // sigval 2759 "sigqueue" | "_sigqueue" 2760 // sighandler_t 2761 | "signal" 2762 // not used in static linking by default 2763 | "dlerror" => true, 2764 _ => false, 2765 }); 2766 2767 cfg.generate("../src/lib.rs", "main.rs"); 2768 } 2769 2770 fn test_linux(target: &str) { 2771 assert!(target.contains("linux")); 2772 2773 // target_env 2774 let gnu = target.contains("gnu"); 2775 let musl = target.contains("musl"); 2776 let uclibc = target.contains("uclibc"); 2777 2778 match (gnu, musl, uclibc) { 2779 (true, false, false) => (), 2780 (false, true, false) => (), 2781 (false, false, true) => (), 2782 (_, _, _) => panic!( 2783 "linux target lib is gnu: {}, musl: {}, uclibc: {}", 2784 gnu, musl, uclibc 2785 ), 2786 } 2787 2788 let arm = target.contains("arm"); 2789 let i686 = target.contains("i686"); 2790 let mips = target.contains("mips"); 2791 let mips32 = mips && !target.contains("64"); 2792 let mips64 = mips && target.contains("64"); 2793 let ppc64 = target.contains("powerpc64"); 2794 let s390x = target.contains("s390x"); 2795 let sparc64 = target.contains("sparc64"); 2796 let x32 = target.contains("x32"); 2797 let x86_32 = target.contains("i686"); 2798 let x86_64 = target.contains("x86_64"); 2799 let aarch64_musl = target.contains("aarch64") && musl; 2800 let gnuabihf = target.contains("gnueabihf"); 2801 let x86_64_gnux32 = target.contains("gnux32") && x86_64; 2802 let riscv64 = target.contains("riscv64"); 2803 let uclibc = target.contains("uclibc"); 2804 2805 let mut cfg = ctest_cfg(); 2806 cfg.define("_GNU_SOURCE", None); 2807 // This macro re-deifnes fscanf,scanf,sscanf to link to the symbols that are 2808 // deprecated since glibc >= 2.29. This allows Rust binaries to link against 2809 // glibc versions older than 2.29. 2810 cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None); 2811 2812 headers! { cfg: 2813 "ctype.h", 2814 "dirent.h", 2815 "dlfcn.h", 2816 "elf.h", 2817 "fcntl.h", 2818 "glob.h", 2819 "grp.h", 2820 "iconv.h", 2821 "ifaddrs.h", 2822 "langinfo.h", 2823 "limits.h", 2824 "link.h", 2825 "locale.h", 2826 "malloc.h", 2827 "mntent.h", 2828 "mqueue.h", 2829 "net/ethernet.h", 2830 "net/if.h", 2831 "net/if_arp.h", 2832 "net/route.h", 2833 "netdb.h", 2834 "netinet/in.h", 2835 "netinet/ip.h", 2836 "netinet/tcp.h", 2837 "netinet/udp.h", 2838 "netpacket/packet.h", 2839 "poll.h", 2840 "pthread.h", 2841 "pty.h", 2842 "pwd.h", 2843 "regex.h", 2844 "resolv.h", 2845 "sched.h", 2846 "semaphore.h", 2847 "shadow.h", 2848 "signal.h", 2849 "spawn.h", 2850 "stddef.h", 2851 "stdint.h", 2852 "stdio.h", 2853 "stdlib.h", 2854 "string.h", 2855 "sys/epoll.h", 2856 "sys/eventfd.h", 2857 "sys/file.h", 2858 "sys/fsuid.h", 2859 "sys/inotify.h", 2860 "sys/ioctl.h", 2861 "sys/ipc.h", 2862 "sys/mman.h", 2863 "sys/mount.h", 2864 "sys/msg.h", 2865 "sys/personality.h", 2866 "sys/prctl.h", 2867 "sys/ptrace.h", 2868 "sys/quota.h", 2869 "sys/random.h", 2870 "sys/reboot.h", 2871 "sys/resource.h", 2872 "sys/sem.h", 2873 "sys/sendfile.h", 2874 "sys/shm.h", 2875 "sys/signalfd.h", 2876 "sys/socket.h", 2877 "sys/stat.h", 2878 "sys/statvfs.h", 2879 "sys/swap.h", 2880 "sys/syscall.h", 2881 "sys/time.h", 2882 "sys/timerfd.h", 2883 "sys/times.h", 2884 "sys/timex.h", 2885 "sys/types.h", 2886 "sys/uio.h", 2887 "sys/un.h", 2888 "sys/user.h", 2889 "sys/utsname.h", 2890 "sys/vfs.h", 2891 "sys/wait.h", 2892 "syslog.h", 2893 "termios.h", 2894 "time.h", 2895 "ucontext.h", 2896 "unistd.h", 2897 "utime.h", 2898 "utmp.h", 2899 "utmpx.h", 2900 "wchar.h", 2901 "errno.h", 2902 // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit 2903 // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162 2904 // Also unavailable on gnuabihf with glibc 2.30. 2905 // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6b33f373c7b9199e00ba5fbafd94ac9bfb4337b1 2906 [(x86_64 || x86_32 || arm) && !gnuabihf]: "sys/io.h", 2907 // `sys/reg.h` is only available on x86 and x86_64 2908 [x86_64 || x86_32]: "sys/reg.h", 2909 // sysctl system call is deprecated and not available on musl 2910 // It is also unsupported in x32, deprecated since glibc 2.30: 2911 [!(x32 || musl || gnu)]: "sys/sysctl.h", 2912 // <execinfo.h> is not supported by musl: 2913 // https://www.openwall.com/lists/musl/2015/04/09/3 2914 // <execinfo.h> is not present on uclibc. 2915 [!(musl || uclibc)]: "execinfo.h", 2916 } 2917 2918 // Include linux headers at the end: 2919 headers! { 2920 cfg: 2921 "asm/mman.h", 2922 "linux/can.h", 2923 "linux/can/raw.h", 2924 "linux/dccp.h", 2925 "linux/errqueue.h", 2926 "linux/falloc.h", 2927 "linux/filter.h", 2928 "linux/fs.h", 2929 "linux/futex.h", 2930 "linux/genetlink.h", 2931 "linux/if.h", 2932 "linux/if_addr.h", 2933 "linux/if_alg.h", 2934 "linux/if_ether.h", 2935 "linux/if_tun.h", 2936 "linux/input.h", 2937 "linux/keyctl.h", 2938 "linux/magic.h", 2939 "linux/memfd.h", 2940 "linux/mempolicy.h", 2941 "linux/mman.h", 2942 "linux/module.h", 2943 "linux/net_tstamp.h", 2944 "linux/netfilter/nfnetlink.h", 2945 "linux/netfilter/nfnetlink_log.h", 2946 "linux/netfilter/nfnetlink_queue.h", 2947 "linux/netfilter/nf_tables.h", 2948 "linux/netfilter_ipv4.h", 2949 "linux/netfilter_ipv6.h", 2950 "linux/netfilter_ipv6/ip6_tables.h", 2951 "linux/netlink.h", 2952 // FIXME: requires more recent kernel headers: 2953 // "linux/openat2.h", 2954 [!musl]: "linux/ptrace.h", 2955 "linux/quota.h", 2956 "linux/random.h", 2957 "linux/reboot.h", 2958 "linux/rtnetlink.h", 2959 "linux/sched.h", 2960 "linux/seccomp.h", 2961 "linux/sockios.h", 2962 "linux/uinput.h", 2963 "linux/vm_sockets.h", 2964 "linux/wait.h", 2965 "sys/fanotify.h", 2966 // <sys/auxv.h> is not present on uclibc 2967 [!uclibc]: "sys/auxv.h", 2968 } 2969 2970 // note: aio.h must be included before sys/mount.h 2971 headers! { 2972 cfg: 2973 "sys/xattr.h", 2974 "sys/sysinfo.h", 2975 // AIO is not supported by uclibc: 2976 [!uclibc]: "aio.h", 2977 } 2978 2979 cfg.type_name(move |ty, is_struct, is_union| { 2980 match ty { 2981 // Just pass all these through, no need for a "struct" prefix 2982 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 2983 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 2984 | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(), 2985 2986 "Ioctl" if gnu => "unsigned long".to_string(), 2987 "Ioctl" => "int".to_string(), 2988 2989 t if is_union => format!("union {}", t), 2990 2991 t if t.ends_with("_t") => t.to_string(), 2992 2993 // In MUSL `flock64` is a typedef to `flock`. 2994 "flock64" if musl => format!("struct {}", ty), 2995 2996 // put `struct` in front of all structs:. 2997 t if is_struct => format!("struct {}", t), 2998 2999 t => t.to_string(), 3000 } 3001 }); 3002 3003 cfg.field_name(move |struct_, field| { 3004 match field { 3005 // Our stat *_nsec fields normally don't actually exist but are part 3006 // of a timeval struct 3007 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 3008 s.replace("e_nsec", ".tv_nsec") 3009 } 3010 // FIXME: epoll_event.data is actually a union in C, but in Rust 3011 // it is only a u64 because we only expose one field 3012 // http://man7.org/linux/man-pages/man2/epoll_wait.2.html 3013 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 3014 // The following structs have a field called `type` in C, 3015 // but `type` is a Rust keyword, so these fields are translated 3016 // to `type_` in Rust. 3017 "type_" 3018 if struct_ == "input_event" 3019 || struct_ == "input_mask" 3020 || struct_ == "ff_effect" => 3021 { 3022 "type".to_string() 3023 } 3024 3025 s => s.to_string(), 3026 } 3027 }); 3028 3029 cfg.skip_type(move |ty| { 3030 match ty { 3031 // FIXME: `sighandler_t` type is incorrect, see: 3032 // https://github.com/rust-lang/libc/issues/1359 3033 "sighandler_t" => true, 3034 3035 // These cannot be tested when "resolv.h" is included and are tested 3036 // in the `linux_elf.rs` file. 3037 "Elf64_Phdr" | "Elf32_Phdr" => true, 3038 3039 // This type is private on Linux. It is implemented as a C `enum` 3040 // (`c_uint`) and this clashes with the type of the `rlimit` APIs 3041 // which expect a `c_int` even though both are ABI compatible. 3042 "__rlimit_resource_t" => true, 3043 // on Linux, this is a volatile int 3044 "pthread_spinlock_t" => true, 3045 3046 // For internal use only, to define architecture specific ioctl constants with a libc specific type. 3047 "Ioctl" => true, 3048 3049 _ => false, 3050 } 3051 }); 3052 3053 cfg.skip_struct(move |ty| { 3054 if ty.starts_with("__c_anonymous_") { 3055 return true; 3056 } 3057 // FIXME: musl CI has old headers 3058 if (musl || sparc64) && ty.starts_with("uinput_") { 3059 return true; 3060 } 3061 // FIXME(https://github.com/rust-lang/libc/issues/1558): passing by 3062 // value corrupts the value for reasons not understood. 3063 if (gnu && sparc64) && ty == "ip_mreqn" { 3064 return true; 3065 } 3066 match ty { 3067 // These cannot be tested when "resolv.h" is included and are tested 3068 // in the `linux_elf.rs` file. 3069 "Elf64_Phdr" | "Elf32_Phdr" => true, 3070 3071 // On Linux, the type of `ut_tv` field of `struct utmpx` 3072 // can be an anonymous struct, so an extra struct, 3073 // which is absent in glibc, has to be defined. 3074 "__timeval" => true, 3075 3076 // FIXME: This is actually a union, not a struct 3077 "sigval" => true, 3078 3079 // This type is tested in the `linux_termios.rs` file since there 3080 // are header conflicts when including them with all the other 3081 // structs. 3082 "termios2" => true, 3083 3084 // FIXME: remove once we set minimum supported glibc version. 3085 // ucontext_t added a new field as of glibc 2.28; our struct definition is 3086 // conservative and omits the field, but that means the size doesn't match for newer 3087 // glibcs (see https://github.com/rust-lang/libc/issues/1410) 3088 "ucontext_t" if gnu => true, 3089 3090 // FIXME: Somehow we cannot include headers correctly in glibc 2.30. 3091 // So let's ignore for now and re-visit later. 3092 // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085 3093 "statx" => true, 3094 "statx_timestamp" => true, 3095 3096 // On Linux, the type of `ut_exit` field of struct `utmpx` 3097 // can be an anonymous struct, so an extra struct, 3098 // which is absent in musl, has to be defined. 3099 "__exit_status" if musl => true, 3100 3101 // FIXME: CI's kernel header version is old. 3102 "sockaddr_can" => true, 3103 3104 // Requires glibc 2.33 or newer. 3105 "mallinfo2" => true, 3106 3107 // Might differ between kernel versions 3108 "open_how" => true, 3109 3110 _ => false, 3111 } 3112 }); 3113 3114 cfg.skip_const(move |name| { 3115 if !gnu { 3116 // Skip definitions from the kernel on non-glibc Linux targets. 3117 // They're libc-independent, so we only need to check them on one 3118 // libc. We don't want to break CI if musl or another libc doesn't 3119 // have the definitions yet. (We do still want to check them on 3120 // every glibc target, though, as some of them can vary by 3121 // architecture.) 3122 // 3123 // This is not an exhaustive list of kernel constants, just a list 3124 // of prefixes of all those that have appeared here or that get 3125 // updated regularly and seem likely to cause breakage. 3126 if name.starts_with("AF_") 3127 || name.starts_with("ARPHRD_") 3128 || name.starts_with("EPOLL") 3129 || name.starts_with("F_") 3130 || name.starts_with("FALLOC_FL_") 3131 || name.starts_with("IFLA_") 3132 || name.starts_with("MS_") 3133 || name.starts_with("MSG_") 3134 || name.starts_with("P_") 3135 || name.starts_with("PF_") 3136 || name.starts_with("RLIMIT_") 3137 || name.starts_with("SOL_") 3138 || name.starts_with("STATX_") 3139 || name.starts_with("SW_") 3140 || name.starts_with("SYS_") 3141 || name.starts_with("TCP_") 3142 || name.starts_with("UINPUT_") 3143 || name.starts_with("VMADDR_") 3144 { 3145 return true; 3146 } 3147 } 3148 match name { 3149 // These constants are not available if gnu headers have been included 3150 // and can therefore not be tested here 3151 // 3152 // The IPV6 constants are tested in the `linux_ipv6.rs` tests: 3153 | "IPV6_FLOWINFO" 3154 | "IPV6_FLOWLABEL_MGR" 3155 | "IPV6_FLOWINFO_SEND" 3156 | "IPV6_FLOWINFO_FLOWLABEL" 3157 | "IPV6_FLOWINFO_PRIORITY" 3158 // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: 3159 | "F_CANCELLK" 3160 | "F_ADD_SEALS" 3161 | "F_GET_SEALS" 3162 | "F_SEAL_SEAL" 3163 | "F_SEAL_SHRINK" 3164 | "F_SEAL_GROW" 3165 | "F_SEAL_WRITE" => true, 3166 // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests 3167 // because including `linux/if_arp.h` causes some conflicts: 3168 "ARPHRD_CAN" => true, 3169 3170 // Require Linux kernel 5.1: 3171 "F_SEAL_FUTURE_WRITE" => true, 3172 3173 // FIXME: deprecated: not available in any header 3174 // See: https://github.com/rust-lang/libc/issues/1356 3175 "ENOATTR" => true, 3176 3177 // FIXME: SIGUNUSED was removed in glibc 2.26 3178 // Users should use SIGSYS instead. 3179 "SIGUNUSED" => true, 3180 3181 // FIXME: conflicts with glibc headers and is tested in 3182 // `linux_termios.rs` below: 3183 | "BOTHER" 3184 | "IBSHIFT" 3185 | "TCGETS2" 3186 | "TCSETS2" 3187 | "TCSETSW2" 3188 | "TCSETSF2" => true, 3189 3190 // FIXME: on musl the pthread types are defined a little differently 3191 // - these constants are used by the glibc implementation. 3192 n if musl && n.contains("__SIZEOF_PTHREAD") => true, 3193 3194 // FIXME: It was extended to 4096 since glibc 2.31 (Linux 5.4). 3195 // We should do so after a while. 3196 "SOMAXCONN" if gnu => true, 3197 3198 // deprecated: not available from Linux kernel 5.6: 3199 "VMADDR_CID_RESERVED" => true, 3200 3201 // Require Linux kernel 5.6: 3202 "VMADDR_CID_LOCAL" => true, 3203 3204 // Requires Linux kernel 5.7: 3205 "MREMAP_DONTUNMAP" => true, 3206 3207 // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP: 3208 | "IPPROTO_MAX" 3209 | "IPPROTO_MPTCP" => true, 3210 3211 // FIXME: Not currently available in headers 3212 "P_PIDFD" if mips => true, 3213 "SYS_pidfd_open" if mips => true, 3214 3215 // FIXME: Not currently available in headers on MIPS 3216 // Not yet implemented on sparc64 3217 "SYS_clone3" if mips | sparc64 => true, 3218 3219 // FIXME: these syscalls were added in Linux 5.9 or later 3220 // and are currently not included in the glibc headers. 3221 | "SYS_close_range" 3222 | "SYS_openat2" 3223 | "SYS_pidfd_getfd" 3224 | "SYS_faccessat2" 3225 | "SYS_process_madvise" 3226 | "SYS_epoll_pwait2" 3227 | "SYS_mount_setattr" => true, 3228 3229 // Requires more recent kernel headers: 3230 | "IFLA_PROP_LIST" 3231 | "IFLA_ALT_IFNAME" 3232 | "IFLA_PERM_ADDRESS" 3233 | "IFLA_PROTO_DOWN_REASON" => true, 3234 3235 // FIXME: They require recent kernel header: 3236 | "CAN_J1939" 3237 | "CAN_RAW_FILTER_MAX" 3238 | "CAN_NPROTO" => true, 3239 3240 // FIXME: Requires recent kernel headers (5.8): 3241 "STATX_MNT_ID" => true, 3242 3243 // FIXME: requires more recent kernel headers on CI 3244 | "UINPUT_VERSION" 3245 | "SW_MAX" 3246 | "SW_CNT" 3247 if mips || ppc64 || riscv64 || sparc64 => true, 3248 3249 // FIXME: Requires more recent kernel headers (5.9 / 5.11): 3250 | "CLOSE_RANGE_UNSHARE" 3251 | "CLOSE_RANGE_CLOEXEC" => true, 3252 3253 // FIXME: requires more recent kernel headers: 3254 | "RESOLVE_BENEATH" 3255 | "RESOLVE_CACHED" 3256 | "RESOLVE_IN_ROOT" 3257 | "RESOLVE_NO_MAGICLINKS" 3258 | "RESOLVE_NO_SYMLINKS" 3259 | "RESOLVE_NO_XDEV" => true, 3260 3261 // FIXME: Not currently available in headers on ARM, MIPS and musl. 3262 "NETLINK_GET_STRICT_CHK" if arm || mips || musl => true, 3263 3264 // kernel constants not available in uclibc 1.0.34 3265 | "EXTPROC" 3266 | "FAN_MARK_FILESYSTEM" 3267 | "FAN_MARK_INODE" 3268 | "IPPROTO_BEETPH" 3269 | "IPPROTO_MPLS" 3270 | "IPV6_HDRINCL" 3271 | "IPV6_MULTICAST_ALL" 3272 | "IPV6_PMTUDISC_INTERFACE" 3273 | "IPV6_PMTUDISC_OMIT" 3274 | "IPV6_ROUTER_ALERT_ISOLATE" 3275 | "PACKET_MR_UNICAST" 3276 | "RUSAGE_THREAD" 3277 | "SHM_EXEC" 3278 | "UDP_GRO" 3279 | "UDP_SEGMENT" 3280 if uclibc => true, 3281 3282 // headers conflicts with linux/pidfd.h 3283 "PIDFD_NONBLOCK" => true, 3284 3285 // is a private value for kernel usage normally 3286 "FUSE_SUPER_MAGIC" => true, 3287 // linux 5.12 min 3288 "MPOL_F_NUMA_BALANCING" => true, 3289 3290 _ => false, 3291 } 3292 }); 3293 3294 cfg.skip_fn(move |name| { 3295 // skip those that are manually verified 3296 match name { 3297 // FIXME: https://github.com/rust-lang/libc/issues/1272 3298 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 3299 3300 // There are two versions of the sterror_r function, see 3301 // 3302 // https://linux.die.net/man/3/strerror_r 3303 // 3304 // An XSI-compliant version provided if: 3305 // 3306 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) 3307 // && ! _GNU_SOURCE 3308 // 3309 // and a GNU specific version provided if _GNU_SOURCE is defined. 3310 // 3311 // libc provides bindings for the XSI-compliant version, which is 3312 // preferred for portable applications. 3313 // 3314 // We skip the test here since here _GNU_SOURCE is defined, and 3315 // test the XSI version below. 3316 "strerror_r" => true, 3317 3318 // FIXME: Our API is unsound. The Rust API allows aliasing 3319 // pointers, but the C API requires pointers not to alias. 3320 // We should probably be at least using `&`/`&mut` here, see: 3321 // https://github.com/gnzlbg/ctest/issues/68 3322 "lio_listio" if musl => true, 3323 3324 // FIXME: the glibc version used by the Sparc64 build jobs 3325 // which use Debian 10.0 is too old. 3326 "statx" if sparc64 => true, 3327 3328 // FIXME: Deprecated since glibc 2.30. Remove fn once upstream does. 3329 "sysctl" if gnu => true, 3330 3331 // FIXME: It now takes c_void instead of timezone since glibc 2.31. 3332 "gettimeofday" if gnu => true, 3333 3334 // These are all implemented as static inline functions in uclibc, so 3335 // they cannot be linked against. 3336 // If implementations are required, they might need to be implemented 3337 // in this crate. 3338 "posix_spawnattr_init" if uclibc => true, 3339 "posix_spawnattr_destroy" if uclibc => true, 3340 "posix_spawnattr_getsigdefault" if uclibc => true, 3341 "posix_spawnattr_setsigdefault" if uclibc => true, 3342 "posix_spawnattr_getsigmask" if uclibc => true, 3343 "posix_spawnattr_setsigmask" if uclibc => true, 3344 "posix_spawnattr_getflags" if uclibc => true, 3345 "posix_spawnattr_setflags" if uclibc => true, 3346 "posix_spawnattr_getpgroup" if uclibc => true, 3347 "posix_spawnattr_setpgroup" if uclibc => true, 3348 "posix_spawnattr_getschedpolicy" if uclibc => true, 3349 "posix_spawnattr_setschedpolicy" if uclibc => true, 3350 "posix_spawnattr_getschedparam" if uclibc => true, 3351 "posix_spawnattr_setschedparam" if uclibc => true, 3352 "posix_spawn_file_actions_init" if uclibc => true, 3353 "posix_spawn_file_actions_destroy" if uclibc => true, 3354 3355 // uclibc defines the flags type as a uint, but dependent crates 3356 // assume it's a int instead. 3357 "getnameinfo" if uclibc => true, 3358 3359 // FIXME: This needs musl 1.2.2 or later. 3360 "gettid" if musl => true, 3361 3362 // Needs glibc 2.33 or later. 3363 "mallinfo2" => true, 3364 3365 "reallocarray" if musl => true, 3366 3367 // Not defined in uclibc as of 1.0.34 3368 "gettid" if uclibc => true, 3369 3370 _ => false, 3371 } 3372 }); 3373 3374 cfg.skip_field_type(move |struct_, field| { 3375 // This is a weird union, don't check the type. 3376 (struct_ == "ifaddrs" && field == "ifa_ifu") || 3377 // sighandler_t type is super weird 3378 (struct_ == "sigaction" && field == "sa_sigaction") || 3379 // __timeval type is a patch which doesn't exist in glibc 3380 (struct_ == "utmpx" && field == "ut_tv") || 3381 // sigval is actually a union, but we pretend it's a struct 3382 (struct_ == "sigevent" && field == "sigev_value") || 3383 // this one is an anonymous union 3384 (struct_ == "ff_effect" && field == "u") || 3385 // `__exit_status` type is a patch which is absent in musl 3386 (struct_ == "utmpx" && field == "ut_exit" && musl) || 3387 // `can_addr` is an anonymous union 3388 (struct_ == "sockaddr_can" && field == "can_addr") 3389 }); 3390 3391 cfg.volatile_item(|i| { 3392 use ctest::VolatileItemKind::*; 3393 match i { 3394 // aio_buf is a volatile void** but since we cannot express that in 3395 // Rust types, we have to explicitly tell the checker about it here: 3396 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 3397 _ => false, 3398 } 3399 }); 3400 3401 cfg.skip_field(move |struct_, field| { 3402 // this is actually a union on linux, so we can't represent it well and 3403 // just insert some padding. 3404 (struct_ == "siginfo_t" && field == "_pad") || 3405 // musl names this __dummy1 but it's still there 3406 (musl && struct_ == "glob_t" && field == "gl_flags") || 3407 // musl seems to define this as an *anonymous* bitfield 3408 (musl && struct_ == "statvfs" && field == "__f_unused") || 3409 // sigev_notify_thread_id is actually part of a sigev_un union 3410 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 3411 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release 3412 // has them yet. 3413 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 3414 field == "_pad2" || 3415 field == "ssi_syscall" || 3416 field == "ssi_call_addr" || 3417 field == "ssi_arch")) || 3418 // FIXME: After musl 1.1.24, it have only one field `sched_priority`, 3419 // while other fields become reserved. 3420 (struct_ == "sched_param" && [ 3421 "sched_ss_low_priority", 3422 "sched_ss_repl_period", 3423 "sched_ss_init_budget", 3424 "sched_ss_max_repl", 3425 ].contains(&field) && musl) || 3426 // FIXME: After musl 1.1.24, the type becomes `int` instead of `unsigned short`. 3427 (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) || 3428 // glibc uses unnamed fields here and Rust doesn't support that yet 3429 (struct_ == "timex" && field.starts_with("__unused")) || 3430 // FIXME: It now takes mode_t since glibc 2.31 on some targets. 3431 (struct_ == "ipc_perm" && field == "mode" 3432 && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32) 3433 ) || 3434 // the `u` field is in fact an anonymous union 3435 (gnu && struct_ == "ptrace_syscall_info" && (field == "u" || field == "pad")) 3436 }); 3437 3438 cfg.skip_roundtrip(move |s| match s { 3439 // FIXME: 3440 "utsname" if mips32 || mips64 => true, 3441 // FIXME: 3442 "mcontext_t" if s390x => true, 3443 // FIXME: This is actually a union. 3444 "fpreg_t" if s390x => true, 3445 3446 "sockaddr_un" | "sembuf" | "ff_constant_effect" if mips32 && (gnu || musl) => true, 3447 "ipv6_mreq" 3448 | "ip_mreq_source" 3449 | "sockaddr_in6" 3450 | "sockaddr_ll" 3451 | "in_pktinfo" 3452 | "arpreq" 3453 | "arpreq_old" 3454 | "sockaddr_un" 3455 | "ff_constant_effect" 3456 | "ff_ramp_effect" 3457 | "ff_condition_effect" 3458 | "Elf32_Ehdr" 3459 | "Elf32_Chdr" 3460 | "ucred" 3461 | "in6_pktinfo" 3462 | "sockaddr_nl" 3463 | "termios" 3464 | "nlmsgerr" 3465 if (mips64 || sparc64) && gnu => 3466 { 3467 true 3468 } 3469 3470 // FIXME: the call ABI of max_align_t is incorrect on these platforms: 3471 "max_align_t" if i686 || mips64 || ppc64 => true, 3472 3473 _ => false, 3474 }); 3475 3476 cfg.generate("../src/lib.rs", "main.rs"); 3477 3478 test_linux_like_apis(target); 3479 } 3480 3481 // This function tests APIs that are incompatible to test when other APIs 3482 // are included (e.g. because including both sets of headers clashes) 3483 fn test_linux_like_apis(target: &str) { 3484 let gnu = target.contains("gnu"); 3485 let musl = target.contains("musl"); 3486 let linux = target.contains("linux"); 3487 let emscripten = target.contains("emscripten"); 3488 let android = target.contains("android"); 3489 assert!(linux || android || emscripten); 3490 3491 if linux || android || emscripten { 3492 // test strerror_r from the `string.h` header 3493 let mut cfg = ctest_cfg(); 3494 cfg.skip_type(|_| true).skip_static(|_| true); 3495 3496 headers! { cfg: "string.h" } 3497 cfg.skip_fn(|f| match f { 3498 "strerror_r" => false, 3499 _ => true, 3500 }) 3501 .skip_const(|_| true) 3502 .skip_struct(|_| true); 3503 cfg.generate("../src/lib.rs", "linux_strerror_r.rs"); 3504 } 3505 3506 if linux || android || emscripten { 3507 // test fcntl - see: 3508 // http://man7.org/linux/man-pages/man2/fcntl.2.html 3509 let mut cfg = ctest_cfg(); 3510 3511 if musl { 3512 cfg.header("fcntl.h"); 3513 } else { 3514 cfg.header("linux/fcntl.h"); 3515 } 3516 3517 cfg.skip_type(|_| true) 3518 .skip_static(|_| true) 3519 .skip_struct(|_| true) 3520 .skip_fn(|_| true) 3521 .skip_const(move |name| match name { 3522 // test fcntl constants: 3523 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" 3524 | "F_SEAL_GROW" | "F_SEAL_WRITE" => false, 3525 _ => true, 3526 }) 3527 .type_name(move |ty, is_struct, is_union| match ty { 3528 t if is_struct => format!("struct {}", t), 3529 t if is_union => format!("union {}", t), 3530 t => t.to_string(), 3531 }); 3532 3533 cfg.generate("../src/lib.rs", "linux_fcntl.rs"); 3534 } 3535 3536 if linux || android { 3537 // test termios 3538 let mut cfg = ctest_cfg(); 3539 cfg.header("asm/termbits.h"); 3540 cfg.header("linux/termios.h"); 3541 cfg.skip_type(|_| true) 3542 .skip_static(|_| true) 3543 .skip_fn(|_| true) 3544 .skip_const(|c| match c { 3545 "BOTHER" | "IBSHIFT" => false, 3546 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => false, 3547 _ => true, 3548 }) 3549 .skip_struct(|s| s != "termios2") 3550 .type_name(move |ty, is_struct, is_union| match ty { 3551 "Ioctl" if gnu => "unsigned long".to_string(), 3552 "Ioctl" => "int".to_string(), 3553 t if is_struct => format!("struct {}", t), 3554 t if is_union => format!("union {}", t), 3555 t => t.to_string(), 3556 }); 3557 cfg.generate("../src/lib.rs", "linux_termios.rs"); 3558 } 3559 3560 if linux || android { 3561 // test IPV6_ constants: 3562 let mut cfg = ctest_cfg(); 3563 headers! { 3564 cfg: 3565 "linux/in6.h" 3566 } 3567 cfg.skip_type(|_| true) 3568 .skip_static(|_| true) 3569 .skip_fn(|_| true) 3570 .skip_const(|_| true) 3571 .skip_struct(|_| true) 3572 .skip_const(move |name| match name { 3573 "IPV6_FLOWINFO" 3574 | "IPV6_FLOWLABEL_MGR" 3575 | "IPV6_FLOWINFO_SEND" 3576 | "IPV6_FLOWINFO_FLOWLABEL" 3577 | "IPV6_FLOWINFO_PRIORITY" => false, 3578 _ => true, 3579 }) 3580 .type_name(move |ty, is_struct, is_union| match ty { 3581 t if is_struct => format!("struct {}", t), 3582 t if is_union => format!("union {}", t), 3583 t => t.to_string(), 3584 }); 3585 cfg.generate("../src/lib.rs", "linux_ipv6.rs"); 3586 } 3587 3588 if linux || android { 3589 // Test Elf64_Phdr and Elf32_Phdr 3590 // These types have a field called `p_type`, but including 3591 // "resolve.h" defines a `p_type` macro that expands to `__p_type` 3592 // making the tests for these fails when both are included. 3593 let mut cfg = ctest_cfg(); 3594 cfg.header("elf.h"); 3595 cfg.skip_fn(|_| true) 3596 .skip_static(|_| true) 3597 .skip_const(|_| true) 3598 .type_name(move |ty, _is_struct, _is_union| ty.to_string()) 3599 .skip_struct(move |ty| match ty { 3600 "Elf64_Phdr" | "Elf32_Phdr" => false, 3601 _ => true, 3602 }) 3603 .skip_type(move |ty| match ty { 3604 "Elf64_Phdr" | "Elf32_Phdr" => false, 3605 _ => true, 3606 }); 3607 cfg.generate("../src/lib.rs", "linux_elf.rs"); 3608 } 3609 3610 if linux || android { 3611 // Test `ARPHRD_CAN`. 3612 let mut cfg = ctest_cfg(); 3613 cfg.header("linux/if_arp.h"); 3614 cfg.skip_fn(|_| true) 3615 .skip_static(|_| true) 3616 .skip_const(move |name| match name { 3617 "ARPHRD_CAN" => false, 3618 _ => true, 3619 }) 3620 .skip_struct(|_| true) 3621 .skip_type(|_| true); 3622 cfg.generate("../src/lib.rs", "linux_if_arp.rs"); 3623 } 3624 } 3625 3626 fn which_freebsd() -> Option<i32> { 3627 let output = std::process::Command::new("freebsd-version") 3628 .output() 3629 .ok()?; 3630 if !output.status.success() { 3631 return None; 3632 } 3633 3634 let stdout = String::from_utf8(output.stdout).ok()?; 3635 3636 match &stdout { 3637 s if s.starts_with("10") => Some(10), 3638 s if s.starts_with("11") => Some(11), 3639 s if s.starts_with("12") => Some(12), 3640 s if s.starts_with("13") => Some(13), 3641 s if s.starts_with("14") => Some(14), 3642 _ => None, 3643 } 3644 } 3645 3646 fn test_haiku(target: &str) { 3647 assert!(target.contains("haiku")); 3648 3649 let mut cfg = ctest_cfg(); 3650 cfg.flag("-Wno-deprecated-declarations"); 3651 cfg.define("__USE_GNU", Some("1")); 3652 3653 // POSIX API 3654 headers! { cfg: 3655 "alloca.h", 3656 "arpa/inet.h", 3657 "arpa/nameser.h", 3658 "arpa/nameser_compat.h", 3659 "assert.h", 3660 "bsd_mem.h", 3661 "complex.h", 3662 "ctype.h", 3663 "dirent.h", 3664 "div_t.h", 3665 "dlfcn.h", 3666 "endian.h", 3667 "errno.h", 3668 "fcntl.h", 3669 "fenv.h", 3670 "fnmatch.h", 3671 "fts.h", 3672 "ftw.h", 3673 "getopt.h", 3674 "glob.h", 3675 "grp.h", 3676 "inttypes.h", 3677 "iovec.h", 3678 "langinfo.h", 3679 "libgen.h", 3680 "libio.h", 3681 "limits.h", 3682 "locale.h", 3683 "malloc.h", 3684 "malloc_debug.h", 3685 "math.h", 3686 "memory.h", 3687 "monetary.h", 3688 "net/if.h", 3689 "net/if_dl.h", 3690 "net/if_media.h", 3691 "net/if_tun.h", 3692 "net/if_types.h", 3693 "net/route.h", 3694 "netdb.h", 3695 "netinet/icmp6.h", 3696 "netinet/in.h", 3697 "netinet/ip.h", 3698 "netinet/ip6.h", 3699 "netinet/ip_icmp.h", 3700 "netinet/ip_var.h", 3701 "netinet/tcp.h", 3702 "netinet/udp.h", 3703 "netinet6/in6.h", 3704 "nl_types.h", 3705 "null.h", 3706 "poll.h", 3707 "pthread.h", 3708 "pwd.h", 3709 "regex.h", 3710 "resolv.h", 3711 "sched.h", 3712 "search.h", 3713 "semaphore.h", 3714 "setjmp.h", 3715 "shadow.h", 3716 "signal.h", 3717 "size_t.h", 3718 "spawn.h", 3719 "stdint.h", 3720 "stdio.h", 3721 "stdlib.h", 3722 "string.h", 3723 "strings.h", 3724 "sys/cdefs.h", 3725 "sys/file.h", 3726 "sys/ioctl.h", 3727 "sys/ipc.h", 3728 "sys/mman.h", 3729 "sys/msg.h", 3730 "sys/param.h", 3731 "sys/poll.h", 3732 "sys/resource.h", 3733 "sys/select.h", 3734 "sys/sem.h", 3735 "sys/socket.h", 3736 "sys/sockio.h", 3737 "sys/stat.h", 3738 "sys/statvfs.h", 3739 "sys/time.h", 3740 "sys/timeb.h", 3741 "sys/times.h", 3742 "sys/types.h", 3743 "sys/uio.h", 3744 "sys/un.h", 3745 "sys/utsname.h", 3746 "sys/wait.h", 3747 "syslog.h", 3748 "tar.h", 3749 "termios.h", 3750 "time.h", 3751 "uchar.h", 3752 "unistd.h", 3753 "utime.h", 3754 "wchar.h", 3755 "wchar_t.h", 3756 "wctype.h" 3757 } 3758 3759 // BSD Extensions 3760 headers! { cfg: 3761 "pty.h", 3762 } 3763 3764 // Native API 3765 headers! { cfg: 3766 "kernel/OS.h", 3767 "kernel/fs_attr.h", 3768 "kernel/fs_index.h", 3769 "kernel/fs_info.h", 3770 "kernel/fs_query.h", 3771 "kernel/fs_volume.h", 3772 "kernel/image.h", 3773 "kernel/scheduler.h", 3774 "storage/FindDirectory.h", 3775 "storage/StorageDefs.h", 3776 "support/Errors.h", 3777 "support/SupportDefs.h", 3778 "support/TypeConstants.h" 3779 } 3780 3781 cfg.skip_struct(move |ty| { 3782 if ty.starts_with("__c_anonymous_") { 3783 return true; 3784 } 3785 match ty { 3786 // FIXME: actually a union 3787 "sigval" => true, 3788 // FIXME: locale_t does not exist on Haiku 3789 "locale_t" => true, 3790 // FIXME: rusage has a different layout on Haiku 3791 "rusage" => true, 3792 // FIXME?: complains that rust aligns on 4 byte boundary, but 3793 // Haiku does not align it at all. 3794 "in6_addr" => true, 3795 // The d_name attribute is an array of 1 on Haiku, with the 3796 // intention that the developer allocates a larger or smaller 3797 // piece of memory depending on the expected/actual size of the name. 3798 // Other platforms have sensible defaults. In Rust, the d_name field 3799 // is sized as the _POSIX_MAX_PATH, so that path names will fit in 3800 // newly allocated dirent objects. This breaks the automated tests. 3801 "dirent" => true, 3802 // The following structs contain function pointers, which cannot be initialized 3803 // with mem::zeroed(), so skip the automated test 3804 "image_info" | "thread_info" => true, 3805 3806 _ => false, 3807 } 3808 }); 3809 3810 cfg.skip_type(move |ty| { 3811 match ty { 3812 // FIXME: locale_t does not exist on Haiku 3813 "locale_t" => true, 3814 // These cause errors, to be reviewed in the future 3815 "sighandler_t" => true, 3816 "pthread_t" => true, 3817 "pthread_condattr_t" => true, 3818 "pthread_mutexattr_t" => true, 3819 "pthread_rwlockattr_t" => true, 3820 _ => false, 3821 } 3822 }); 3823 3824 cfg.skip_fn(move |name| { 3825 // skip those that are manually verified 3826 match name { 3827 // FIXME: https://github.com/rust-lang/libc/issues/1272 3828 "execv" | "execve" | "execvp" | "execvpe" => true, 3829 // FIXME: does not exist on haiku 3830 "open_wmemstream" => true, 3831 "mlockall" | "munlockall" => true, 3832 "tcgetsid" => true, 3833 "cfsetspeed" => true, 3834 // ignore for now, will be part of Haiku R1 beta 3 3835 "mlock" | "munlock" => true, 3836 // returns const char * on Haiku 3837 "strsignal" => true, 3838 // uses an enum as a parameter argument, which is incorrectly 3839 // translated into a struct argument 3840 "find_path" => true, 3841 3842 _ => false, 3843 } 3844 }); 3845 3846 cfg.skip_const(move |name| { 3847 match name { 3848 // FIXME: these constants do not exist on Haiku 3849 "DT_UNKNOWN" | "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" 3850 | "DT_SOCK" => true, 3851 "USRQUOTA" | "GRPQUOTA" => true, 3852 "SIGIOT" => true, 3853 "ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM" | "ATF_PUBL" 3854 | "ATF_USETRAILERS" => true, 3855 // Haiku does not have MAP_FILE, but rustc requires it 3856 "MAP_FILE" => true, 3857 // The following does not exist on Haiku but is required by 3858 // several crates 3859 "FIOCLEX" => true, 3860 // just skip this one, it is not defined on Haiku beta 2 but 3861 // since it is meant as a mask and not a parameter it can exist 3862 // here 3863 "LOG_PRIMASK" => true, 3864 // not defined on Haiku, but [get|set]priority is, so they are 3865 // useful 3866 "PRIO_MIN" | "PRIO_MAX" => true, 3867 // 3868 _ => false, 3869 } 3870 }); 3871 3872 cfg.skip_field(move |struct_, field| { 3873 match (struct_, field) { 3874 // FIXME: the stat struct actually has timespec members, whereas 3875 // the current representation has these unpacked. 3876 ("stat", "st_atime") => true, 3877 ("stat", "st_atime_nsec") => true, 3878 ("stat", "st_mtime") => true, 3879 ("stat", "st_mtime_nsec") => true, 3880 ("stat", "st_ctime") => true, 3881 ("stat", "st_ctime_nsec") => true, 3882 ("stat", "st_crtime") => true, 3883 ("stat", "st_crtime_nsec") => true, 3884 3885 // these are actually unions, but we cannot represent it well 3886 ("siginfo_t", "sigval") => true, 3887 ("sem_t", "named_sem_id") => true, 3888 ("sigaction", "sa_sigaction") => true, 3889 ("sigevent", "sigev_value") => true, 3890 ("fpu_state", "_fpreg") => true, 3891 // these fields have a simplified data definition in libc 3892 ("fpu_state", "_xmm") => true, 3893 ("savefpu", "_fp_ymm") => true, 3894 3895 // skip these enum-type fields 3896 ("thread_info", "state") => true, 3897 ("image_info", "image_type") => true, 3898 _ => false, 3899 } 3900 }); 3901 3902 cfg.skip_roundtrip(move |s| match s { 3903 // FIXME: for some reason the roundtrip check fails for cpu_info 3904 "cpu_info" => true, 3905 _ => false, 3906 }); 3907 3908 cfg.type_name(move |ty, is_struct, is_union| { 3909 match ty { 3910 // Just pass all these through, no need for a "struct" prefix 3911 "area_info" | "port_info" | "port_message_info" | "team_info" | "sem_info" 3912 | "team_usage_info" | "thread_info" | "cpu_info" | "system_info" 3913 | "object_wait_info" | "image_info" | "attr_info" | "index_info" | "fs_info" 3914 | "FILE" | "DIR" | "Dl_info" => ty.to_string(), 3915 3916 // is actually a union 3917 "sigval" => format!("union sigval"), 3918 t if is_union => format!("union {}", t), 3919 t if t.ends_with("_t") => t.to_string(), 3920 t if is_struct => format!("struct {}", t), 3921 t => t.to_string(), 3922 } 3923 }); 3924 3925 cfg.field_name(move |struct_, field| { 3926 match field { 3927 // Field is named `type` in C but that is a Rust keyword, 3928 // so these fields are translated to `type_` in the bindings. 3929 "type_" if struct_ == "object_wait_info" => "type".to_string(), 3930 "type_" if struct_ == "sem_t" => "type".to_string(), 3931 "type_" if struct_ == "attr_info" => "type".to_string(), 3932 "type_" if struct_ == "index_info" => "type".to_string(), 3933 "image_type" if struct_ == "image_info" => "type".to_string(), 3934 s => s.to_string(), 3935 } 3936 }); 3937 cfg.generate("../src/lib.rs", "main.rs"); 3938 } 3939