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