1 #![deny(warnings)] 2 #![allow(clippy::match_like_matches_macro)] 3 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 src_hotfix_dir() -> PathBuf { 12 Path::new(&env::var_os("OUT_DIR").unwrap()).join("src-hotfix") 13 } 14 15 fn do_cc() { 16 let target = env::var("TARGET").unwrap(); 17 if cfg!(unix) || target.contains("cygwin") { 18 let exclude = ["redox", "wasi", "wali"]; 19 if !exclude.iter().any(|x| target.contains(x)) { 20 let mut cmsg = cc::Build::new(); 21 22 cmsg.file("src/cmsg.c"); 23 24 if target.contains("solaris") || target.contains("illumos") { 25 cmsg.define("_XOPEN_SOURCE", "700"); 26 } 27 cmsg.compile("cmsg"); 28 } 29 30 if (target.contains("linux") && !target.contains("wasm32")) 31 || target.contains("android") 32 || target.contains("emscripten") 33 || target.contains("fuchsia") 34 || target.contains("bsd") 35 || target.contains("cygwin") 36 { 37 cc::Build::new().file("src/makedev.c").compile("makedev"); 38 } 39 } 40 if target.contains("android") || (target.contains("linux") && !target.contains("wasm32")) { 41 cc::Build::new().file("src/errqueue.c").compile("errqueue"); 42 } 43 if (target.contains("linux") && !target.contains("wasm32")) 44 || target.contains("l4re") 45 || target.contains("android") 46 || target.contains("emscripten") 47 || target.contains("solaris") 48 || target.contains("illumos") 49 { 50 cc::Build::new().file("src/sigrt.c").compile("sigrt"); 51 } 52 } 53 54 fn do_ctest() { 55 match &env::var("TARGET").unwrap() { 56 t if t.contains("android") => test_android(t), 57 t if t.contains("apple") => test_apple(t), 58 t if t.contains("dragonfly") => test_dragonflybsd(t), 59 t if t.contains("emscripten") => test_emscripten(t), 60 t if t.contains("freebsd") => test_freebsd(t), 61 t if t.contains("haiku") => test_haiku(t), 62 t if t.contains("linux") => test_linux(t), 63 t if t.contains("netbsd") => test_netbsd(t), 64 t if t.contains("openbsd") => test_openbsd(t), 65 t if t.contains("cygwin") => test_cygwin(t), 66 t if t.contains("redox") => test_redox(t), 67 t if t.contains("solaris") => test_solarish(t), 68 t if t.contains("illumos") => test_solarish(t), 69 t if t.contains("wasi") => test_wasi(t), 70 t if t.contains("windows") => test_windows(t), 71 t if t.contains("vxworks") => test_vxworks(t), 72 t if t.contains("nto-qnx") => test_neutrino(t), 73 t => panic!("unknown target {t}"), 74 } 75 } 76 77 fn ctest_cfg() -> ctest::TestGenerator { 78 let mut cfg = ctest::TestGenerator::new(); 79 let libc_cfgs = ["libc_thread_local"]; 80 for f in &libc_cfgs { 81 cfg.cfg(f, None); 82 } 83 cfg 84 } 85 86 fn do_semver() { 87 let mut out = PathBuf::from(env::var("OUT_DIR").unwrap()); 88 out.push("semver.rs"); 89 let mut output = BufWriter::new(File::create(&out).unwrap()); 90 91 let family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap(); 92 let vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); 93 let os = env::var("CARGO_CFG_TARGET_OS").unwrap(); 94 let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); 95 let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); 96 97 // `libc-test/semver` dir. 98 let mut semver_root = PathBuf::from("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 // We don't do semver for unknown targets. 109 if vendor != "unknown" { 110 process_semver_file(&mut output, &mut semver_root, &vendor); 111 } 112 process_semver_file(&mut output, &mut semver_root, &os); 113 let os_arch = format!("{os}-{arch}"); 114 process_semver_file(&mut output, &mut semver_root, &os_arch); 115 if !target_env.is_empty() { 116 let os_env = format!("{os}-{target_env}"); 117 process_semver_file(&mut output, &mut semver_root, &os_env); 118 119 let os_env_arch = format!("{os}-{target_env}-{arch}"); 120 process_semver_file(&mut output, &mut semver_root, &os_env_arch); 121 } 122 } 123 124 fn process_semver_file<W: Write, P: AsRef<Path>>(output: &mut W, path: &mut PathBuf, file: P) { 125 // NOTE: `path` is reused between calls, so always remove the file again. 126 path.push(file); 127 path.set_extension("txt"); 128 129 println!("cargo:rerun-if-changed={}", path.display()); 130 let input_file = match File::open(&*path) { 131 Ok(file) => file, 132 Err(ref err) if err.kind() == io::ErrorKind::NotFound => { 133 path.pop(); 134 return; 135 } 136 Err(err) => panic!("unexpected error opening file: {err}"), 137 }; 138 let input = BufReader::new(input_file); 139 140 writeln!(output, "// Source: {}.", path.display()).unwrap(); 141 output.write_all(b"use libc::{\n").unwrap(); 142 for line in input.lines() { 143 let line = line.unwrap().into_bytes(); 144 match line.first() { 145 // Ignore comments and empty lines. 146 Some(b'#') | None => continue, 147 _ => { 148 output.write_all(b" ").unwrap(); 149 output.write_all(&line).unwrap(); 150 output.write_all(b",\n").unwrap(); 151 } 152 } 153 } 154 output.write_all(b"};\n\n").unwrap(); 155 path.pop(); 156 } 157 158 fn main() { 159 // Avoid unnecessary re-building. 160 println!("cargo:rerun-if-changed=build.rs"); 161 162 let hotfix_dir = src_hotfix_dir(); 163 if std::fs::exists(&hotfix_dir).unwrap() { 164 std::fs::remove_dir_all(&hotfix_dir).unwrap(); 165 } 166 167 // FIXME(ctest): ctest2 cannot parse `crate::` in paths, so replace them with `::` 168 let re = regex::bytes::Regex::new(r"(?-u:\b)crate::").unwrap(); 169 copy_dir_hotfix(Path::new("../src"), &hotfix_dir, &re, b"::"); 170 171 do_cc(); 172 do_ctest(); 173 do_semver(); 174 } 175 176 // FIXME(clippy): removing `replace` somehow fails the `Test tier1 (x86_64-pc-windows-msvc, windows-2022)` CI job 177 #[allow(clippy::only_used_in_recursion)] 178 fn copy_dir_hotfix(src: &Path, dst: &Path, regex: ®ex::bytes::Regex, replace: &[u8]) { 179 std::fs::create_dir(dst).unwrap(); 180 for entry in src.read_dir().unwrap() { 181 let entry = entry.unwrap(); 182 let src_path = entry.path(); 183 let dst_path = dst.join(entry.file_name()); 184 if entry.file_type().unwrap().is_dir() { 185 copy_dir_hotfix(&src_path, &dst_path, regex, replace); 186 } else { 187 // Replace "crate::" with "::" 188 let src_data = std::fs::read(&src_path).unwrap(); 189 let dst_data = regex.replace_all(&src_data, b"::"); 190 std::fs::write(&dst_path, &dst_data).unwrap(); 191 } 192 } 193 } 194 195 macro_rules! headers { 196 ($cfg:ident: [$m:expr]: $header:literal) => { 197 if $m { 198 $cfg.header($header); 199 } 200 }; 201 ($cfg:ident: $header:literal) => { 202 $cfg.header($header); 203 }; 204 ($($cfg:ident: $([$c:expr]:)* $header:literal,)*) => { 205 $(headers!($cfg: $([$c]:)* $header);)* 206 }; 207 ($cfg:ident: $( $([$c:expr]:)* $header:literal,)*) => { 208 headers!($($cfg: $([$c]:)* $header,)*); 209 }; 210 ($cfg:ident: $( $([$c:expr]:)* $header:literal),*) => { 211 headers!($($cfg: $([$c]:)* $header,)*); 212 }; 213 } 214 215 fn test_apple(target: &str) { 216 assert!(target.contains("apple")); 217 let x86_64 = target.contains("x86_64"); 218 let i686 = target.contains("i686"); 219 220 let mut cfg = ctest_cfg(); 221 cfg.flag("-Wno-deprecated-declarations"); 222 cfg.define("__APPLE_USE_RFC_3542", None); 223 224 headers! { cfg: 225 "aio.h", 226 "CommonCrypto/CommonCrypto.h", 227 "CommonCrypto/CommonRandom.h", 228 "copyfile.h", 229 "crt_externs.h", 230 "ctype.h", 231 "dirent.h", 232 "dlfcn.h", 233 "errno.h", 234 "execinfo.h", 235 "fcntl.h", 236 "fnmatch.h", 237 "getopt.h", 238 "glob.h", 239 "grp.h", 240 "iconv.h", 241 "ifaddrs.h", 242 "langinfo.h", 243 "libgen.h", 244 "libproc.h", 245 "limits.h", 246 "locale.h", 247 "mach-o/dyld.h", 248 "mach/mach_init.h", 249 "mach/mach.h", 250 "mach/mach_time.h", 251 "mach/mach_types.h", 252 "mach/mach_vm.h", 253 "mach/thread_act.h", 254 "mach/thread_policy.h", 255 "malloc/malloc.h", 256 "net/bpf.h", 257 "net/dlil.h", 258 "net/if.h", 259 "net/if_arp.h", 260 "net/if_dl.h", 261 "net/if_mib.h", 262 "net/if_utun.h", 263 "net/if_var.h", 264 "net/ndrv.h", 265 "net/route.h", 266 "netdb.h", 267 "netinet/if_ether.h", 268 "netinet/in.h", 269 "netinet/ip.h", 270 "netinet/tcp.h", 271 "netinet/udp.h", 272 "netinet6/in6_var.h", 273 "os/clock.h", 274 "os/lock.h", 275 "os/signpost.h", 276 // FIXME(macos): Requires the macOS 14.4 SDK. 277 //"os/os_sync_wait_on_address.h", 278 "poll.h", 279 "pthread.h", 280 "pthread_spis.h", 281 "pthread/introspection.h", 282 "pthread/spawn.h", 283 "pthread/stack_np.h", 284 "pwd.h", 285 "regex.h", 286 "resolv.h", 287 "sched.h", 288 "semaphore.h", 289 "signal.h", 290 "spawn.h", 291 "stddef.h", 292 "stdint.h", 293 "stdio.h", 294 "stdlib.h", 295 "string.h", 296 "sysdir.h", 297 "sys/appleapiopts.h", 298 "sys/attr.h", 299 "sys/clonefile.h", 300 "sys/event.h", 301 "sys/file.h", 302 "sys/ioctl.h", 303 "sys/ipc.h", 304 "sys/kern_control.h", 305 "sys/mman.h", 306 "sys/mount.h", 307 "sys/proc_info.h", 308 "sys/ptrace.h", 309 "sys/quota.h", 310 "sys/random.h", 311 "sys/resource.h", 312 "sys/sem.h", 313 "sys/shm.h", 314 "sys/socket.h", 315 "sys/stat.h", 316 "sys/statvfs.h", 317 "sys/sys_domain.h", 318 "sys/sysctl.h", 319 "sys/time.h", 320 "sys/times.h", 321 "sys/timex.h", 322 "sys/types.h", 323 "sys/uio.h", 324 "sys/un.h", 325 "sys/utsname.h", 326 "sys/vsock.h", 327 "sys/wait.h", 328 "sys/xattr.h", 329 "syslog.h", 330 "termios.h", 331 "time.h", 332 "unistd.h", 333 "util.h", 334 "utime.h", 335 "utmpx.h", 336 "wchar.h", 337 "xlocale.h", 338 [x86_64]: "crt_externs.h", 339 } 340 341 cfg.skip_struct(move |ty| { 342 if ty.starts_with("__c_anonymous_") { 343 return true; 344 } 345 match ty { 346 // FIXME(union): actually a union 347 "sigval" => true, 348 349 // FIXME(macos): The size is changed in recent macOSes. 350 "malloc_zone_t" => true, 351 // it is a moving target, changing through versions 352 // also contains bitfields members 353 "tcp_connection_info" => true, 354 // FIXME(macos): The size is changed in recent macOSes. 355 "malloc_introspection_t" => true, 356 357 _ => false, 358 } 359 }); 360 361 cfg.skip_type(move |ty| { 362 if ty.starts_with("__c_anonymous_") { 363 return true; 364 } 365 match ty { 366 // FIXME(macos): Requires the macOS 14.4 SDK. 367 "os_sync_wake_by_address_flags_t" | "os_sync_wait_on_address_flags_t" => true, 368 369 // FIXME(macos): "'__uint128' undeclared" in C 370 "__uint128" => true, 371 372 _ => false, 373 } 374 }); 375 376 cfg.skip_const(move |name| { 377 // They're declared via `deprecated_mach` and we don't support it anymore. 378 if name.starts_with("VM_FLAGS_") { 379 return true; 380 } 381 match name { 382 // These OSX constants are removed in Sierra. 383 // https://developer.apple.com/library/content/releasenotes/General/APIDiffsMacOS10_12/Swift/Darwin.html 384 "KERN_KDENABLE_BG_TRACE" | "KERN_KDDISABLE_BG_TRACE" => true, 385 // FIXME(macos): the value has been changed since Catalina (0xffff0000 -> 0x3fff0000). 386 "SF_SETTABLE" => true, 387 388 // FIXME(macos): XCode 13.1 doesn't have it. 389 "TIOCREMOTE" => true, 390 391 // FIXME(macos): Requires the macOS 14.4 SDK. 392 "OS_SYNC_WAKE_BY_ADDRESS_NONE" 393 | "OS_SYNC_WAKE_BY_ADDRESS_SHARED" 394 | "OS_SYNC_WAIT_ON_ADDRESS_NONE" 395 | "OS_SYNC_WAIT_ON_ADDRESS_SHARED" => true, 396 397 _ => false, 398 } 399 }); 400 401 cfg.skip_fn(move |name| { 402 // skip those that are manually verified 403 match name { 404 // FIXME: https://github.com/rust-lang/libc/issues/1272 405 "execv" | "execve" | "execvp" => true, 406 407 // close calls the close_nocancel system call 408 "close" => true, 409 410 // FIXME(1.0): std removed libresolv support: https://github.com/rust-lang/rust/pull/102766 411 "res_init" => true, 412 413 // FIXME(macos): remove once the target in CI is updated 414 "pthread_jit_write_freeze_callbacks_np" => true, 415 416 // FIXME(macos): ABI has been changed on recent macOSes. 417 "os_unfair_lock_assert_owner" | "os_unfair_lock_assert_not_owner" => true, 418 419 // FIXME(macos): Once the SDK get updated to Ventura's level 420 "freadlink" | "mknodat" | "mkfifoat" => true, 421 422 // FIXME(macos): Requires the macOS 14.4 SDK. 423 "os_sync_wake_by_address_any" 424 | "os_sync_wake_by_address_all" 425 | "os_sync_wake_by_address_flags_t" 426 | "os_sync_wait_on_address" 427 | "os_sync_wait_on_address_flags_t" 428 | "os_sync_wait_on_address_with_deadline" 429 | "os_sync_wait_on_address_with_timeout" => true, 430 431 _ => false, 432 } 433 }); 434 435 cfg.skip_field(move |struct_, field| { 436 match (struct_, field) { 437 // FIXME(macos): the array size has been changed since macOS 10.15 ([8] -> [7]). 438 ("statfs", "f_reserved") => true, 439 ("__darwin_arm_neon_state64", "__v") => true, 440 // MAXPATHLEN is too big for auto-derive traits on arrays. 441 ("vnode_info_path", "vip_path") => true, 442 ("ifreq", "ifr_ifru") => true, 443 ("in6_ifreq", "ifr_ifru") => true, 444 ("ifkpi", "ifk_data") => true, 445 ("ifconf", "ifc_ifcu") => true, 446 // FIXME: this field has been incorporated into a resized `rmx_filler` array. 447 ("rt_metrics", "rmx_state") => true, 448 ("rt_metrics", "rmx_filler") => true, 449 _ => false, 450 } 451 }); 452 453 cfg.skip_field_type(move |struct_, field| { 454 match (struct_, field) { 455 // FIXME(union): actually a union 456 ("sigevent", "sigev_value") => true, 457 _ => false, 458 } 459 }); 460 461 cfg.volatile_item(|i| { 462 use ctest::VolatileItemKind::*; 463 match i { 464 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 465 _ => false, 466 } 467 }); 468 469 cfg.type_name(move |ty, is_struct, is_union| { 470 match ty { 471 // Just pass all these through, no need for a "struct" prefix 472 "FILE" | "DIR" | "Dl_info" => ty.to_string(), 473 474 // OSX calls this something else 475 "sighandler_t" => "sig_t".to_string(), 476 477 t if is_union => format!("union {t}"), 478 t if t.ends_with("_t") => t.to_string(), 479 t if is_struct => format!("struct {t}"), 480 t => t.to_string(), 481 } 482 }); 483 484 cfg.field_name(move |struct_, field| { 485 match field { 486 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 487 s.replace("e_nsec", "espec.tv_nsec") 488 } 489 // FIXME(macos): sigaction actually contains a union with two variants: 490 // a sa_sigaction with type: (*)(int, struct __siginfo *, void *) 491 // a sa_handler with type sig_t 492 "sa_sigaction" if struct_ == "sigaction" => "sa_handler".to_string(), 493 s => s.to_string(), 494 } 495 }); 496 497 cfg.skip_roundtrip(move |s| match s { 498 // FIXME(macos): this type has the wrong ABI 499 "max_align_t" if i686 => true, 500 // Can't return an array from a C function. 501 "uuid_t" | "vol_capabilities_set_t" => true, 502 _ => false, 503 }); 504 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 505 } 506 507 fn test_openbsd(target: &str) { 508 assert!(target.contains("openbsd")); 509 510 let mut cfg = ctest_cfg(); 511 cfg.flag("-Wno-deprecated-declarations"); 512 513 let x86_64 = target.contains("x86_64"); 514 515 headers! { cfg: 516 "elf.h", 517 "errno.h", 518 "execinfo.h", 519 "fcntl.h", 520 "fnmatch.h", 521 "getopt.h", 522 "libgen.h", 523 "limits.h", 524 "link.h", 525 "locale.h", 526 "stddef.h", 527 "stdint.h", 528 "stdio.h", 529 "stdlib.h", 530 "sys/stat.h", 531 "sys/types.h", 532 "time.h", 533 "wchar.h", 534 "ctype.h", 535 "dirent.h", 536 "sys/socket.h", 537 [x86_64]:"machine/fpu.h", 538 "net/if.h", 539 "net/route.h", 540 "net/if_arp.h", 541 "netdb.h", 542 "netinet/in.h", 543 "netinet/ip.h", 544 "netinet/tcp.h", 545 "netinet/udp.h", 546 "net/bpf.h", 547 "regex.h", 548 "resolv.h", 549 "pthread.h", 550 "dlfcn.h", 551 "search.h", 552 "spawn.h", 553 "signal.h", 554 "string.h", 555 "sys/file.h", 556 "sys/futex.h", 557 "sys/ioctl.h", 558 "sys/ipc.h", 559 "sys/mman.h", 560 "sys/param.h", 561 "sys/resource.h", 562 "sys/shm.h", 563 "sys/socket.h", 564 "sys/time.h", 565 "sys/uio.h", 566 "sys/ktrace.h", 567 "sys/un.h", 568 "sys/wait.h", 569 "unistd.h", 570 "utime.h", 571 "pwd.h", 572 "grp.h", 573 "sys/utsname.h", 574 "sys/ptrace.h", 575 "sys/mount.h", 576 "sys/uio.h", 577 "sched.h", 578 "termios.h", 579 "poll.h", 580 "syslog.h", 581 "semaphore.h", 582 "sys/statvfs.h", 583 "sys/times.h", 584 "glob.h", 585 "ifaddrs.h", 586 "langinfo.h", 587 "sys/sysctl.h", 588 "utmp.h", 589 "sys/event.h", 590 "net/if_dl.h", 591 "util.h", 592 "ufs/ufs/quota.h", 593 "pthread_np.h", 594 "sys/reboot.h", 595 "sys/syscall.h", 596 "sys/shm.h", 597 "sys/param.h", 598 } 599 600 cfg.skip_struct(move |ty| { 601 if ty.starts_with("__c_anonymous_") { 602 return true; 603 } 604 match ty { 605 // FIXME(union): actually a union 606 "sigval" => true, 607 608 _ => false, 609 } 610 }); 611 612 cfg.skip_const(move |name| { 613 match name { 614 // Removed in OpenBSD 6.0 615 "KERN_USERMOUNT" | "KERN_ARND" => true, 616 // Removed in OpenBSD 7.2 617 "KERN_NSELCOLL" => true, 618 // Good chance it's going to be wrong depending on the host release 619 "KERN_MAXID" | "NET_RT_MAXID" => true, 620 "EV_SYSFLAGS" => true, 621 622 // Removed in OpenBSD 7.7 (unused since 1991) 623 "ATF_COM" | "ATF_PERM" | "ATF_PUBL" | "ATF_USETRAILERS" => true, 624 625 _ => false, 626 } 627 }); 628 629 cfg.skip_fn(move |name| { 630 match name { 631 // FIXME: https://github.com/rust-lang/libc/issues/1272 632 "execv" | "execve" | "execvp" | "execvpe" => true, 633 634 // Removed in OpenBSD 6.5 635 // https://marc.info/?l=openbsd-cvs&m=154723400730318 636 "mincore" => true, 637 638 // futex() has volatile arguments, but that doesn't exist in Rust. 639 "futex" => true, 640 641 // Available for openBSD 7.3 642 "mimmutable" => true, 643 644 // Removed in OpenBSD 7.5 645 // https://marc.info/?l=openbsd-cvs&m=170239504300386 646 "syscall" => true, 647 648 _ => false, 649 } 650 }); 651 652 cfg.type_name(move |ty, is_struct, is_union| { 653 match ty { 654 // Just pass all these through, no need for a "struct" prefix 655 "FILE" | "DIR" | "Dl_info" | "Elf32_Phdr" | "Elf64_Phdr" => ty.to_string(), 656 657 // OSX calls this something else 658 "sighandler_t" => "sig_t".to_string(), 659 660 t if is_union => format!("union {t}"), 661 t if t.ends_with("_t") => t.to_string(), 662 t if is_struct => format!("struct {t}"), 663 t => t.to_string(), 664 } 665 }); 666 667 cfg.field_name(move |struct_, field| match field { 668 "st_birthtime" if struct_.starts_with("stat") => "__st_birthtime".to_string(), 669 "st_birthtime_nsec" if struct_.starts_with("stat") => "__st_birthtimensec".to_string(), 670 s if s.ends_with("_nsec") && struct_.starts_with("stat") => s.replace("e_nsec", ".tv_nsec"), 671 "sa_sigaction" if struct_ == "sigaction" => "sa_handler".to_string(), 672 s => s.to_string(), 673 }); 674 675 cfg.skip_field_type(move |struct_, field| { 676 // type siginfo_t.si_addr changed from OpenBSD 6.0 to 6.1 677 struct_ == "siginfo_t" && field == "si_addr" 678 }); 679 680 cfg.skip_field(|struct_, field| { 681 match (struct_, field) { 682 // conflicting with `p_type` macro from <resolve.h>. 683 ("Elf32_Phdr", "p_type") => true, 684 ("Elf64_Phdr", "p_type") => true, 685 // ifr_ifru is defined is an union 686 ("ifreq", "ifr_ifru") => true, 687 _ => false, 688 } 689 }); 690 691 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 692 } 693 694 fn test_cygwin(target: &str) { 695 assert!(target.contains("cygwin")); 696 697 let mut cfg = ctest_cfg(); 698 cfg.define("_GNU_SOURCE", None); 699 700 headers! { cfg: 701 "ctype.h", 702 "dirent.h", 703 "dlfcn.h", 704 "errno.h", 705 "fcntl.h", 706 "fnmatch.h", 707 "grp.h", 708 "iconv.h", 709 "langinfo.h", 710 "limits.h", 711 "locale.h", 712 "net/if.h", 713 "netdb.h", 714 "netinet/tcp.h", 715 "poll.h", 716 "pthread.h", 717 "pty.h", 718 "pwd.h", 719 "resolv.h", 720 "sched.h", 721 "semaphore.h", 722 "signal.h", 723 "spawn.h", 724 "stddef.h", 725 "stdlib.h", 726 "string.h", 727 "sys/cpuset.h", 728 "sys/ioctl.h", 729 "sys/mman.h", 730 "sys/mount.h", 731 "sys/param.h", 732 "sys/quota.h", 733 "sys/random.h", 734 "sys/resource.h", 735 "sys/select.h", 736 "sys/socket.h", 737 "sys/statvfs.h", 738 "sys/times.h", 739 "sys/types.h", 740 "sys/uio.h", 741 "sys/un.h", 742 "sys/utsname.h", 743 "sys/vfs.h", 744 "syslog.h", 745 "termios.h", 746 "unistd.h", 747 "utime.h", 748 "wait.h", 749 "wchar.h", 750 } 751 752 cfg.type_name(move |ty, is_struct, is_union| { 753 match ty { 754 // Just pass all these through, no need for a "struct" prefix 755 "FILE" | "DIR" | "Dl_info" | "fd_set" => ty.to_string(), 756 757 "Ioctl" => "int".to_string(), 758 759 t if is_union => format!("union {t}"), 760 761 t if t.ends_with("_t") => t.to_string(), 762 763 // sigval is a struct in Rust, but a union in C: 764 "sigval" => "union sigval".to_string(), 765 766 // put `struct` in front of all structs:. 767 t if is_struct => format!("struct {t}"), 768 769 t => t.to_string(), 770 } 771 }); 772 773 cfg.skip_const(move |name| { 774 match name { 775 // FIXME(cygwin): these constants do not exist on Cygwin 776 "ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM" | "ATF_PUBL" 777 | "ATF_USETRAILERS" => true, 778 779 // not defined on Cygwin, but [get|set]priority is, so they are 780 // useful 781 "PRIO_MIN" | "PRIO_MAX" => true, 782 783 // The following does not exist on Cygwin but is required by 784 // several crates 785 "FIOCLEX" | "SA_NOCLDWAIT" => true, 786 787 _ => false, 788 } 789 }); 790 791 cfg.skip_signededness(move |c| match c { 792 n if n.starts_with("pthread") => true, 793 794 // For consistency with other platforms. Actually a function ptr. 795 "sighandler_t" => true, 796 797 _ => false, 798 }); 799 800 cfg.skip_struct(move |ty| { 801 if ty.starts_with("__c_anonymous_") { 802 return true; 803 } 804 805 false 806 }); 807 808 cfg.field_name(move |struct_, field| { 809 match field { 810 // Our stat *_nsec fields normally don't actually exist but are part 811 // of a timeval struct 812 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 813 s.replace("e_nsec", ".tv_nsec") 814 } 815 816 // FIXME(cygwin): sigaction actually contains a union with two variants: 817 // a sa_sigaction with type: (*)(int, struct __siginfo *, void *) 818 // a sa_handler with type sig_t 819 "sa_sigaction" if struct_ == "sigaction" => "sa_handler".to_string(), 820 821 s => s.to_string(), 822 } 823 }); 824 825 cfg.skip_field(|struct_, field| { 826 match (struct_, field) { 827 // this is actually a union on linux, so we can't represent it well and 828 // just insert some padding. 829 ("ifreq", "ifr_ifru") => true, 830 ("ifconf", "ifc_ifcu") => true, 831 832 _ => false, 833 } 834 }); 835 836 cfg.skip_fn(move |name| { 837 // skip those that are manually verified 838 match name { 839 // There are two versions of the sterror_r function, see 840 // 841 // https://linux.die.net/man/3/strerror_r 842 // 843 // An XSI-compliant version provided if: 844 // 845 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE 846 // 847 // and a GNU specific version provided if _GNU_SOURCE is defined. 848 // 849 // libc provides bindings for the XSI-compliant version, which is 850 // preferred for portable applications. 851 // 852 // We skip the test here since here _GNU_SOURCE is defined, and 853 // test the XSI version below. 854 "strerror_r" => true, 855 856 // FIXME(cygwin): does not exist on Cygwin 857 "mlockall" | "munlockall" => true, 858 859 _ => false, 860 } 861 }); 862 863 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 864 } 865 866 fn test_windows(target: &str) { 867 assert!(target.contains("windows")); 868 let gnu = target.contains("gnu"); 869 let i686 = target.contains("i686"); 870 871 let mut cfg = ctest_cfg(); 872 if target.contains("msvc") { 873 cfg.flag("/wd4324"); 874 } 875 cfg.define("_WIN32_WINNT", Some("0x8000")); 876 877 headers! { cfg: 878 "direct.h", 879 "errno.h", 880 "fcntl.h", 881 "io.h", 882 "limits.h", 883 "locale.h", 884 "process.h", 885 "signal.h", 886 "stddef.h", 887 "stdint.h", 888 "stdio.h", 889 "stdlib.h", 890 "sys/stat.h", 891 "sys/types.h", 892 "sys/utime.h", 893 "time.h", 894 "wchar.h", 895 [gnu]: "ws2tcpip.h", 896 [!gnu]: "Winsock2.h", 897 } 898 899 cfg.type_name(move |ty, is_struct, is_union| { 900 match ty { 901 // Just pass all these through, no need for a "struct" prefix 902 "FILE" | "DIR" | "Dl_info" => ty.to_string(), 903 904 // FIXME(windows): these don't exist: 905 "time64_t" => "__time64_t".to_string(), 906 "ssize_t" => "SSIZE_T".to_string(), 907 908 "sighandler_t" if !gnu => "_crt_signal_t".to_string(), 909 "sighandler_t" if gnu => "__p_sig_fn_t".to_string(), 910 911 t if is_union => format!("union {t}"), 912 t if t.ends_with("_t") => t.to_string(), 913 914 // Windows uppercase structs don't have `struct` in front: 915 t if is_struct => { 916 if ty.chars().next().unwrap().is_uppercase() { 917 t.to_string() 918 } else if t == "stat" { 919 "struct __stat64".to_string() 920 } else if t == "utimbuf" { 921 "struct __utimbuf64".to_string() 922 } else { 923 // put `struct` in front of all structs: 924 format!("struct {t}") 925 } 926 } 927 t => t.to_string(), 928 } 929 }); 930 931 cfg.fn_cname(move |name, cname| cname.unwrap_or(name).to_string()); 932 933 cfg.skip_type(move |name| match name { 934 "SSIZE_T" if !gnu => true, 935 "ssize_t" if !gnu => true, 936 // FIXME(windows): The size and alignment of this type are incorrect 937 "time_t" if gnu && i686 => true, 938 _ => false, 939 }); 940 941 cfg.skip_struct(move |ty| { 942 if ty.starts_with("__c_anonymous_") { 943 return true; 944 } 945 match ty { 946 // FIXME(windows): The size and alignment of this struct are incorrect 947 "timespec" if gnu && i686 => true, 948 _ => false, 949 } 950 }); 951 952 cfg.skip_const(move |name| { 953 match name { 954 // FIXME(windows): API error: 955 // SIG_ERR type is "void (*)(int)", not "int" 956 "SIG_ERR" | 957 // Similar for SIG_DFL/IGN/GET/SGE/ACK 958 "SIG_DFL" | "SIG_IGN" | "SIG_GET" | "SIG_SGE" | "SIG_ACK" => true, 959 // FIXME(windows): newer windows-gnu environment on CI? 960 "_O_OBTAIN_DIR" if gnu => true, 961 _ => false, 962 } 963 }); 964 965 cfg.skip_field(move |s, field| match s { 966 "CONTEXT" if field == "Fp" => true, 967 _ => false, 968 }); 969 // FIXME(windows): All functions point to the wrong addresses? 970 cfg.skip_fn_ptrcheck(|_| true); 971 972 cfg.skip_signededness(move |c| { 973 match c { 974 // windows-isms 975 n if n.starts_with("P") => true, 976 n if n.starts_with("H") => true, 977 n if n.starts_with("LP") => true, 978 "sighandler_t" if gnu => true, 979 _ => false, 980 } 981 }); 982 983 cfg.skip_fn(move |name| { 984 match name { 985 // FIXME: https://github.com/rust-lang/libc/issues/1272 986 "execv" | "execve" | "execvp" | "execvpe" => true, 987 988 _ => false, 989 } 990 }); 991 992 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 993 } 994 995 fn test_redox(target: &str) { 996 assert!(target.contains("redox")); 997 998 let mut cfg = ctest_cfg(); 999 cfg.flag("-Wno-deprecated-declarations"); 1000 1001 headers! { 1002 cfg: 1003 "ctype.h", 1004 "dirent.h", 1005 "dlfcn.h", 1006 "errno.h", 1007 "fcntl.h", 1008 "fnmatch.h", 1009 "grp.h", 1010 "limits.h", 1011 "locale.h", 1012 "netdb.h", 1013 "netinet/in.h", 1014 "netinet/ip.h", 1015 "netinet/tcp.h", 1016 "poll.h", 1017 "pwd.h", 1018 "semaphore.h", 1019 "string.h", 1020 "strings.h", 1021 "sys/file.h", 1022 "sys/ioctl.h", 1023 "sys/mman.h", 1024 "sys/ptrace.h", 1025 "sys/resource.h", 1026 "sys/socket.h", 1027 "sys/stat.h", 1028 "sys/statvfs.h", 1029 "sys/time.h", 1030 "sys/types.h", 1031 "sys/uio.h", 1032 "sys/un.h", 1033 "sys/utsname.h", 1034 "sys/wait.h", 1035 "termios.h", 1036 "time.h", 1037 "unistd.h", 1038 "utime.h", 1039 "wchar.h", 1040 } 1041 1042 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 1043 } 1044 1045 fn test_solarish(target: &str) { 1046 let is_solaris = target.contains("solaris"); 1047 let is_illumos = target.contains("illumos"); 1048 assert!(is_solaris || is_illumos); 1049 1050 // ctest generates arguments supported only by clang, so make sure to run with CC=clang. 1051 // While debugging, "CFLAGS=-ferror-limit=<large num>" is useful to get more error output. 1052 let mut cfg = ctest_cfg(); 1053 cfg.flag("-Wno-deprecated-declarations"); 1054 1055 cfg.define("_XOPEN_SOURCE", Some("700")); 1056 cfg.define("__EXTENSIONS__", None); 1057 cfg.define("_LCONV_C99", None); 1058 1059 // FIXME(solaris): This should be removed once new Nix crate is released. 1060 // See comment in src/unix/solarish/solaris.rs for these. 1061 if is_solaris { 1062 cfg.define("O_DIRECT", Some("0x2000000")); 1063 cfg.define("SIGINFO", Some("41")); 1064 } 1065 1066 headers! { 1067 cfg: 1068 "aio.h", 1069 "ctype.h", 1070 "dirent.h", 1071 "dlfcn.h", 1072 "door.h", 1073 "errno.h", 1074 "execinfo.h", 1075 "fcntl.h", 1076 "fnmatch.h", 1077 "getopt.h", 1078 "glob.h", 1079 "grp.h", 1080 "ifaddrs.h", 1081 "langinfo.h", 1082 "limits.h", 1083 "link.h", 1084 "locale.h", 1085 "mqueue.h", 1086 "net/if.h", 1087 "net/if_arp.h", 1088 "net/route.h", 1089 "netdb.h", 1090 "netinet/in.h", 1091 "netinet/ip.h", 1092 "netinet/tcp.h", 1093 "netinet/udp.h", 1094 "poll.h", 1095 "port.h", 1096 "pthread.h", 1097 "pwd.h", 1098 "resolv.h", 1099 "sched.h", 1100 "semaphore.h", 1101 "signal.h", 1102 "spawn.h", 1103 "stddef.h", 1104 "stdint.h", 1105 "stdio.h", 1106 "stdlib.h", 1107 "string.h", 1108 "sys/auxv.h", 1109 "sys/file.h", 1110 "sys/filio.h", 1111 "sys/ioctl.h", 1112 "sys/lgrp_user.h", 1113 "sys/loadavg.h", 1114 "sys/mkdev.h", 1115 "sys/mman.h", 1116 "sys/mount.h", 1117 "sys/priv.h", 1118 "sys/pset.h", 1119 "sys/random.h", 1120 "sys/resource.h", 1121 "sys/sendfile.h", 1122 "sys/socket.h", 1123 "sys/stat.h", 1124 "sys/statvfs.h", 1125 "sys/stropts.h", 1126 "sys/shm.h", 1127 "sys/systeminfo.h", 1128 "sys/time.h", 1129 "sys/times.h", 1130 "sys/timex.h", 1131 "sys/types.h", 1132 "sys/uio.h", 1133 "sys/un.h", 1134 "sys/utsname.h", 1135 "sys/wait.h", 1136 "syslog.h", 1137 "termios.h", 1138 "thread.h", 1139 "time.h", 1140 "priv.h", 1141 "ucontext.h", 1142 "unistd.h", 1143 "utime.h", 1144 "utmpx.h", 1145 "wchar.h", 1146 } 1147 1148 if is_illumos { 1149 headers! { cfg: 1150 "sys/epoll.h", 1151 "sys/eventfd.h", 1152 } 1153 } 1154 1155 if is_solaris { 1156 headers! { cfg: 1157 "sys/lgrp_user_impl.h", 1158 } 1159 } 1160 1161 cfg.skip_type(move |ty| match ty { 1162 "sighandler_t" => true, 1163 _ => false, 1164 }); 1165 1166 cfg.type_name(move |ty, is_struct, is_union| match ty { 1167 "FILE" => "__FILE".to_string(), 1168 "DIR" | "Dl_info" => ty.to_string(), 1169 t if t.ends_with("_t") => t.to_string(), 1170 t if is_struct => format!("struct {t}"), 1171 t if is_union => format!("union {t}"), 1172 t => t.to_string(), 1173 }); 1174 1175 cfg.field_name(move |struct_, field| { 1176 match struct_ { 1177 // rust struct uses raw u64, rather than union 1178 "epoll_event" if field == "u64" => "data.u64".to_string(), 1179 // rust struct was committed with typo for Solaris 1180 "door_arg_t" if field == "dec_num" => "desc_num".to_string(), 1181 "stat" if field.ends_with("_nsec") => { 1182 // expose stat.Xtim.tv_nsec fields 1183 field.trim_end_matches("e_nsec").to_string() + ".tv_nsec" 1184 } 1185 _ => field.to_string(), 1186 } 1187 }); 1188 1189 cfg.skip_const(move |name| match name { 1190 "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" | "DT_SOCK" 1191 | "USRQUOTA" | "GRPQUOTA" | "PRIO_MIN" | "PRIO_MAX" => true, 1192 1193 // skip sighandler_t assignments 1194 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, 1195 1196 "DT_UNKNOWN" => true, 1197 1198 "_UTX_LINESIZE" | "_UTX_USERSIZE" | "_UTX_PADSIZE" | "_UTX_IDSIZE" | "_UTX_HOSTSIZE" => { 1199 true 1200 } 1201 1202 "EADI" | "EXTPROC" | "IPC_SEAT" => true, 1203 1204 // This evaluates to a sysconf() call rather than a constant 1205 "PTHREAD_STACK_MIN" => true, 1206 1207 // EPOLLEXCLUSIVE is a relatively recent addition to the epoll interface and may not be 1208 // defined on older systems. It is, however, safe to use on systems which do not 1209 // explicitly support it. (A no-op is an acceptable implementation of EPOLLEXCLUSIVE.) 1210 "EPOLLEXCLUSIVE" if is_illumos => true, 1211 1212 _ => false, 1213 }); 1214 1215 cfg.skip_struct(move |ty| { 1216 if ty.starts_with("__c_anonymous_") { 1217 return true; 1218 } 1219 // the union handling is a mess 1220 if ty.contains("door_desc_t_") { 1221 return true; 1222 } 1223 match ty { 1224 // union, not a struct 1225 "sigval" => true, 1226 // a bunch of solaris-only fields 1227 "utmpx" if is_illumos => true, 1228 _ => false, 1229 } 1230 }); 1231 1232 cfg.skip_field_type(move |struct_, field| { 1233 // aio_buf is "volatile void*" 1234 struct_ == "aiocb" && field == "aio_buf" 1235 }); 1236 1237 cfg.skip_field(move |s, field| { 1238 match s { 1239 // C99 sizing on this is tough 1240 "dirent" if field == "d_name" => true, 1241 // the union/macro makes this rough 1242 "sigaction" if field == "sa_sigaction" => true, 1243 // Missing in illumos 1244 "sigevent" if field == "ss_sp" => true, 1245 // Avoid sigval union issues 1246 "sigevent" if field == "sigev_value" => true, 1247 // const issues 1248 "sigevent" if field == "sigev_notify_attributes" => true, 1249 1250 // Avoid const and union issues 1251 "door_arg" if field == "desc_ptr" => true, 1252 "door_desc_t" if field == "d_data" => true, 1253 "door_arg_t" if field.ends_with("_ptr") => true, 1254 "door_arg_t" if field.ends_with("rbuf") => true, 1255 1256 // anonymous union challenges 1257 "fpregset_t" if field == "fp_reg_set" => true, 1258 1259 // The LX brand (integrated into some illumos distros) commandeered several of the 1260 // `uc_filler` fields to use for brand-specific state. 1261 "ucontext_t" if is_illumos && (field == "uc_filler" || field == "uc_brand_data") => { 1262 true 1263 } 1264 1265 _ => false, 1266 } 1267 }); 1268 1269 cfg.skip_fn(move |name| { 1270 // skip those that are manually verified 1271 match name { 1272 // const-ness only added recently 1273 "dladdr" => true, 1274 1275 // Definition of those functions as changed since unified headers 1276 // from NDK r14b These changes imply some API breaking changes but 1277 // are still ABI compatible. We can wait for the next major release 1278 // to be compliant with the new API. 1279 // 1280 // FIXME(solarish): unskip these for next major release 1281 "setpriority" | "personality" => true, 1282 1283 // signal is defined in terms of sighandler_t, so ignore 1284 "signal" => true, 1285 1286 // Currently missing 1287 "cfmakeraw" | "cfsetspeed" => true, 1288 1289 // const-ness issues 1290 "execv" | "execve" | "execvp" | "settimeofday" | "sethostname" => true, 1291 1292 // FIXME(1.0): https://github.com/rust-lang/libc/issues/1272 1293 "fexecve" => true, 1294 1295 // Solaris-different 1296 "getpwent_r" | "getgrent_r" | "updwtmpx" if is_illumos => true, 1297 "madvise" | "mprotect" if is_illumos => true, 1298 "door_call" | "door_return" | "door_create" if is_illumos => true, 1299 1300 // The compat functions use these "native" functions linked to their 1301 // non-prefixed implementations in libc. 1302 "native_getpwent_r" | "native_getgrent_r" => true, 1303 1304 // Not visible when build with _XOPEN_SOURCE=700 1305 "mmapobj" | "mmap64" | "meminfo" | "getpagesizes" | "getpagesizes2" => true, 1306 1307 // These functions may return int or void depending on the exact 1308 // configuration of the compilation environment, but the return 1309 // value is not useful (always 0) so we can ignore it: 1310 "setservent" | "endservent" => true, 1311 1312 // Following illumos#3729, getifaddrs was changed to a 1313 // redefine_extname symbol in order to preserve compatibility. 1314 // Until better symbol binding story is figured out, it must be 1315 // excluded from the tests. 1316 "getifaddrs" if is_illumos => true, 1317 1318 // FIXME(ctest): Our API is unsound. The Rust API allows aliasing 1319 // pointers, but the C API requires pointers not to alias. 1320 // We should probably be at least using `&`/`&mut` here, see: 1321 // https://github.com/gnzlbg/ctest/issues/68 1322 "lio_listio" => true, 1323 1324 // Exists on illumos too but, for now, is 1325 // [a recent addition](https://www.illumos.org/issues/17094). 1326 "secure_getenv" if is_illumos => true, 1327 1328 _ => false, 1329 } 1330 }); 1331 1332 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 1333 } 1334 1335 fn test_netbsd(target: &str) { 1336 assert!(target.contains("netbsd")); 1337 let mut cfg = ctest_cfg(); 1338 1339 cfg.flag("-Wno-deprecated-declarations"); 1340 cfg.define("_NETBSD_SOURCE", Some("1")); 1341 1342 headers! { 1343 cfg: 1344 "elf.h", 1345 "errno.h", 1346 "fcntl.h", 1347 "fnmatch.h", 1348 "getopt.h", 1349 "libgen.h", 1350 "limits.h", 1351 "link.h", 1352 "locale.h", 1353 "stddef.h", 1354 "stdint.h", 1355 "stdio.h", 1356 "stdlib.h", 1357 "sys/stat.h", 1358 "sys/types.h", 1359 "time.h", 1360 "wchar.h", 1361 "aio.h", 1362 "ctype.h", 1363 "dirent.h", 1364 "dlfcn.h", 1365 "glob.h", 1366 "grp.h", 1367 "ifaddrs.h", 1368 "langinfo.h", 1369 "net/bpf.h", 1370 "net/if.h", 1371 "net/if_arp.h", 1372 "net/if_dl.h", 1373 "net/route.h", 1374 "netdb.h", 1375 "netinet/in.h", 1376 "netinet/ip.h", 1377 "netinet/tcp.h", 1378 "netinet/udp.h", 1379 "poll.h", 1380 "pthread.h", 1381 "pwd.h", 1382 "regex.h", 1383 "resolv.h", 1384 "sched.h", 1385 "semaphore.h", 1386 "signal.h", 1387 "string.h", 1388 "sys/endian.h", 1389 "sys/exec_elf.h", 1390 "sys/xattr.h", 1391 "sys/extattr.h", 1392 "sys/file.h", 1393 "sys/ioctl.h", 1394 "sys/ioctl_compat.h", 1395 "sys/ipc.h", 1396 "sys/ktrace.h", 1397 "sys/mman.h", 1398 "sys/mount.h", 1399 "sys/ptrace.h", 1400 "sys/resource.h", 1401 "sys/shm.h", 1402 "sys/socket.h", 1403 "sys/statvfs.h", 1404 "sys/sysctl.h", 1405 "sys/time.h", 1406 "sys/times.h", 1407 "sys/timex.h", 1408 "sys/ucontext.h", 1409 "sys/ucred.h", 1410 "sys/uio.h", 1411 "sys/un.h", 1412 "sys/utsname.h", 1413 "sys/wait.h", 1414 "syslog.h", 1415 "termios.h", 1416 "ufs/ufs/quota.h", 1417 "ufs/ufs/quota1.h", 1418 "unistd.h", 1419 "util.h", 1420 "utime.h", 1421 "mqueue.h", 1422 "netinet/dccp.h", 1423 "sys/event.h", 1424 "sys/quota.h", 1425 "sys/reboot.h", 1426 "sys/shm.h", 1427 "iconv.h", 1428 } 1429 1430 cfg.type_name(move |ty, is_struct, is_union| { 1431 match ty { 1432 // Just pass all these through, no need for a "struct" prefix 1433 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 1434 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 1435 | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(), 1436 1437 // OSX calls this something else 1438 "sighandler_t" => "sig_t".to_string(), 1439 1440 t if is_union => format!("union {t}"), 1441 1442 t if t.ends_with("_t") => t.to_string(), 1443 1444 // put `struct` in front of all structs:. 1445 t if is_struct => format!("struct {t}"), 1446 1447 t => t.to_string(), 1448 } 1449 }); 1450 1451 cfg.field_name(move |struct_, field| { 1452 match field { 1453 // Our stat *_nsec fields normally don't actually exist but are part 1454 // of a timeval struct 1455 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 1456 s.replace("e_nsec", ".tv_nsec") 1457 } 1458 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 1459 s => s.to_string(), 1460 } 1461 }); 1462 1463 cfg.skip_type(move |ty| { 1464 if ty.starts_with("__c_anonymous_") { 1465 return true; 1466 } 1467 match ty { 1468 // FIXME(netbsd): sighandler_t is crazy across platforms 1469 "sighandler_t" => true, 1470 _ => false, 1471 } 1472 }); 1473 1474 cfg.skip_struct(move |ty| { 1475 match ty { 1476 // This is actually a union, not a struct 1477 "sigval" => true, 1478 // These are tested as part of the linux_fcntl tests since there are 1479 // header conflicts when including them with all the other structs. 1480 "termios2" => true, 1481 _ => false, 1482 } 1483 }); 1484 1485 cfg.skip_signededness(move |c| { 1486 match c { 1487 "LARGE_INTEGER" | "float" | "double" => true, 1488 n if n.starts_with("pthread") => true, 1489 // sem_t is a struct or pointer 1490 "sem_t" => true, 1491 _ => false, 1492 } 1493 }); 1494 1495 cfg.skip_const(move |name| { 1496 match name { 1497 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 1498 "SIGUNUSED" => true, // removed in glibc 2.26 1499 1500 // weird signed extension or something like that? 1501 "MS_NOUSER" => true, 1502 "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 1503 "BOTHER" => true, 1504 "GRND_RANDOM" | "GRND_INSECURE" | "GRND_NONBLOCK" => true, // netbsd 10 minimum 1505 1506 _ => false, 1507 } 1508 }); 1509 1510 cfg.skip_fn(move |name| { 1511 #[expect(clippy::wildcard_in_or_patterns)] 1512 match name { 1513 // FIXME(netbsd): https://github.com/rust-lang/libc/issues/1272 1514 "execv" | "execve" | "execvp" => true, 1515 // FIXME: netbsd 10 minimum 1516 "getentropy" | "getrandom" => true, 1517 1518 "getrlimit" | "getrlimit64" | // non-int in 1st arg 1519 "setrlimit" | "setrlimit64" | // non-int in 1st arg 1520 "prlimit" | "prlimit64" | // non-int in 2nd arg 1521 1522 _ => false, 1523 } 1524 }); 1525 1526 cfg.skip_field_type(move |struct_, field| { 1527 // This is a weird union, don't check the type. 1528 (struct_ == "ifaddrs" && field == "ifa_ifu") || 1529 // sighandler_t type is super weird 1530 (struct_ == "sigaction" && field == "sa_sigaction") || 1531 // sigval is actually a union, but we pretend it's a struct 1532 (struct_ == "sigevent" && field == "sigev_value") || 1533 // aio_buf is "volatile void*" and Rust doesn't understand volatile 1534 (struct_ == "aiocb" && field == "aio_buf") 1535 }); 1536 1537 cfg.skip_field(|struct_, field| { 1538 match (struct_, field) { 1539 // conflicting with `p_type` macro from <resolve.h>. 1540 ("Elf32_Phdr", "p_type") => true, 1541 ("Elf64_Phdr", "p_type") => true, 1542 // pthread_spin_t is a volatile uchar 1543 ("pthread_spinlock_t", "pts_spin") => true, 1544 _ => false, 1545 } 1546 }); 1547 1548 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 1549 } 1550 1551 fn test_dragonflybsd(target: &str) { 1552 assert!(target.contains("dragonfly")); 1553 let mut cfg = ctest_cfg(); 1554 cfg.flag("-Wno-deprecated-declarations"); 1555 1556 headers! { 1557 cfg: 1558 "aio.h", 1559 "ctype.h", 1560 "dirent.h", 1561 "dlfcn.h", 1562 "errno.h", 1563 "execinfo.h", 1564 "fcntl.h", 1565 "fnmatch.h", 1566 "getopt.h", 1567 "glob.h", 1568 "grp.h", 1569 "ifaddrs.h", 1570 "kenv.h", 1571 "kvm.h", 1572 "langinfo.h", 1573 "libgen.h", 1574 "limits.h", 1575 "link.h", 1576 "locale.h", 1577 "mqueue.h", 1578 "net/bpf.h", 1579 "net/if.h", 1580 "net/if_arp.h", 1581 "net/if_dl.h", 1582 "net/route.h", 1583 "netdb.h", 1584 "netinet/in.h", 1585 "netinet/ip.h", 1586 "netinet/tcp.h", 1587 "netinet/udp.h", 1588 "poll.h", 1589 "pthread.h", 1590 "pthread_np.h", 1591 "pwd.h", 1592 "regex.h", 1593 "resolv.h", 1594 "sched.h", 1595 "semaphore.h", 1596 "signal.h", 1597 "stddef.h", 1598 "stdint.h", 1599 "stdio.h", 1600 "stdlib.h", 1601 "string.h", 1602 "sys/event.h", 1603 "sys/file.h", 1604 "sys/ioctl.h", 1605 "sys/cpuctl.h", 1606 "sys/eui64.h", 1607 "sys/ipc.h", 1608 "sys/kinfo.h", 1609 "sys/ktrace.h", 1610 "sys/malloc.h", 1611 "sys/mman.h", 1612 "sys/mount.h", 1613 "sys/procctl.h", 1614 "sys/ptrace.h", 1615 "sys/reboot.h", 1616 "sys/resource.h", 1617 "sys/rtprio.h", 1618 "sys/sched.h", 1619 "sys/shm.h", 1620 "sys/socket.h", 1621 "sys/stat.h", 1622 "sys/statvfs.h", 1623 "sys/sysctl.h", 1624 "sys/time.h", 1625 "sys/times.h", 1626 "sys/timex.h", 1627 "sys/types.h", 1628 "sys/checkpoint.h", 1629 "sys/uio.h", 1630 "sys/un.h", 1631 "sys/utsname.h", 1632 "sys/wait.h", 1633 "syslog.h", 1634 "termios.h", 1635 "time.h", 1636 "ucontext.h", 1637 "unistd.h", 1638 "util.h", 1639 "utime.h", 1640 "utmpx.h", 1641 "vfs/ufs/quota.h", 1642 "vm/vm_map.h", 1643 "wchar.h", 1644 "iconv.h", 1645 } 1646 1647 cfg.type_name(move |ty, is_struct, is_union| { 1648 match ty { 1649 // Just pass all these through, no need for a "struct" prefix 1650 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 1651 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 1652 | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(), 1653 1654 // FIXME(dragonflybsd): OSX calls this something else 1655 "sighandler_t" => "sig_t".to_string(), 1656 1657 t if is_union => format!("union {t}"), 1658 1659 t if t.ends_with("_t") => t.to_string(), 1660 1661 // sigval is a struct in Rust, but a union in C: 1662 "sigval" => "union sigval".to_string(), 1663 1664 // put `struct` in front of all structs:. 1665 t if is_struct => format!("struct {t}"), 1666 1667 t => t.to_string(), 1668 } 1669 }); 1670 1671 cfg.field_name(move |struct_, field| { 1672 match field { 1673 // Our stat *_nsec fields normally don't actually exist but are part 1674 // of a timeval struct 1675 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 1676 s.replace("e_nsec", ".tv_nsec") 1677 } 1678 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 1679 // Field is named `type` in C but that is a Rust keyword, 1680 // so these fields are translated to `type_` in the bindings. 1681 "type_" if struct_ == "rtprio" => "type".to_string(), 1682 s => s.to_string(), 1683 } 1684 }); 1685 1686 cfg.skip_type(move |ty| { 1687 match ty { 1688 // sighandler_t is crazy across platforms 1689 "sighandler_t" => true, 1690 _ => false, 1691 } 1692 }); 1693 1694 cfg.skip_struct(move |ty| { 1695 if ty.starts_with("__c_anonymous_") { 1696 return true; 1697 } 1698 match ty { 1699 // FIXME(dragonflybsd): These are tested as part of the linux_fcntl tests since 1700 // there are header conflicts when including them with all the other 1701 // structs. 1702 "termios2" => true, 1703 1704 _ => false, 1705 } 1706 }); 1707 1708 cfg.skip_signededness(move |c| { 1709 match c { 1710 "LARGE_INTEGER" | "float" | "double" => true, 1711 // uuid_t is a struct, not an integer. 1712 "uuid_t" => true, 1713 n if n.starts_with("pthread") => true, 1714 // sem_t is a struct or pointer 1715 "sem_t" => true, 1716 // mqd_t is a pointer on DragonFly 1717 "mqd_t" => true, 1718 1719 _ => false, 1720 } 1721 }); 1722 1723 cfg.skip_const(move |name| { 1724 match name { 1725 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 1726 1727 // weird signed extension or something like that? 1728 "MS_NOUSER" => true, 1729 "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 1730 1731 // These are defined for Solaris 11, but the crate is tested on 1732 // illumos, where they are currently not defined 1733 "EADI" | "PORT_SOURCE_POSTWAIT" | "PORT_SOURCE_SIGNAL" | "PTHREAD_STACK_MIN" => true, 1734 1735 _ => false, 1736 } 1737 }); 1738 1739 cfg.skip_fn(move |name| { 1740 // skip those that are manually verified 1741 match name { 1742 // FIXME: https://github.com/rust-lang/libc/issues/1272 1743 "execv" | "execve" | "execvp" | "fexecve" => true, 1744 1745 "getrlimit" | "getrlimit64" | // non-int in 1st arg 1746 "setrlimit" | "setrlimit64" | // non-int in 1st arg 1747 "prlimit" | "prlimit64" // non-int in 2nd arg 1748 => true, 1749 1750 _ => false, 1751 } 1752 }); 1753 1754 cfg.skip_field_type(move |struct_, field| { 1755 // This is a weird union, don't check the type. 1756 (struct_ == "ifaddrs" && field == "ifa_ifu") || 1757 // sighandler_t type is super weird 1758 (struct_ == "sigaction" && field == "sa_sigaction") || 1759 // sigval is actually a union, but we pretend it's a struct 1760 (struct_ == "sigevent" && field == "sigev_value") || 1761 // aio_buf is "volatile void*" and Rust doesn't understand volatile 1762 (struct_ == "aiocb" && field == "aio_buf") 1763 }); 1764 1765 cfg.skip_field(move |struct_, field| { 1766 // this is actually a union on linux, so we can't represent it well and 1767 // just insert some padding. 1768 (struct_ == "siginfo_t" && field == "_pad") || 1769 // sigev_notify_thread_id is actually part of a sigev_un union 1770 (struct_ == "sigevent" && field == "sigev_notify_thread_id") 1771 }); 1772 1773 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 1774 } 1775 1776 fn test_wasi(target: &str) { 1777 assert!(target.contains("wasi")); 1778 let p2 = target.contains("wasip2"); 1779 1780 let mut cfg = ctest_cfg(); 1781 cfg.define("_GNU_SOURCE", None); 1782 1783 headers! { cfg: 1784 "ctype.h", 1785 "dirent.h", 1786 "errno.h", 1787 "fcntl.h", 1788 "fnmatch.h", 1789 "langinfo.h", 1790 "limits.h", 1791 "locale.h", 1792 "malloc.h", 1793 [p2]: "netdb.h", 1794 [p2]: "netinet/in.h", 1795 [p2]: "netinet/tcp.h", 1796 "poll.h", 1797 "sched.h", 1798 "stdbool.h", 1799 "stddef.h", 1800 "stdint.h", 1801 "stdio.h", 1802 "stdlib.h", 1803 "string.h", 1804 "sys/ioctl.h", 1805 "sys/resource.h", 1806 "sys/select.h", 1807 "sys/socket.h", 1808 "sys/stat.h", 1809 "sys/times.h", 1810 "sys/types.h", 1811 "sys/uio.h", 1812 "sys/utsname.h", 1813 "time.h", 1814 "unistd.h", 1815 "wasi/api.h", 1816 "wasi/libc-find-relpath.h", 1817 "wasi/libc-nocwd.h", 1818 "wasi/libc.h", 1819 "wchar.h", 1820 } 1821 1822 // Currently `ctest2` doesn't support macros-in-static-expressions and will 1823 // panic on them. That affects `CLOCK_*` defines in wasi to set this here 1824 // to omit them. 1825 cfg.cfg("libc_ctest", None); 1826 1827 // `ctest2` has a hard-coded list of default cfgs which doesn't include 1828 // wasip2, which is why it has to be set here manually. 1829 if p2 { 1830 cfg.cfg("target_env", Some("p2")); 1831 } 1832 1833 cfg.type_name(move |ty, is_struct, is_union| match ty { 1834 "FILE" | "fd_set" | "DIR" => ty.to_string(), 1835 t if is_union => format!("union {t}"), 1836 t if t.starts_with("__wasi") && t.ends_with("_u") => format!("union {t}"), 1837 t if t.starts_with("__wasi") && is_struct => format!("struct {t}"), 1838 t if t.ends_with("_t") => t.to_string(), 1839 t if is_struct => format!("struct {t}"), 1840 t => t.to_string(), 1841 }); 1842 1843 cfg.field_name(move |_struct, field| { 1844 match field { 1845 // deal with fields as rust keywords 1846 "type_" => "type".to_string(), 1847 s => s.to_string(), 1848 } 1849 }); 1850 1851 // These have a different and internal type in header files and are only 1852 // used here to generate a pointer to them in bindings so skip these tests. 1853 cfg.skip_static(|c| c.starts_with("_CLOCK_")); 1854 1855 cfg.skip_const(|c| match c { 1856 // These constants aren't yet defined in wasi-libc. 1857 // Exposing them is being tracked by https://github.com/WebAssembly/wasi-libc/issues/531. 1858 "SO_BROADCAST" | "SO_LINGER" => true, 1859 1860 _ => false, 1861 }); 1862 1863 cfg.skip_fn(|f| match f { 1864 // This function doesn't actually exist in libc's header files 1865 "__errno_location" => true, 1866 1867 // The `timeout` argument to this function is `*const` in Rust but 1868 // mutable in C which causes a mismatch. Avoiding breakage by changing 1869 // this in wasi-libc and instead accepting that this is slightly 1870 // different. 1871 "select" => true, 1872 1873 _ => false, 1874 }); 1875 1876 // d_name is declared as a flexible array in WASI libc, so it 1877 // doesn't support sizeof. 1878 cfg.skip_field(|s, field| s == "dirent" && field == "d_name"); 1879 1880 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 1881 } 1882 1883 fn test_android(target: &str) { 1884 assert!(target.contains("android")); 1885 let target_pointer_width = match target { 1886 t if t.contains("aarch64") || t.contains("x86_64") => 64, 1887 t if t.contains("i686") || t.contains("arm") => 32, 1888 t => panic!("unsupported target: {t}"), 1889 }; 1890 let x86 = target.contains("i686") || target.contains("x86_64"); 1891 let aarch64 = target.contains("aarch64"); 1892 1893 let mut cfg = ctest_cfg(); 1894 cfg.define("_GNU_SOURCE", None); 1895 1896 headers! { cfg: 1897 "arpa/inet.h", 1898 "ctype.h", 1899 "dirent.h", 1900 "dlfcn.h", 1901 "elf.h", 1902 "errno.h", 1903 "fcntl.h", 1904 "fnmatch.h", 1905 "getopt.h", 1906 "grp.h", 1907 "ifaddrs.h", 1908 "libgen.h", 1909 "limits.h", 1910 "link.h", 1911 "linux/sysctl.h", 1912 "locale.h", 1913 "malloc.h", 1914 "net/ethernet.h", 1915 "net/if.h", 1916 "net/if_arp.h", 1917 "net/route.h", 1918 "netdb.h", 1919 "netinet/in.h", 1920 "netinet/ip.h", 1921 "netinet/tcp.h", 1922 "netinet/udp.h", 1923 "netpacket/packet.h", 1924 "poll.h", 1925 "pthread.h", 1926 "pty.h", 1927 "pwd.h", 1928 "regex.h", 1929 "resolv.h", 1930 "sched.h", 1931 "semaphore.h", 1932 "signal.h", 1933 "spawn.h", 1934 "stddef.h", 1935 "stdint.h", 1936 "stdio.h", 1937 "stdlib.h", 1938 "string.h", 1939 "sys/auxv.h", 1940 "sys/epoll.h", 1941 "sys/eventfd.h", 1942 "sys/file.h", 1943 "sys/fsuid.h", 1944 "sys/inotify.h", 1945 "sys/ioctl.h", 1946 "sys/klog.h", 1947 "sys/mman.h", 1948 "sys/mount.h", 1949 "sys/personality.h", 1950 "sys/prctl.h", 1951 "sys/ptrace.h", 1952 "sys/random.h", 1953 "sys/reboot.h", 1954 "sys/resource.h", 1955 "sys/sendfile.h", 1956 "sys/signalfd.h", 1957 "sys/socket.h", 1958 "sys/stat.h", 1959 "sys/statvfs.h", 1960 "sys/swap.h", 1961 "sys/syscall.h", 1962 "sys/sysinfo.h", 1963 "sys/system_properties.h", 1964 "sys/time.h", 1965 "sys/timerfd.h", 1966 "sys/times.h", 1967 "sys/types.h", 1968 "sys/ucontext.h", 1969 "sys/uio.h", 1970 "sys/un.h", 1971 "sys/user.h", 1972 "sys/utsname.h", 1973 "sys/vfs.h", 1974 "sys/xattr.h", 1975 "sys/wait.h", 1976 "syslog.h", 1977 "termios.h", 1978 "time.h", 1979 "unistd.h", 1980 "utime.h", 1981 "utmp.h", 1982 "wchar.h", 1983 "xlocale.h", 1984 // time64_t is not defined for 64-bit targets If included it will 1985 // generate the error 'Your time_t is already 64-bit' 1986 [target_pointer_width == 32]: "time64.h", 1987 [x86]: "sys/reg.h", 1988 } 1989 1990 // Include linux headers at the end: 1991 headers! { cfg: 1992 "asm/mman.h", 1993 "linux/auxvec.h", 1994 "linux/dccp.h", 1995 "linux/elf.h", 1996 "linux/errqueue.h", 1997 "linux/falloc.h", 1998 "linux/filter.h", 1999 "linux/futex.h", 2000 "linux/fs.h", 2001 "linux/genetlink.h", 2002 "linux/if_alg.h", 2003 "linux/if_addr.h", 2004 "linux/if_ether.h", 2005 "linux/if_link.h", 2006 "linux/rtnetlink.h", 2007 "linux/if_tun.h", 2008 "linux/kexec.h", 2009 "linux/magic.h", 2010 "linux/membarrier.h", 2011 "linux/memfd.h", 2012 "linux/mempolicy.h", 2013 "linux/module.h", 2014 "linux/mount.h", 2015 "linux/net_tstamp.h", 2016 "linux/netfilter/nfnetlink.h", 2017 "linux/netfilter/nfnetlink_log.h", 2018 "linux/netfilter/nfnetlink_queue.h", 2019 "linux/netfilter/nf_tables.h", 2020 "linux/netfilter_arp.h", 2021 "linux/netfilter_bridge.h", 2022 "linux/netfilter_ipv4.h", 2023 "linux/netfilter_ipv6.h", 2024 "linux/netfilter_ipv6/ip6_tables.h", 2025 "linux/netlink.h", 2026 "linux/quota.h", 2027 "linux/reboot.h", 2028 "linux/seccomp.h", 2029 "linux/sched.h", 2030 "linux/sockios.h", 2031 "linux/uinput.h", 2032 "linux/vm_sockets.h", 2033 "linux/wait.h", 2034 2035 } 2036 2037 // Include Android-specific headers: 2038 headers! { cfg: 2039 "android/set_abort_message.h" 2040 } 2041 2042 cfg.type_name(move |ty, is_struct, is_union| { 2043 match ty { 2044 // Just pass all these through, no need for a "struct" prefix 2045 "FILE" | "fd_set" | "Dl_info" | "Elf32_Phdr" | "Elf64_Phdr" => ty.to_string(), 2046 2047 t if is_union => format!("union {t}"), 2048 2049 t if t.ends_with("_t") => t.to_string(), 2050 2051 // sigval is a struct in Rust, but a union in C: 2052 "sigval" => "union sigval".to_string(), 2053 2054 // put `struct` in front of all structs:. 2055 t if is_struct => format!("struct {t}"), 2056 2057 t => t.to_string(), 2058 } 2059 }); 2060 2061 cfg.field_name(move |struct_, field| { 2062 match field { 2063 // Our stat *_nsec fields normally don't actually exist but are part 2064 // of a timeval struct 2065 s if s.ends_with("_nsec") && struct_.starts_with("stat") => s.to_string(), 2066 // FIXME(union): appears that `epoll_event.data` is an union 2067 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 2068 // The following structs have a field called `type` in C, 2069 // but `type` is a Rust keyword, so these fields are translated 2070 // to `type_` in Rust. 2071 "type_" 2072 if struct_ == "input_event" 2073 || struct_ == "input_mask" 2074 || struct_ == "ff_effect" => 2075 { 2076 "type".to_string() 2077 } 2078 2079 s => s.to_string(), 2080 } 2081 }); 2082 2083 cfg.skip_type(move |ty| { 2084 match ty { 2085 // FIXME(android): `sighandler_t` type is incorrect, see: 2086 // https://github.com/rust-lang/libc/issues/1359 2087 "sighandler_t" => true, 2088 2089 // These are tested in the `linux_elf.rs` file. 2090 "Elf64_Phdr" | "Elf32_Phdr" => true, 2091 2092 // These are intended to be opaque 2093 "posix_spawn_file_actions_t" => true, 2094 "posix_spawnattr_t" => true, 2095 2096 // FIXME(android): "'__uint128' undeclared" in C 2097 "__uint128" => true, 2098 // Added in API level 24 2099 "if_nameindex" => true, 2100 2101 _ => false, 2102 } 2103 }); 2104 2105 cfg.skip_struct(move |ty| { 2106 if ty.starts_with("__c_anonymous_") { 2107 return true; 2108 } 2109 match ty { 2110 // These are tested as part of the linux_fcntl tests since there are 2111 // header conflicts when including them with all the other structs. 2112 "termios2" => true, 2113 // uc_sigmask and uc_sigmask64 of ucontext_t are an anonymous union 2114 "ucontext_t" => true, 2115 // 'private' type 2116 "prop_info" => true, 2117 2118 // These are tested in the `linux_elf.rs` file. 2119 "Elf64_Phdr" | "Elf32_Phdr" => true, 2120 2121 // FIXME(android): The type of `iv` has been changed. 2122 "af_alg_iv" => true, 2123 2124 // FIXME(android): The size of struct has been changed: 2125 "inotify_event" => true, 2126 // FIXME(android): The field has been changed: 2127 "sockaddr_vm" => true, 2128 2129 _ => false, 2130 } 2131 }); 2132 2133 cfg.skip_const(move |name| { 2134 match name { 2135 // The IPV6 constants are tested in the `linux_ipv6.rs` tests: 2136 | "IPV6_FLOWINFO" 2137 | "IPV6_FLOWLABEL_MGR" 2138 | "IPV6_FLOWINFO_SEND" 2139 | "IPV6_FLOWINFO_FLOWLABEL" 2140 | "IPV6_FLOWINFO_PRIORITY" 2141 // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: 2142 | "F_CANCELLK" 2143 | "F_ADD_SEALS" 2144 | "F_GET_SEALS" 2145 | "F_SEAL_SEAL" 2146 | "F_SEAL_SHRINK" 2147 | "F_SEAL_GROW" 2148 | "F_SEAL_WRITE" => true, 2149 2150 // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests: 2151 "ARPHRD_CAN" => true, 2152 2153 // FIXME(deprecated): deprecated: not available in any header 2154 // See: https://github.com/rust-lang/libc/issues/1356 2155 "ENOATTR" => true, 2156 2157 // FIXME(android): still necessary? 2158 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 2159 // FIXME(deprecated): deprecated - removed in glibc 2.26 2160 "SIGUNUSED" => true, 2161 2162 // Needs a newer Android SDK for the definition 2163 "P_PIDFD" => true, 2164 2165 // Requires Linux kernel 5.6 2166 "VMADDR_CID_LOCAL" => true, 2167 2168 // FIXME(android): conflicts with standard C headers and is tested in 2169 // `linux_termios.rs` below: 2170 "BOTHER" => true, 2171 "IBSHIFT" => true, 2172 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => true, 2173 2174 // is a private value for kernel usage normally 2175 "FUSE_SUPER_MAGIC" => true, 2176 // linux 5.12 min 2177 "MPOL_F_NUMA_BALANCING" => true, 2178 2179 // GRND_INSECURE was added in platform-tools-30.0.0 2180 "GRND_INSECURE" => true, 2181 2182 // kernel 5.10 minimum required 2183 "MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ" | "MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ" => true, 2184 2185 // kernel 5.18 minimum 2186 | "MADV_COLD" 2187 | "MADV_DONTNEED_LOCKED" 2188 | "MADV_PAGEOUT" 2189 | "MADV_POPULATE_READ" 2190 | "MADV_POPULATE_WRITE" => true, 2191 2192 // kernel 5.6 minimum required 2193 "IPPROTO_MPTCP" | "IPPROTO_ETHERNET" => true, 2194 2195 // kernel 6.2 minimum 2196 "TUN_F_USO4" | "TUN_F_USO6" | "IFF_NO_CARRIER" => true, 2197 2198 // FIXME(android): NDK r22 minimum required 2199 | "FDB_NOTIFY_BIT" 2200 | "FDB_NOTIFY_INACTIVE_BIT" 2201 | "IFLA_ALT_IFNAME" 2202 | "IFLA_PERM_ADDRESS" 2203 | "IFLA_PROP_LIST" 2204 | "IFLA_PROTO_DOWN_REASON" 2205 | "NDA_FDB_EXT_ATTRS" 2206 | "NDA_NH_ID" 2207 | "NFEA_ACTIVITY_NOTIFY" 2208 | "NFEA_DONT_REFRESH" 2209 | "NFEA_UNSPEC" => true, 2210 2211 // FIXME(android): NDK r23 minimum required 2212 | "IFLA_PARENT_DEV_BUS_NAME" 2213 | "IFLA_PARENT_DEV_NAME" => true, 2214 2215 // FIXME(android): NDK r25 minimum required 2216 | "IFLA_GRO_MAX_SIZE" 2217 | "NDA_FLAGS_EXT" 2218 | "NTF_EXT_MANAGED" => true, 2219 2220 // FIXME(android): NDK above r25 required 2221 | "IFLA_ALLMULTI" 2222 | "IFLA_DEVLINK_PORT" 2223 | "IFLA_GRO_IPV4_MAX_SIZE" 2224 | "IFLA_GSO_IPV4_MAX_SIZE" 2225 | "IFLA_TSO_MAX_SEGS" 2226 | "IFLA_TSO_MAX_SIZE" 2227 | "NDA_NDM_STATE_MASK" 2228 | "NDA_NDM_FLAGS_MASK" 2229 | "NDTPA_INTERVAL_PROBE_TIME_MS" 2230 | "NFQA_UNSPEC" 2231 | "NTF_EXT_LOCKED" 2232 | "ALG_SET_DRBG_ENTROPY" => true, 2233 2234 // FIXME(android): Something has been changed on r26b: 2235 | "IPPROTO_MAX" 2236 | "NFNL_SUBSYS_COUNT" 2237 | "NF_NETDEV_NUMHOOKS" 2238 | "NFT_MSG_MAX" 2239 | "SW_MAX" 2240 | "SW_CNT" => true, 2241 2242 // FIXME(android): aarch64 env cannot find it: 2243 | "PTRACE_GETREGS" 2244 | "PTRACE_SETREGS" if aarch64 => true, 2245 // FIXME(android): The value has been changed on r26b: 2246 | "SYS_syscalls" if aarch64 => true, 2247 2248 // From `<include/linux/sched.h>`. 2249 | "PF_VCPU" 2250 | "PF_IDLE" 2251 | "PF_EXITING" 2252 | "PF_POSTCOREDUMP" 2253 | "PF_IO_WORKER" 2254 | "PF_WQ_WORKER" 2255 | "PF_FORKNOEXEC" 2256 | "PF_MCE_PROCESS" 2257 | "PF_SUPERPRIV" 2258 | "PF_DUMPCORE" 2259 | "PF_SIGNALED" 2260 | "PF_MEMALLOC" 2261 | "PF_NPROC_EXCEEDED" 2262 | "PF_USED_MATH" 2263 | "PF_USER_WORKER" 2264 | "PF_NOFREEZE" 2265 | "PF_KSWAPD" 2266 | "PF_MEMALLOC_NOFS" 2267 | "PF_MEMALLOC_NOIO" 2268 | "PF_LOCAL_THROTTLE" 2269 | "PF_KTHREAD" 2270 | "PF_RANDOMIZE" 2271 | "PF_NO_SETAFFINITY" 2272 | "PF_MCE_EARLY" 2273 | "PF_MEMALLOC_PIN" 2274 | "PF_BLOCK_TS" 2275 | "PF_SUSPEND_TASK" => true, 2276 2277 // FIXME(android): Requires >= 6.12 kernel headers. 2278 "SOF_TIMESTAMPING_OPT_RX_FILTER" => true, 2279 2280 _ => false, 2281 } 2282 }); 2283 2284 cfg.skip_fn(move |name| { 2285 // skip those that are manually verified 2286 match name { 2287 // FIXME(android): https://github.com/rust-lang/libc/issues/1272 2288 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2289 2290 // There are two versions of the sterror_r function, see 2291 // 2292 // https://linux.die.net/man/3/strerror_r 2293 // 2294 // An XSI-compliant version provided if: 2295 // 2296 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE 2297 // 2298 // and a GNU specific version provided if _GNU_SOURCE is defined. 2299 // 2300 // libc provides bindings for the XSI-compliant version, which is 2301 // preferred for portable applications. 2302 // 2303 // We skip the test here since here _GNU_SOURCE is defined, and 2304 // test the XSI version below. 2305 "strerror_r" => true, 2306 "reallocarray" => true, 2307 "__system_property_wait" => true, 2308 2309 // Added in API level 30, but tests use level 28. 2310 "memfd_create" | "mlock2" | "renameat2" | "statx" | "statx_timestamp" => true, 2311 2312 // Added in glibc 2.25. 2313 "getentropy" => true, 2314 2315 // Added in API level 28, but some tests use level 24. 2316 "getrandom" => true, 2317 2318 // Added in API level 28, but some tests use level 24. 2319 "syncfs" => true, 2320 2321 // Added in API level 28, but some tests use level 24. 2322 "pthread_attr_getinheritsched" | "pthread_attr_setinheritsched" => true, 2323 // Added in API level 28, but some tests use level 24. 2324 "fread_unlocked" | "fwrite_unlocked" | "fgets_unlocked" | "fflush_unlocked" => true, 2325 2326 // Added in API level 28, but some tests use level 24. 2327 "aligned_alloc" => true, 2328 2329 // Added in API level 26, but some tests use level 24. 2330 "getgrent" => true, 2331 2332 // Added in API level 26, but some tests use level 24. 2333 "setgrent" => true, 2334 2335 // Added in API level 26, but some tests use level 24. 2336 "endgrent" => true, 2337 2338 // Added in API level 26, but some tests use level 24. 2339 "getdomainname" | "setdomainname" => true, 2340 2341 // FIXME(android): bad function pointers: 2342 "isalnum" | "isalpha" | "iscntrl" | "isdigit" | "isgraph" | "islower" | "isprint" 2343 | "ispunct" | "isspace" | "isupper" | "isxdigit" | "isblank" | "tolower" 2344 | "toupper" => true, 2345 2346 // Added in API level 24 2347 "if_nameindex" | "if_freenameindex" => true, 2348 2349 _ => false, 2350 } 2351 }); 2352 2353 cfg.skip_field_type(move |struct_, field| { 2354 // This is a weird union, don't check the type. 2355 (struct_ == "ifaddrs" && field == "ifa_ifu") || 2356 // sigval is actually a union, but we pretend it's a struct 2357 (struct_ == "sigevent" && field == "sigev_value") || 2358 // this one is an anonymous union 2359 (struct_ == "ff_effect" && field == "u") || 2360 // FIXME(android): `sa_sigaction` has type `sighandler_t` but that type is 2361 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 2362 (struct_ == "sigaction" && field == "sa_sigaction") || 2363 // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet. 2364 (struct_ == "signalfd_siginfo" && field == "ssi_call_addr") || 2365 // FIXME(android): Seems the type has been changed on NDK r26b 2366 (struct_ == "flock64" && (field == "l_start" || field == "l_len")) 2367 }); 2368 2369 cfg.skip_field(|struct_, field| { 2370 match (struct_, field) { 2371 // conflicting with `p_type` macro from <resolve.h>. 2372 ("Elf32_Phdr", "p_type") => true, 2373 ("Elf64_Phdr", "p_type") => true, 2374 2375 // this is actually a union on linux, so we can't represent it well and 2376 // just insert some padding. 2377 ("siginfo_t", "_pad") => true, 2378 ("ifreq", "ifr_ifru") => true, 2379 ("ifconf", "ifc_ifcu") => true, 2380 2381 _ => false, 2382 } 2383 }); 2384 2385 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 2386 2387 test_linux_like_apis(target); 2388 } 2389 2390 fn test_freebsd(target: &str) { 2391 assert!(target.contains("freebsd")); 2392 let mut cfg = ctest_cfg(); 2393 2394 let freebsd_ver = which_freebsd(); 2395 2396 match freebsd_ver { 2397 Some(12) => cfg.cfg("freebsd12", None), 2398 Some(13) => cfg.cfg("freebsd13", None), 2399 Some(14) => cfg.cfg("freebsd14", None), 2400 Some(15) => cfg.cfg("freebsd15", None), 2401 _ => &mut cfg, 2402 }; 2403 2404 // For sched linux compat fn 2405 cfg.define("_WITH_CPU_SET_T", None); 2406 // Required for `getline`: 2407 cfg.define("_WITH_GETLINE", None); 2408 // Required for making freebsd11_stat available in the headers 2409 cfg.define("_WANT_FREEBSD11_STAT", None); 2410 2411 let freebsd13 = matches!(freebsd_ver, Some(n) if n >= 13); 2412 let freebsd14 = matches!(freebsd_ver, Some(n) if n >= 14); 2413 let freebsd15 = matches!(freebsd_ver, Some(n) if n >= 15); 2414 2415 headers! { cfg: 2416 "aio.h", 2417 "arpa/inet.h", 2418 "bsm/audit.h", 2419 "ctype.h", 2420 "dirent.h", 2421 "dlfcn.h", 2422 "elf.h", 2423 "errno.h", 2424 "execinfo.h", 2425 "fcntl.h", 2426 "fnmatch.h", 2427 "getopt.h", 2428 "glob.h", 2429 "grp.h", 2430 "iconv.h", 2431 "ifaddrs.h", 2432 "kenv.h", 2433 "langinfo.h", 2434 "libgen.h", 2435 "libutil.h", 2436 "limits.h", 2437 "link.h", 2438 "locale.h", 2439 "machine/elf.h", 2440 "machine/reg.h", 2441 "malloc_np.h", 2442 "memstat.h", 2443 "mqueue.h", 2444 "net/bpf.h", 2445 "net/if.h", 2446 "net/if_arp.h", 2447 "net/if_dl.h", 2448 "net/if_mib.h", 2449 "net/route.h", 2450 "netdb.h", 2451 "netinet/ip.h", 2452 "netinet/in.h", 2453 "netinet/sctp.h", 2454 "netinet/tcp.h", 2455 "netinet/udp.h", 2456 "poll.h", 2457 "pthread.h", 2458 "pthread_np.h", 2459 "pwd.h", 2460 "regex.h", 2461 "resolv.h", 2462 "sched.h", 2463 "semaphore.h", 2464 "signal.h", 2465 "spawn.h", 2466 "stddef.h", 2467 "stdint.h", 2468 "stdio.h", 2469 "stdlib.h", 2470 "string.h", 2471 "sys/capsicum.h", 2472 "sys/auxv.h", 2473 "sys/cpuset.h", 2474 "sys/domainset.h", 2475 "sys/eui64.h", 2476 "sys/event.h", 2477 [freebsd13]:"sys/eventfd.h", 2478 "sys/extattr.h", 2479 "sys/file.h", 2480 "sys/ioctl.h", 2481 "sys/ipc.h", 2482 "sys/jail.h", 2483 "sys/mman.h", 2484 "sys/mount.h", 2485 "sys/msg.h", 2486 "sys/procctl.h", 2487 "sys/procdesc.h", 2488 "sys/ptrace.h", 2489 "sys/queue.h", 2490 "sys/random.h", 2491 "sys/reboot.h", 2492 "sys/resource.h", 2493 "sys/rtprio.h", 2494 "sys/sem.h", 2495 "sys/shm.h", 2496 "sys/socket.h", 2497 "sys/stat.h", 2498 "sys/statvfs.h", 2499 "sys/sysctl.h", 2500 "sys/thr.h", 2501 "sys/time.h", 2502 [freebsd14 || freebsd15]:"sys/timerfd.h", 2503 [freebsd13 || freebsd14 || freebsd15]:"dev/evdev/input.h", 2504 "sys/times.h", 2505 "sys/timex.h", 2506 "sys/types.h", 2507 "sys/proc.h", 2508 "kvm.h", // must be after "sys/types.h" 2509 "sys/ucontext.h", 2510 "sys/uio.h", 2511 "sys/ktrace.h", 2512 "sys/umtx.h", 2513 "sys/un.h", 2514 "sys/user.h", 2515 "sys/utsname.h", 2516 "sys/uuid.h", 2517 "sys/vmmeter.h", 2518 "sys/wait.h", 2519 "libprocstat.h", 2520 "devstat.h", 2521 "syslog.h", 2522 "termios.h", 2523 "time.h", 2524 "ufs/ufs/quota.h", 2525 "unistd.h", 2526 "utime.h", 2527 "utmpx.h", 2528 "wchar.h", 2529 } 2530 2531 cfg.type_name(move |ty, is_struct, is_union| { 2532 match ty { 2533 // Just pass all these through, no need for a "struct" prefix 2534 "FILE" 2535 | "fd_set" 2536 | "Dl_info" 2537 | "DIR" 2538 | "Elf32_Phdr" 2539 | "Elf64_Phdr" 2540 | "Elf32_Auxinfo" 2541 | "Elf64_Auxinfo" 2542 | "devstat_select_mode" 2543 | "devstat_support_flags" 2544 | "devstat_type_flags" 2545 | "devstat_match_flags" 2546 | "devstat_priority" => ty.to_string(), 2547 2548 // FIXME(freebsd): https://github.com/rust-lang/libc/issues/1273 2549 "sighandler_t" => "sig_t".to_string(), 2550 2551 t if is_union => format!("union {t}"), 2552 2553 t if t.ends_with("_t") => t.to_string(), 2554 2555 // sigval is a struct in Rust, but a union in C: 2556 "sigval" => "union sigval".to_string(), 2557 2558 // put `struct` in front of all structs:. 2559 t if is_struct => format!("struct {t}"), 2560 2561 t => t.to_string(), 2562 } 2563 }); 2564 2565 cfg.field_name(move |struct_, field| { 2566 match field { 2567 // Our stat *_nsec fields normally don't actually exist but are part 2568 // of a timeval struct 2569 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2570 s.replace("e_nsec", ".tv_nsec") 2571 } 2572 // Field is named `type` in C but that is a Rust keyword, 2573 // so these fields are translated to `type_` in the bindings. 2574 "type_" if struct_ == "rtprio" => "type".to_string(), 2575 "type_" if struct_ == "sockstat" => "type".to_string(), 2576 "type_" if struct_ == "devstat_match_table" => "type".to_string(), 2577 "type_" if struct_ == "input_event" => "type".to_string(), 2578 s => s.to_string(), 2579 } 2580 }); 2581 2582 cfg.skip_const(move |name| { 2583 match name { 2584 // These constants were introduced in FreeBSD 13: 2585 "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" 2586 | "F_SEAL_WRITE" 2587 if Some(13) > freebsd_ver => 2588 { 2589 true 2590 } 2591 2592 // These constants were introduced in FreeBSD 13: 2593 "EFD_CLOEXEC" | "EFD_NONBLOCK" | "EFD_SEMAPHORE" if Some(13) > freebsd_ver => true, 2594 2595 // These constants were introduced in FreeBSD 12: 2596 "AT_RESOLVE_BENEATH" | "O_RESOLVE_BENEATH" if Some(12) > freebsd_ver => true, 2597 2598 // These constants were introduced in FreeBSD 13: 2599 "O_DSYNC" | "O_PATH" | "O_EMPTY_PATH" | "AT_EMPTY_PATH" if Some(13) > freebsd_ver => { 2600 true 2601 } 2602 2603 // These aliases were introduced in FreeBSD 13: 2604 // (note however that the constants themselves work on any version) 2605 "CLOCK_BOOTTIME" | "CLOCK_REALTIME_COARSE" | "CLOCK_MONOTONIC_COARSE" 2606 if Some(13) > freebsd_ver => 2607 { 2608 true 2609 } 2610 2611 // FIXME(deprecated): These are deprecated - remove in a couple of releases. 2612 // These constants were removed in FreeBSD 11 (svn r273250) but will 2613 // still be accepted and ignored at runtime. 2614 "MAP_RENAME" | "MAP_NORESERVE" => true, 2615 2616 // FIXME(deprecated): These are deprecated - remove in a couple of releases. 2617 // These constants were removed in FreeBSD 11 (svn r262489), 2618 // and they've never had any legitimate use outside of the 2619 // base system anyway. 2620 "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "USER_MAXID" => true, 2621 2622 // Deprecated and removed in FreeBSD 15. It was never actually implemented. 2623 "TCP_MAXPEAKRATE" => true, 2624 2625 // FIXME: This is deprecated - remove in a couple of releases. 2626 // This was removed in FreeBSD 14 (git 1b4701fe1e8) and never 2627 // should've been used anywhere anyway. 2628 "TDF_UNUSED23" => true, 2629 2630 // Removed in FreeBSD 15 2631 "TDF_CANSWAP" | "TDF_SWAPINREQ" => true, 2632 2633 // Unaccessible in FreeBSD 15 2634 "TDI_SWAPPED" | "P_SWAPPINGOUT" | "P_SWAPPINGIN" => true, 2635 2636 // Removed in FreeBSD 14 (git a6b55ee6be1) 2637 "IFF_KNOWSEPOCH" => true, 2638 2639 // Removed in FreeBSD 14 (git 7ff9ae90f0b) 2640 "IFF_NOGROUP" => true, 2641 2642 // FIXME(deprecated): These are deprecated - remove in a couple of releases. 2643 // These symbols are not stable across OS-versions. They were 2644 // changed for FreeBSD 14 in git revisions b62848b0c3f and 2645 // 2cf7870864e. 2646 "PRI_MAX_ITHD" | "PRI_MIN_REALTIME" | "PRI_MAX_REALTIME" | "PRI_MIN_KERN" 2647 | "PRI_MAX_KERN" | "PSWP" | "PVM" | "PINOD" | "PRIBIO" | "PVFS" | "PZERO" | "PSOCK" 2648 | "PWAIT" | "PLOCK" | "PPAUSE" | "PRI_MIN_TIMESHARE" | "PUSER" | "PI_AV" | "PI_NET" 2649 | "PI_DISK" | "PI_TTY" | "PI_DULL" | "PI_SOFT" => true, 2650 2651 // This constant changed in FreeBSD 15 (git 3458bbd397783). It was never intended to 2652 // be stable, and probably shouldn't be bound by libc at all. 2653 "RLIM_NLIMITS" => true, 2654 2655 // This symbol changed in FreeBSD 14 (git 051e7d78b03), but the new 2656 // version should be safe to use on older releases. 2657 "IFCAP_CANTCHANGE" => true, 2658 2659 // These were removed in FreeBSD 14 (git c6d31b8306e) 2660 "TDF_ASTPENDING" | "TDF_NEEDSUSPCHK" | "TDF_NEEDRESCHED" | "TDF_NEEDSIGCHK" 2661 | "TDF_ALRMPEND" | "TDF_PROFPEND" | "TDF_MACPEND" => true, 2662 2663 // This constant was removed in FreeBSD 13 (svn r363622), and never 2664 // had any legitimate use outside of the base system anyway. 2665 "CTL_P1003_1B_MAXID" => true, 2666 2667 // This was renamed in FreeBSD 12.2 and 13 (r352486). 2668 "CTL_UNSPEC" | "CTL_SYSCTL" => true, 2669 2670 // This was renamed in FreeBSD 12.2 and 13 (r350749). 2671 "IPPROTO_SEP" | "IPPROTO_DCCP" => true, 2672 2673 // This was changed to 96(0x60) in FreeBSD 13: 2674 // https://github.com/freebsd/freebsd/ 2675 // commit/06b00ceaa914a3907e4e27bad924f44612bae1d7 2676 "MINCORE_SUPER" if Some(13) <= freebsd_ver => true, 2677 2678 // Added in FreeBSD 13.0 (r356667) 2679 "GRND_INSECURE" if Some(13) > freebsd_ver => true, 2680 2681 // Added in FreeBSD 13.0 (r349609) 2682 "PROC_PROTMAX_CTL" 2683 | "PROC_PROTMAX_STATUS" 2684 | "PROC_PROTMAX_FORCE_ENABLE" 2685 | "PROC_PROTMAX_FORCE_DISABLE" 2686 | "PROC_PROTMAX_NOFORCE" 2687 | "PROC_PROTMAX_ACTIVE" 2688 | "PROC_NO_NEW_PRIVS_CTL" 2689 | "PROC_NO_NEW_PRIVS_STATUS" 2690 | "PROC_NO_NEW_PRIVS_ENABLE" 2691 | "PROC_NO_NEW_PRIVS_DISABLE" 2692 | "PROC_WXMAP_CTL" 2693 | "PROC_WXMAP_STATUS" 2694 | "PROC_WX_MAPPINGS_PERMIT" 2695 | "PROC_WX_MAPPINGS_DISALLOW_EXEC" 2696 | "PROC_WXORX_ENFORCE" 2697 if Some(13) > freebsd_ver => 2698 { 2699 true 2700 } 2701 2702 // Added in FreeBSD 13.0 (r367776 and r367287) 2703 "SCM_CREDS2" | "LOCAL_CREDS_PERSISTENT" if Some(13) > freebsd_ver => true, 2704 2705 // Added in FreeBSD 14 2706 "SPACECTL_DEALLOC" if Some(14) > freebsd_ver => true, 2707 2708 // Added in FreeBSD 13. 2709 "KERN_PROC_SIGFASTBLK" 2710 | "USER_LOCALBASE" 2711 | "TDP_SIGFASTBLOCK" 2712 | "TDP_UIOHELD" 2713 | "TDP_SIGFASTPENDING" 2714 | "TDP2_COMPAT32RB" 2715 | "P2_PROTMAX_ENABLE" 2716 | "P2_PROTMAX_DISABLE" 2717 | "CTLFLAG_NEEDGIANT" 2718 | "CTL_SYSCTL_NEXTNOSKIP" 2719 if Some(13) > freebsd_ver => 2720 { 2721 true 2722 } 2723 2724 // Added in freebsd 14. 2725 "IFCAP_MEXTPG" if Some(14) > freebsd_ver => true, 2726 // Added in freebsd 13. 2727 "IFCAP_TXTLS4" | "IFCAP_TXTLS6" | "IFCAP_VXLAN_HWCSUM" | "IFCAP_VXLAN_HWTSO" 2728 | "IFCAP_TXTLS_RTLMT" | "IFCAP_TXTLS" 2729 if Some(13) > freebsd_ver => 2730 { 2731 true 2732 } 2733 // Added in FreeBSD 13. 2734 "PS_FST_TYPE_EVENTFD" if Some(13) > freebsd_ver => true, 2735 2736 // Added in FreeBSD 14. 2737 "MNT_RECURSE" | "MNT_DEFERRED" if Some(14) > freebsd_ver => true, 2738 2739 // Added in FreeBSD 13. 2740 "MNT_EXTLS" | "MNT_EXTLSCERT" | "MNT_EXTLSCERTUSER" | "MNT_NOCOVER" 2741 | "MNT_EMPTYDIR" 2742 if Some(13) > freebsd_ver => 2743 { 2744 true 2745 } 2746 2747 // Added in FreeBSD 14. 2748 "PT_COREDUMP" | "PC_ALL" | "PC_COMPRESS" | "PT_GETREGSET" | "PT_SETREGSET" 2749 | "PT_SC_REMOTE" 2750 if Some(14) > freebsd_ver => 2751 { 2752 true 2753 } 2754 2755 // Added in FreeBSD 14. 2756 "F_KINFO" => true, // FIXME(freebsd): depends how frequent freebsd 14 is updated on CI, this addition went this week only. 2757 "SHM_RENAME_NOREPLACE" 2758 | "SHM_RENAME_EXCHANGE" 2759 | "SHM_LARGEPAGE_ALLOC_DEFAULT" 2760 | "SHM_LARGEPAGE_ALLOC_NOWAIT" 2761 | "SHM_LARGEPAGE_ALLOC_HARD" 2762 | "MFD_CLOEXEC" 2763 | "MFD_ALLOW_SEALING" 2764 | "MFD_HUGETLB" 2765 | "MFD_HUGE_MASK" 2766 | "MFD_HUGE_64KB" 2767 | "MFD_HUGE_512KB" 2768 | "MFD_HUGE_1MB" 2769 | "MFD_HUGE_2MB" 2770 | "MFD_HUGE_8MB" 2771 | "MFD_HUGE_16MB" 2772 | "MFD_HUGE_32MB" 2773 | "MFD_HUGE_256MB" 2774 | "MFD_HUGE_512MB" 2775 | "MFD_HUGE_1GB" 2776 | "MFD_HUGE_2GB" 2777 | "MFD_HUGE_16GB" 2778 if Some(13) > freebsd_ver => 2779 { 2780 true 2781 } 2782 2783 // Flags introduced in FreeBSD 14. 2784 "TCP_MAXUNACKTIME" 2785 | "TCP_IDLE_REDUCE" 2786 | "TCP_REMOTE_UDP_ENCAPS_PORT" 2787 | "TCP_DELACK" 2788 | "TCP_FIN_IS_RST" 2789 | "TCP_LOG_LIMIT" 2790 | "TCP_SHARED_CWND_ALLOWED" 2791 | "TCP_PROC_ACCOUNTING" 2792 | "TCP_USE_CMP_ACKS" 2793 | "TCP_PERF_INFO" 2794 | "TCP_LRD" 2795 if Some(14) > freebsd_ver => 2796 { 2797 true 2798 } 2799 2800 // Introduced in FreeBSD 14 then removed ? 2801 "TCP_LRD" if freebsd_ver >= Some(15) => true, 2802 2803 // Added in FreeBSD 14 2804 "LIO_READV" | "LIO_WRITEV" | "LIO_VECTORED" if Some(14) > freebsd_ver => true, 2805 2806 // Added in FreeBSD 13 2807 "FIOSSHMLPGCNF" if Some(13) > freebsd_ver => true, 2808 2809 // Added in FreeBSD 14 2810 "IFCAP_NV" if Some(14) > freebsd_ver => true, 2811 2812 // FIXME(freebsd): Removed in https://reviews.freebsd.org/D38574 and https://reviews.freebsd.org/D38822 2813 // We maybe should deprecate them once a stable release ships them. 2814 "IP_BINDMULTI" | "IP_RSS_LISTEN_BUCKET" => true, 2815 2816 // FIXME(freebsd): Removed in https://reviews.freebsd.org/D39127. 2817 "KERN_VNODE" => true, 2818 2819 // Added in FreeBSD 14 2820 "EV_KEEPUDATA" if Some(14) > freebsd_ver => true, 2821 2822 // Added in FreeBSD 13.2 2823 "AT_USRSTACKBASE" | "AT_USRSTACKLIM" if Some(13) > freebsd_ver => true, 2824 2825 // Added in FreeBSD 14 2826 "TFD_CLOEXEC" | "TFD_NONBLOCK" | "TFD_TIMER_ABSTIME" | "TFD_TIMER_CANCEL_ON_SET" 2827 if Some(14) > freebsd_ver => 2828 { 2829 true 2830 } 2831 2832 // Added in FreeBSD 14.1 2833 "KCMP_FILE" | "KCMP_FILEOBJ" | "KCMP_FILES" | "KCMP_SIGHAND" | "KCMP_VM" 2834 if Some(14) > freebsd_ver => 2835 { 2836 true 2837 } 2838 2839 // FIXME(freebsd): Removed in FreeBSD 15: 2840 "LOCAL_CONNWAIT" if freebsd_ver >= Some(15) => true, 2841 2842 // FIXME(freebsd): The values has been changed in FreeBSD 15: 2843 "CLOCK_BOOTTIME" if Some(15) <= freebsd_ver => true, 2844 2845 // Added in FreeBSD 14.0 2846 "TCP_FUNCTION_ALIAS" if Some(14) > freebsd_ver => true, 2847 2848 // These constants may change or disappear in future OS releases, and they probably 2849 // have no legitimate use in applications anyway. 2850 "CAP_UNUSED0_44" | "CAP_UNUSED0_57" | "CAP_UNUSED1_22" | "CAP_UNUSED1_57" 2851 | "CAP_ALL0" | "CAP_ALL1" => true, 2852 2853 // FIXME(freebsd): Removed in FreeBSD 15, deprecated in libc 2854 "TCP_PCAP_OUT" | "TCP_PCAP_IN" => true, 2855 2856 _ => false, 2857 } 2858 }); 2859 2860 cfg.skip_type(move |ty| { 2861 match ty { 2862 // the struct "__kvm" is quite tricky to bind so since we only use a pointer to it 2863 // for now, it doesn't matter too much... 2864 "kvm_t" => true, 2865 // `eventfd(2)` and things come with it are added in FreeBSD 13 2866 "eventfd_t" if Some(13) > freebsd_ver => true, 2867 2868 _ => false, 2869 } 2870 }); 2871 2872 cfg.skip_struct(move |ty| { 2873 if ty.starts_with("__c_anonymous_") { 2874 return true; 2875 } 2876 match ty { 2877 // `procstat` is a private struct 2878 "procstat" => true, 2879 2880 // `spacectl_range` was introduced in FreeBSD 14 2881 "spacectl_range" if Some(14) > freebsd_ver => true, 2882 2883 // `ptrace_coredump` introduced in FreeBSD 14. 2884 "ptrace_coredump" if Some(14) > freebsd_ver => true, 2885 // `ptrace_sc_remote` introduced in FreeBSD 14. 2886 "ptrace_sc_remote" if Some(14) > freebsd_ver => true, 2887 2888 // `sockcred2` is not available in FreeBSD 12. 2889 "sockcred2" if Some(13) > freebsd_ver => true, 2890 // `shm_largepage_conf` was introduced in FreeBSD 13. 2891 "shm_largepage_conf" if Some(13) > freebsd_ver => true, 2892 2893 // Those are private types 2894 "memory_type" => true, 2895 "memory_type_list" => true, 2896 "pidfh" => true, 2897 "sctp_gen_error_cause" 2898 | "sctp_error_missing_param" 2899 | "sctp_remote_error" 2900 | "sctp_assoc_change" 2901 | "sctp_send_failed_event" 2902 | "sctp_stream_reset_event" => true, 2903 2904 // FIXME(freebsd): Changed in FreeBSD 15 2905 "tcp_info" | "sockstat" if Some(15) >= freebsd_ver => true, 2906 2907 _ => false, 2908 } 2909 }); 2910 2911 cfg.skip_fn(move |name| { 2912 // skip those that are manually verified 2913 match name { 2914 // FIXME: https://github.com/rust-lang/libc/issues/1272 2915 // Also, `execvpe` is introduced in FreeBSD 14.1 2916 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2917 2918 // The `uname` function in the `utsname.h` FreeBSD header is a C 2919 // inline function (has no symbol) that calls the `__xuname` symbol. 2920 // Therefore the function pointer comparison does not make sense for it. 2921 "uname" => true, 2922 2923 // FIXME(ctest): Our API is unsound. The Rust API allows aliasing 2924 // pointers, but the C API requires pointers not to alias. 2925 // We should probably be at least using `&`/`&mut` here, see: 2926 // https://github.com/gnzlbg/ctest/issues/68 2927 "lio_listio" => true, 2928 2929 // Those are introduced in FreeBSD 12. 2930 "clock_nanosleep" | "getrandom" | "elf_aux_info" | "setproctitle_fast" 2931 | "timingsafe_bcmp" | "timingsafe_memcmp" 2932 if Some(12) > freebsd_ver => 2933 { 2934 true 2935 } 2936 2937 // Those are introduced in FreeBSD 13. 2938 "memfd_create" 2939 | "shm_create_largepage" 2940 | "shm_rename" 2941 | "getentropy" 2942 | "eventfd" 2943 | "SOCKCRED2SIZE" 2944 | "getlocalbase" 2945 | "aio_readv" 2946 | "aio_writev" 2947 | "copy_file_range" 2948 | "eventfd_read" 2949 | "eventfd_write" 2950 if Some(13) > freebsd_ver => 2951 { 2952 true 2953 } 2954 2955 // Those are introduced in FreeBSD 14. 2956 "sched_getaffinity" | "sched_setaffinity" | "sched_getcpu" | "fspacectl" 2957 if Some(14) > freebsd_ver => 2958 { 2959 true 2960 } 2961 2962 // Those are introduced in FreeBSD 14. 2963 "timerfd_create" | "timerfd_gettime" | "timerfd_settime" if Some(14) > freebsd_ver => { 2964 true 2965 } 2966 2967 // Those are introduced in FreeBSD 14.1. 2968 "kcmp" => true, 2969 2970 _ => false, 2971 } 2972 }); 2973 2974 cfg.volatile_item(|i| { 2975 use ctest::VolatileItemKind::*; 2976 match i { 2977 // aio_buf is a volatile void** but since we cannot express that in 2978 // Rust types, we have to explicitly tell the checker about it here: 2979 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 2980 _ => false, 2981 } 2982 }); 2983 2984 cfg.skip_field(move |struct_, field| { 2985 match (struct_, field) { 2986 // FIXME(freebsd): `sa_sigaction` has type `sighandler_t` but that type is 2987 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 2988 ("sigaction", "sa_sigaction") => true, 2989 2990 // conflicting with `p_type` macro from <resolve.h>. 2991 ("Elf32_Phdr", "p_type") => true, 2992 ("Elf64_Phdr", "p_type") => true, 2993 2994 // not available until FreeBSD 12, and is an anonymous union there. 2995 ("xucred", "cr_pid__c_anonymous_union") => true, 2996 2997 // m_owner field is a volatile __lwpid_t 2998 ("umutex", "m_owner") => true, 2999 // c_has_waiters field is a volatile int32_t 3000 ("ucond", "c_has_waiters") => true, 3001 // is PATH_MAX long but tests can't accept multi array as equivalent. 3002 ("kinfo_vmentry", "kve_path") => true, 3003 3004 // a_un field is a union 3005 ("Elf32_Auxinfo", "a_un") => true, 3006 ("Elf64_Auxinfo", "a_un") => true, 3007 3008 // union fields 3009 ("if_data", "__ifi_epoch") => true, 3010 ("if_data", "__ifi_lastchange") => true, 3011 ("ifreq", "ifr_ifru") => true, 3012 ("ifconf", "ifc_ifcu") => true, 3013 3014 // anonymous struct 3015 ("devstat", "dev_links") => true, 3016 3017 // FIXME(freebsd): structs too complicated to bind for now... 3018 ("kinfo_proc", "ki_paddr") => true, 3019 ("kinfo_proc", "ki_addr") => true, 3020 ("kinfo_proc", "ki_tracep") => true, 3021 ("kinfo_proc", "ki_textvp") => true, 3022 ("kinfo_proc", "ki_fd") => true, 3023 ("kinfo_proc", "ki_vmspace") => true, 3024 ("kinfo_proc", "ki_pcb") => true, 3025 ("kinfo_proc", "ki_tdaddr") => true, 3026 ("kinfo_proc", "ki_pd") => true, 3027 3028 // Anonymous type. 3029 ("filestat", "next") => true, 3030 3031 // We ignore this field because we needed to use a hack in order to make rust 1.19 3032 // happy... 3033 ("kinfo_proc", "ki_sparestrings") => true, 3034 3035 // `__sem_base` is a private struct field 3036 ("semid_ds", "__sem_base") => true, 3037 3038 // `snap_time` is a `long double`, but it's a nightmare to bind correctly in rust 3039 // for the moment, so it's a best effort thing... 3040 ("statinfo", "snap_time") => true, 3041 ("sctp_sndrcvinfo", "__reserve_pad") => true, 3042 ("sctp_extrcvinfo", "__reserve_pad") => true, 3043 // `tcp_snd_wscale` and `tcp_rcv_wscale` are bitfields 3044 ("tcp_info", "tcp_snd_wscale") => true, 3045 ("tcp_info", "tcp_rcv_wscale") => true, 3046 3047 _ => false, 3048 } 3049 }); 3050 if target.contains("arm") { 3051 cfg.skip_roundtrip(move |s| match s { 3052 // Can't return an array from a C function. 3053 "__gregset_t" => true, 3054 _ => false, 3055 }); 3056 } 3057 3058 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 3059 } 3060 3061 fn test_emscripten(target: &str) { 3062 assert!(target.contains("emscripten")); 3063 3064 let mut cfg = ctest_cfg(); 3065 cfg.define("_GNU_SOURCE", None); // FIXME(emscripten): ?? 3066 3067 headers! { cfg: 3068 "ctype.h", 3069 "dirent.h", 3070 "dlfcn.h", 3071 "errno.h", 3072 "fcntl.h", 3073 "fnmatch.h", 3074 "glob.h", 3075 "grp.h", 3076 "ifaddrs.h", 3077 "langinfo.h", 3078 "limits.h", 3079 "locale.h", 3080 "malloc.h", 3081 "mntent.h", 3082 "mqueue.h", 3083 "net/ethernet.h", 3084 "net/if.h", 3085 "net/if_arp.h", 3086 "net/route.h", 3087 "netdb.h", 3088 "netinet/in.h", 3089 "netinet/ip.h", 3090 "netinet/tcp.h", 3091 "netinet/udp.h", 3092 "netpacket/packet.h", 3093 "poll.h", 3094 "pthread.h", 3095 "pty.h", 3096 "pwd.h", 3097 "resolv.h", 3098 "sched.h", 3099 "sched.h", 3100 "semaphore.h", 3101 "shadow.h", 3102 "signal.h", 3103 "stddef.h", 3104 "stdint.h", 3105 "stdio.h", 3106 "stdlib.h", 3107 "string.h", 3108 "sys/file.h", 3109 "sys/ioctl.h", 3110 "sys/ipc.h", 3111 "sys/mman.h", 3112 "sys/mount.h", 3113 "sys/msg.h", 3114 "sys/resource.h", 3115 "sys/sem.h", 3116 "sys/shm.h", 3117 "sys/socket.h", 3118 "sys/stat.h", 3119 "sys/statvfs.h", 3120 "sys/syscall.h", 3121 "sys/sysinfo.h", 3122 "sys/time.h", 3123 "sys/times.h", 3124 "sys/types.h", 3125 "sys/uio.h", 3126 "sys/un.h", 3127 "sys/user.h", 3128 "sys/utsname.h", 3129 "sys/vfs.h", 3130 "sys/wait.h", 3131 "sys/xattr.h", 3132 "syslog.h", 3133 "termios.h", 3134 "time.h", 3135 "ucontext.h", 3136 "unistd.h", 3137 "utime.h", 3138 "utmp.h", 3139 "utmpx.h", 3140 "wchar.h", 3141 } 3142 3143 cfg.type_name(move |ty, is_struct, is_union| { 3144 match ty { 3145 // Just pass all these through, no need for a "struct" prefix 3146 "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(), 3147 3148 // LFS64 types have been removed in Emscripten 3.1.44 3149 // https://github.com/emscripten-core/emscripten/pull/19812 3150 "off64_t" => "off_t".to_string(), 3151 3152 // typedefs don't need any keywords 3153 t if t.ends_with("_t") => t.to_string(), 3154 3155 // put `struct` in front of all structs:. 3156 t if is_struct => format!("struct {t}"), 3157 3158 // put `union` in front of all unions: 3159 t if is_union => format!("union {t}"), 3160 3161 t => t.to_string(), 3162 } 3163 }); 3164 3165 cfg.field_name(move |struct_, field| { 3166 match field { 3167 // Our stat *_nsec fields normally don't actually exist but are part 3168 // of a timeval struct 3169 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 3170 s.replace("e_nsec", ".tv_nsec") 3171 } 3172 // Rust struct uses raw u64, rather than union 3173 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 3174 s => s.to_string(), 3175 } 3176 }); 3177 3178 cfg.skip_type(move |ty| { 3179 match ty { 3180 // sighandler_t is crazy across platforms 3181 // FIXME(emscripten): is this necessary? 3182 "sighandler_t" => true, 3183 3184 // No epoll support 3185 // https://github.com/emscripten-core/emscripten/issues/5033 3186 ty if ty.starts_with("epoll") => true, 3187 3188 // LFS64 types have been removed in Emscripten 3.1.44 3189 // https://github.com/emscripten-core/emscripten/pull/19812 3190 t => t.ends_with("64") || t.ends_with("64_t"), 3191 } 3192 }); 3193 3194 cfg.skip_struct(move |ty| { 3195 match ty { 3196 // This is actually a union, not a struct 3197 "sigval" => true, 3198 3199 // FIXME(emscripten): Investigate why the test fails. 3200 // Skip for now to unblock CI. 3201 "pthread_condattr_t" => true, 3202 "pthread_mutexattr_t" => true, 3203 3204 // No epoll support 3205 // https://github.com/emscripten-core/emscripten/issues/5033 3206 ty if ty.starts_with("epoll") => true, 3207 ty if ty.starts_with("signalfd") => true, 3208 3209 // LFS64 types have been removed in Emscripten 3.1.44 3210 // https://github.com/emscripten-core/emscripten/pull/19812 3211 ty => ty.ends_with("64") || ty.ends_with("64_t"), 3212 } 3213 }); 3214 3215 cfg.skip_fn(move |name| { 3216 match name { 3217 // Emscripten does not support fork/exec/wait or any kind of multi-process support 3218 // https://github.com/emscripten-core/emscripten/blob/3.1.68/tools/system_libs.py#L1100 3219 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" | "wait4" => true, 3220 3221 _ => false, 3222 } 3223 }); 3224 3225 cfg.skip_const(move |name| { 3226 match name { 3227 // FIXME(deprecated): deprecated - SIGNUNUSED was removed in glibc 2.26 3228 // users should use SIGSYS instead 3229 "SIGUNUSED" => true, 3230 3231 // FIXME(emscripten): emscripten uses different constants to constructs these 3232 n if n.contains("__SIZEOF_PTHREAD") => true, 3233 3234 // No epoll support 3235 // https://github.com/emscripten-core/emscripten/issues/5033 3236 n if n.starts_with("EPOLL") => true, 3237 3238 // No ptrace.h 3239 // https://github.com/emscripten-core/emscripten/pull/17704 3240 n if n.starts_with("PTRACE_") => true, 3241 3242 // No quota.h 3243 // https://github.com/emscripten-core/emscripten/pull/17704 3244 n if n.starts_with("QIF_") => true, 3245 "USRQUOTA" | "GRPQUOTA" | "Q_GETFMT" | "Q_GETINFO" | "Q_SETINFO" | "Q_SYNC" 3246 | "Q_QUOTAON" | "Q_QUOTAOFF" | "Q_GETQUOTA" | "Q_SETQUOTA" => true, 3247 3248 // `SYS_gettid` was removed in Emscripten v1.39.9 3249 // https://github.com/emscripten-core/emscripten/pull/10439 3250 "SYS_gettid" => true, 3251 3252 // No personality.h 3253 // https://github.com/emscripten-core/emscripten/pull/17704 3254 "ADDR_NO_RANDOMIZE" | "MMAP_PAGE_ZERO" | "ADDR_COMPAT_LAYOUT" | "READ_IMPLIES_EXEC" 3255 | "ADDR_LIMIT_32BIT" | "SHORT_INODE" | "WHOLE_SECONDS" | "STICKY_TIMEOUTS" 3256 | "ADDR_LIMIT_3GB" => true, 3257 3258 // `SIG_IGN` has been changed to -2 since 1 is a valid function address 3259 // https://github.com/emscripten-core/emscripten/pull/14883 3260 "SIG_IGN" => true, 3261 3262 // Constants present in other linuxes but not emscripten 3263 "SI_DETHREAD" | "TRAP_PERF" => true, 3264 3265 // LFS64 types have been removed in Emscripten 3.1.44 3266 // https://github.com/emscripten-core/emscripten/pull/19812 3267 n if n.starts_with("RLIM64") => true, 3268 3269 _ => false, 3270 } 3271 }); 3272 3273 cfg.skip_field_type(move |struct_, field| { 3274 // This is a weird union, don't check the type. 3275 (struct_ == "ifaddrs" && field == "ifa_ifu") || 3276 // sighandler_t type is super weird 3277 (struct_ == "sigaction" && field == "sa_sigaction") || 3278 // sigval is actually a union, but we pretend it's a struct 3279 (struct_ == "sigevent" && field == "sigev_value") 3280 }); 3281 3282 cfg.skip_field(move |struct_, field| { 3283 // this is actually a union on linux, so we can't represent it well and 3284 // just insert some padding. 3285 (struct_ == "siginfo_t" && field == "_pad") || 3286 // musl names this __dummy1 but it's still there 3287 (struct_ == "glob_t" && field == "gl_flags") || 3288 // FIXME(emscripten): After musl 1.1.24, it have only one field `sched_priority`, 3289 // while other fields become reserved. 3290 (struct_ == "sched_param" && [ 3291 "sched_ss_low_priority", 3292 "sched_ss_repl_period", 3293 "sched_ss_init_budget", 3294 "sched_ss_max_repl", 3295 ].contains(&field)) 3296 }); 3297 3298 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 3299 } 3300 3301 fn test_neutrino(target: &str) { 3302 assert!(target.contains("nto-qnx")); 3303 3304 let mut cfg = ctest_cfg(); 3305 if target.ends_with("_iosock") { 3306 let qnx_target_val = env::var("QNX_TARGET") 3307 .unwrap_or_else(|_| "QNX_TARGET_not_set_please_source_qnxsdp".into()); 3308 3309 cfg.include(qnx_target_val + "/usr/include/io-sock"); 3310 headers! { cfg: 3311 "io-sock.h", 3312 "sys/types.h", 3313 "sys/socket.h", 3314 "sys/sysctl.h", 3315 "net/if.h", 3316 "net/if_arp.h" 3317 } 3318 } 3319 3320 headers! { cfg: 3321 "ctype.h", 3322 "dirent.h", 3323 "dlfcn.h", 3324 "sys/elf.h", 3325 "fcntl.h", 3326 "fnmatch.h", 3327 "glob.h", 3328 "grp.h", 3329 "iconv.h", 3330 "ifaddrs.h", 3331 "limits.h", 3332 "sys/link.h", 3333 "locale.h", 3334 "sys/malloc.h", 3335 "rcheck/malloc.h", 3336 "malloc.h", 3337 "mqueue.h", 3338 "net/if.h", 3339 "net/if_arp.h", 3340 "net/route.h", 3341 "netdb.h", 3342 "netinet/in.h", 3343 "netinet/ip.h", 3344 "netinet/tcp.h", 3345 "netinet/udp.h", 3346 "netinet/ip_var.h", 3347 "sys/poll.h", 3348 "pthread.h", 3349 "pwd.h", 3350 "regex.h", 3351 "resolv.h", 3352 "sys/sched.h", 3353 "sched.h", 3354 "semaphore.h", 3355 "shadow.h", 3356 "signal.h", 3357 "spawn.h", 3358 "stddef.h", 3359 "stdint.h", 3360 "stdio.h", 3361 "stdlib.h", 3362 "string.h", 3363 "sys/sysctl.h", 3364 "sys/file.h", 3365 "sys/inotify.h", 3366 "sys/ioctl.h", 3367 "sys/ipc.h", 3368 "sys/mman.h", 3369 "sys/mount.h", 3370 "sys/msg.h", 3371 "sys/resource.h", 3372 "sys/sem.h", 3373 "sys/socket.h", 3374 "sys/stat.h", 3375 "sys/statvfs.h", 3376 "sys/swap.h", 3377 "sys/termio.h", 3378 "sys/time.h", 3379 "sys/times.h", 3380 "sys/types.h", 3381 "sys/uio.h", 3382 "sys/un.h", 3383 "sys/utsname.h", 3384 "sys/wait.h", 3385 "syslog.h", 3386 "termios.h", 3387 "time.h", 3388 "sys/time.h", 3389 "ucontext.h", 3390 "unistd.h", 3391 "utime.h", 3392 "utmp.h", 3393 "wchar.h", 3394 "aio.h", 3395 "nl_types.h", 3396 "langinfo.h", 3397 "unix.h", 3398 "nbutil.h", 3399 "aio.h", 3400 "net/bpf.h", 3401 "net/if_dl.h", 3402 "sys/syspage.h", 3403 3404 // TODO: The following header file doesn't appear as part of the default headers 3405 // found in a standard installation of Neutrino 7.1 SDP. The structures/ 3406 // functions dependent on it are currently commented out. 3407 //"sys/asyncmsg.h", 3408 } 3409 3410 // Create and include a header file containing 3411 // items which are not included in any official 3412 // header file. 3413 let internal_header = "internal.h"; 3414 let out_dir = env::var("OUT_DIR").unwrap(); 3415 cfg.header(internal_header); 3416 cfg.include(&out_dir); 3417 std::fs::write( 3418 out_dir.to_owned() + "/" + internal_header, 3419 "#ifndef __internal_h__ 3420 #define __internal_h__ 3421 void __my_thread_exit(const void **); 3422 #endif", 3423 ) 3424 .unwrap(); 3425 3426 cfg.type_name(move |ty, is_struct, is_union| { 3427 match ty { 3428 // Just pass all these through, no need for a "struct" prefix 3429 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 3430 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 3431 | "Elf32_Chdr" | "Elf64_Chdr" | "aarch64_qreg_t" | "syspage_entry_info" 3432 | "syspage_array_info" => ty.to_string(), 3433 3434 "Ioctl" => "int".to_string(), 3435 3436 t if is_union => format!("union {t}"), 3437 3438 t if t.ends_with("_t") => t.to_string(), 3439 3440 // put `struct` in front of all structs:. 3441 t if is_struct => format!("struct {t}"), 3442 3443 t => t.to_string(), 3444 } 3445 }); 3446 3447 cfg.field_name(move |_struct_, field| match field { 3448 "type_" => "type".to_string(), 3449 3450 s => s.to_string(), 3451 }); 3452 3453 cfg.volatile_item(|i| { 3454 use ctest::VolatileItemKind::*; 3455 match i { 3456 // The following fields are volatie but since we cannot express that in 3457 // Rust types, we have to explicitly tell the checker about it here: 3458 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 3459 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec_tod_adjust" => true, 3460 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec" => true, 3461 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec_stable" => true, 3462 StructField(ref n, ref f) if n == "intrspin" && f == "value" => true, 3463 _ => false, 3464 } 3465 }); 3466 3467 cfg.skip_type(move |ty| { 3468 match ty { 3469 // FIXME(sighandler): `sighandler_t` type is incorrect, see: 3470 // https://github.com/rust-lang/libc/issues/1359 3471 "sighandler_t" => true, 3472 3473 // Does not exist in Neutrino 3474 "locale_t" => true, 3475 3476 // FIXME: "'__uint128' undeclared" in C 3477 "__uint128" => true, 3478 3479 _ => false, 3480 } 3481 }); 3482 3483 cfg.skip_struct(move |ty| { 3484 if ty.starts_with("__c_anonymous_") { 3485 return true; 3486 } 3487 match ty { 3488 "Elf64_Phdr" | "Elf32_Phdr" => true, 3489 3490 // FIXME(union): This is actually a union, not a struct 3491 "sigval" => true, 3492 3493 // union 3494 "_channel_connect_attr" => true, 3495 3496 _ => false, 3497 } 3498 }); 3499 3500 cfg.skip_const(move |name| { 3501 match name { 3502 // These signal "functions" are actually integer values that are casted to a fn ptr 3503 // This causes the compiler to err because of "illegal cast of int to ptr". 3504 "SIG_DFL" => true, 3505 "SIG_IGN" => true, 3506 "SIG_ERR" => true, 3507 3508 _ => false, 3509 } 3510 }); 3511 3512 cfg.skip_fn(move |name| { 3513 // skip those that are manually verified 3514 match name { 3515 // FIXME: https://github.com/rust-lang/libc/issues/1272 3516 "execv" | "execve" | "execvp" | "execvpe" => true, 3517 3518 // wrong signature 3519 "signal" => true, 3520 3521 // wrong signature of callback ptr 3522 "__cxa_atexit" => true, 3523 3524 // FIXME(ctest): Our API is unsound. The Rust API allows aliasing 3525 // pointers, but the C API requires pointers not to alias. 3526 // We should probably be at least using `&`/`&mut` here, see: 3527 // https://github.com/gnzlbg/ctest/issues/68 3528 "lio_listio" => true, 3529 3530 // 2 fields are actually unions which we're simply representing 3531 // as structures. 3532 "ChannelConnectAttr" => true, 3533 3534 // fields contains unions 3535 "SignalKillSigval" => true, 3536 "SignalKillSigval_r" => true, 3537 3538 // Not defined in any headers. Defined to work around a 3539 // stack unwinding bug. 3540 "__my_thread_exit" => true, 3541 3542 // Wrong const-ness 3543 "dl_iterate_phdr" => true, 3544 3545 _ => false, 3546 } 3547 }); 3548 3549 cfg.skip_field_type(move |struct_, field| { 3550 // sigval is actually a union, but we pretend it's a struct 3551 struct_ == "sigevent" && field == "sigev_value" || 3552 // Anonymous structures 3553 struct_ == "_idle_hook" && field == "time" 3554 }); 3555 3556 cfg.skip_field(|struct_, field| { 3557 matches!( 3558 (struct_, field), 3559 ("__sched_param", "reserved") 3560 | ("sched_param", "reserved") 3561 | ("sigevent", "__padding1") // ensure alignment 3562 | ("sigevent", "__padding2") // union 3563 | ("sigevent", "__sigev_un2") // union 3564 | ("sigaction", "sa_sigaction") // sighandler_t type is super weird 3565 | ("syspage_entry", "__reserved") // does not exist 3566 ) 3567 }); 3568 3569 cfg.skip_static(move |name| (name == "__dso_handle")); 3570 3571 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 3572 } 3573 3574 fn test_vxworks(target: &str) { 3575 assert!(target.contains("vxworks")); 3576 3577 let mut cfg = ctest::TestGenerator::new(); 3578 headers! { cfg: 3579 "vxWorks.h", 3580 "yvals.h", 3581 "nfs/nfsCommon.h", 3582 "rtpLibCommon.h", 3583 "randomNumGen.h", 3584 "taskLib.h", 3585 "sysLib.h", 3586 "ioLib.h", 3587 "inetLib.h", 3588 "socket.h", 3589 "errnoLib.h", 3590 "ctype.h", 3591 "dirent.h", 3592 "dlfcn.h", 3593 "elf.h", 3594 "fcntl.h", 3595 "grp.h", 3596 "sys/poll.h", 3597 "ifaddrs.h", 3598 "langinfo.h", 3599 "limits.h", 3600 "link.h", 3601 "locale.h", 3602 "sys/stat.h", 3603 "netdb.h", 3604 "pthread.h", 3605 "pwd.h", 3606 "sched.h", 3607 "semaphore.h", 3608 "signal.h", 3609 "stddef.h", 3610 "stdint.h", 3611 "stdio.h", 3612 "stdlib.h", 3613 "string.h", 3614 "sys/file.h", 3615 "sys/ioctl.h", 3616 "sys/socket.h", 3617 "sys/time.h", 3618 "sys/times.h", 3619 "sys/types.h", 3620 "sys/uio.h", 3621 "sys/un.h", 3622 "sys/utsname.h", 3623 "sys/wait.h", 3624 "netinet/tcp.h", 3625 "syslog.h", 3626 "termios.h", 3627 "time.h", 3628 "ucontext.h", 3629 "unistd.h", 3630 "utime.h", 3631 "wchar.h", 3632 "errno.h", 3633 "sys/mman.h", 3634 "pathLib.h", 3635 "mqueue.h", 3636 } 3637 // FIXME(vxworks) 3638 cfg.skip_const(move |name| match name { 3639 // sighandler_t weirdness 3640 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" 3641 // This is not defined in vxWorks 3642 | "RTLD_DEFAULT" => true, 3643 _ => false, 3644 }); 3645 // FIXME(vxworks) 3646 cfg.skip_type(move |ty| match ty { 3647 "stat64" | "sighandler_t" | "off64_t" => true, 3648 _ => false, 3649 }); 3650 3651 cfg.skip_field_type(move |struct_, field| match (struct_, field) { 3652 ("siginfo_t", "si_value") | ("stat", "st_size") | ("sigaction", "sa_u") => true, 3653 _ => false, 3654 }); 3655 3656 cfg.skip_roundtrip(|_| false); 3657 3658 cfg.type_name(move |ty, is_struct, is_union| match ty { 3659 "DIR" | "FILE" | "Dl_info" | "RTP_DESC" => ty.to_string(), 3660 t if is_union => format!("union {t}"), 3661 t if t.ends_with("_t") => t.to_string(), 3662 t if is_struct => format!("struct {t}"), 3663 t => t.to_string(), 3664 }); 3665 3666 // FIXME(vxworks) 3667 cfg.skip_fn(move |name| match name { 3668 // sigval 3669 "sigqueue" | "_sigqueue" 3670 // sighandler_t 3671 | "signal" 3672 // not used in static linking by default 3673 | "dlerror" => true, 3674 _ => false, 3675 }); 3676 3677 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 3678 } 3679 3680 fn config_gnu_bits(target: &str, cfg: &mut ctest::TestGenerator) { 3681 match env::var("RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS") { 3682 Ok(val) if val == "64" => { 3683 if target.contains("gnu") 3684 && target.contains("linux") 3685 && !target.ends_with("x32") 3686 && !target.contains("riscv32") 3687 && env::var("CARGO_CFG_TARGET_POINTER_WIDTH").unwrap() == "32" 3688 { 3689 cfg.define("_FILE_OFFSET_BITS", Some("64")); 3690 cfg.cfg("gnu_file_offset_bits64", None); 3691 } 3692 } 3693 Ok(val) if val != "32" => { 3694 panic!("RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS may only be set to '32' or '64'") 3695 } 3696 _ => {} 3697 } 3698 } 3699 3700 fn test_linux(target: &str) { 3701 assert!(target.contains("linux")); 3702 3703 // target_env 3704 let gnu = target.contains("gnu"); 3705 let musl = target.contains("musl") || target.contains("ohos"); 3706 let uclibc = target.contains("uclibc"); 3707 3708 match (gnu, musl, uclibc) { 3709 (true, false, false) => (), 3710 (false, true, false) => (), 3711 (false, false, true) => (), 3712 (_, _, _) => panic!("linux target lib is gnu: {gnu}, musl: {musl}, uclibc: {uclibc}"), 3713 } 3714 3715 let arm = target.contains("arm"); 3716 let aarch64 = target.contains("aarch64"); 3717 let i686 = target.contains("i686"); 3718 let ppc = target.contains("powerpc"); 3719 let ppc64 = target.contains("powerpc64"); 3720 let s390x = target.contains("s390x"); 3721 let sparc64 = target.contains("sparc64"); 3722 let x32 = target.contains("x32"); 3723 let x86_32 = target.contains("i686"); 3724 let x86_64 = target.contains("x86_64"); 3725 let aarch64_musl = aarch64 && musl; 3726 let gnueabihf = target.contains("gnueabihf"); 3727 let x86_64_gnux32 = target.contains("gnux32") && x86_64; 3728 let riscv64 = target.contains("riscv64"); 3729 let loongarch64 = target.contains("loongarch64"); 3730 let wasm32 = target.contains("wasm32"); 3731 let uclibc = target.contains("uclibc"); 3732 3733 let mut cfg = ctest_cfg(); 3734 cfg.define("_GNU_SOURCE", None); 3735 // This macro re-defines fscanf,scanf,sscanf to link to the symbols that are 3736 // deprecated since glibc >= 2.29. This allows Rust binaries to link against 3737 // glibc versions older than 2.29. 3738 cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None); 3739 3740 config_gnu_bits(target, &mut cfg); 3741 3742 headers! { cfg: 3743 "ctype.h", 3744 "dirent.h", 3745 "dlfcn.h", 3746 "elf.h", 3747 "fcntl.h", 3748 "fnmatch.h", 3749 "getopt.h", 3750 "glob.h", 3751 [gnu]: "gnu/libc-version.h", 3752 "grp.h", 3753 "iconv.h", 3754 "ifaddrs.h", 3755 "langinfo.h", 3756 "libgen.h", 3757 "limits.h", 3758 "link.h", 3759 "linux/sysctl.h", 3760 "locale.h", 3761 "malloc.h", 3762 "mntent.h", 3763 "mqueue.h", 3764 "net/ethernet.h", 3765 "net/if.h", 3766 "net/if_arp.h", 3767 "net/route.h", 3768 "netdb.h", 3769 "netinet/in.h", 3770 "netinet/ip.h", 3771 "netinet/tcp.h", 3772 "netinet/udp.h", 3773 "poll.h", 3774 "pthread.h", 3775 "pty.h", 3776 "pwd.h", 3777 "regex.h", 3778 "resolv.h", 3779 "sched.h", 3780 "semaphore.h", 3781 "shadow.h", 3782 "signal.h", 3783 "spawn.h", 3784 "stddef.h", 3785 "stdint.h", 3786 "stdio.h", 3787 "stdlib.h", 3788 "string.h", 3789 "sys/epoll.h", 3790 "sys/eventfd.h", 3791 "sys/file.h", 3792 "sys/fsuid.h", 3793 "sys/klog.h", 3794 "sys/inotify.h", 3795 "sys/ioctl.h", 3796 "sys/ipc.h", 3797 "sys/mman.h", 3798 "sys/mount.h", 3799 "sys/msg.h", 3800 "sys/personality.h", 3801 "sys/prctl.h", 3802 "sys/ptrace.h", 3803 "sys/quota.h", 3804 "sys/random.h", 3805 "sys/reboot.h", 3806 "sys/resource.h", 3807 "sys/sem.h", 3808 "sys/sendfile.h", 3809 "sys/shm.h", 3810 "sys/signalfd.h", 3811 "sys/socket.h", 3812 "sys/stat.h", 3813 "sys/statvfs.h", 3814 "sys/swap.h", 3815 "sys/syscall.h", 3816 "sys/time.h", 3817 "sys/timerfd.h", 3818 "sys/times.h", 3819 "sys/timex.h", 3820 "sys/types.h", 3821 "sys/uio.h", 3822 "sys/un.h", 3823 "sys/user.h", 3824 "sys/utsname.h", 3825 "sys/vfs.h", 3826 "sys/wait.h", 3827 "syslog.h", 3828 "termios.h", 3829 "time.h", 3830 "ucontext.h", 3831 "unistd.h", 3832 "utime.h", 3833 "utmp.h", 3834 "utmpx.h", 3835 "wchar.h", 3836 "errno.h", 3837 // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit 3838 // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162 3839 // Also unavailable on gnueabihf with glibc 2.30. 3840 // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6b33f373c7b9199e00ba5fbafd94ac9bfb4337b1 3841 [(x86_64 || x86_32 || arm) && !gnueabihf]: "sys/io.h", 3842 // `sys/reg.h` is only available on x86 and x86_64 3843 [x86_64 || x86_32]: "sys/reg.h", 3844 // sysctl system call is deprecated and not available on musl 3845 // It is also unsupported in x32, deprecated since glibc 2.30: 3846 [!(x32 || musl || gnu)]: "sys/sysctl.h", 3847 // <execinfo.h> is not supported by musl: 3848 // https://www.openwall.com/lists/musl/2015/04/09/3 3849 // <execinfo.h> is not present on uclibc. 3850 [!(musl || uclibc)]: "execinfo.h", 3851 } 3852 3853 // Include linux headers at the end: 3854 headers! { 3855 cfg: 3856 [loongarch64 || riscv64]: "asm/hwcap.h", 3857 "asm/mman.h", 3858 } 3859 3860 if !wasm32 { 3861 headers! { cfg: 3862 [gnu]: "linux/aio_abi.h", 3863 "linux/can.h", 3864 "linux/can/raw.h", 3865 "linux/can/j1939.h", 3866 "linux/dccp.h", 3867 "linux/errqueue.h", 3868 "linux/falloc.h", 3869 "linux/filter.h", 3870 "linux/fs.h", 3871 "linux/futex.h", 3872 "linux/genetlink.h", 3873 "linux/if.h", 3874 "linux/if_addr.h", 3875 "linux/if_alg.h", 3876 "linux/if_ether.h", 3877 "linux/if_packet.h", 3878 "linux/if_tun.h", 3879 "linux/if_xdp.h", 3880 "linux/input.h", 3881 "linux/ipv6.h", 3882 "linux/kexec.h", 3883 "linux/keyctl.h", 3884 "linux/magic.h", 3885 "linux/memfd.h", 3886 "linux/membarrier.h", 3887 "linux/mempolicy.h", 3888 "linux/mman.h", 3889 "linux/module.h", 3890 "linux/mount.h", 3891 "linux/net_tstamp.h", 3892 "linux/netfilter/nfnetlink.h", 3893 "linux/netfilter/nfnetlink_log.h", 3894 "linux/netfilter/nfnetlink_queue.h", 3895 "linux/netfilter/nf_tables.h", 3896 "linux/netfilter_arp.h", 3897 "linux/netfilter_bridge.h", 3898 "linux/netfilter_ipv4.h", 3899 "linux/netfilter_ipv6.h", 3900 "linux/netfilter_ipv6/ip6_tables.h", 3901 "linux/netlink.h", 3902 "linux/nsfs.h", 3903 "linux/openat2.h", 3904 // FIXME(linux): some items require Linux >= 5.6: 3905 "linux/ptp_clock.h", 3906 "linux/ptrace.h", 3907 "linux/quota.h", 3908 "linux/random.h", 3909 "linux/reboot.h", 3910 "linux/rtnetlink.h", 3911 "linux/sched.h", 3912 "linux/sctp.h", 3913 "linux/seccomp.h", 3914 "linux/sock_diag.h", 3915 "linux/sockios.h", 3916 "linux/tls.h", 3917 "linux/uinput.h", 3918 "linux/vm_sockets.h", 3919 "linux/wait.h", 3920 "linux/wireless.h", 3921 "sys/fanotify.h", 3922 // <sys/auxv.h> is not present on uclibc 3923 [!uclibc]: "sys/auxv.h", 3924 [gnu || musl]: "linux/close_range.h", 3925 } 3926 } 3927 3928 // note: aio.h must be included before sys/mount.h 3929 headers! { 3930 cfg: 3931 "sys/xattr.h", 3932 "sys/sysinfo.h", 3933 // AIO is not supported by uclibc: 3934 [!uclibc]: "aio.h", 3935 } 3936 3937 cfg.type_name(move |ty, is_struct, is_union| { 3938 match ty { 3939 // Just pass all these through, no need for a "struct" prefix 3940 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 3941 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 3942 | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(), 3943 3944 "Ioctl" if gnu => "unsigned long".to_string(), 3945 "Ioctl" => "int".to_string(), 3946 3947 // LFS64 types have been removed in musl 1.2.4+ 3948 "off64_t" if musl => "off_t".to_string(), 3949 3950 // typedefs don't need any keywords 3951 t if t.ends_with("_t") => t.to_string(), 3952 // put `struct` in front of all structs:. 3953 t if is_struct => format!("struct {t}"), 3954 // put `union` in front of all unions: 3955 t if is_union => format!("union {t}"), 3956 3957 t => t.to_string(), 3958 } 3959 }); 3960 3961 cfg.field_name(move |struct_, field| { 3962 match field { 3963 // Our stat *_nsec fields normally don't actually exist but are part 3964 // of a timeval struct 3965 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 3966 s.replace("e_nsec", ".tv_nsec") 3967 } 3968 // FIXME(linux): epoll_event.data is actually a union in C, but in Rust 3969 // it is only a u64 because we only expose one field 3970 // http://man7.org/linux/man-pages/man2/epoll_wait.2.html 3971 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 3972 // The following structs have a field called `type` in C, 3973 // but `type` is a Rust keyword, so these fields are translated 3974 // to `type_` in Rust. 3975 "type_" 3976 if struct_ == "input_event" 3977 || struct_ == "input_mask" 3978 || struct_ == "ff_effect" => 3979 { 3980 "type".to_string() 3981 } 3982 3983 s => s.to_string(), 3984 } 3985 }); 3986 3987 cfg.skip_type(move |ty| { 3988 // FIXME(musl): very recent additions to musl, not yet released. 3989 // also apparently some glibc versions 3990 if ty == "Elf32_Relr" || ty == "Elf64_Relr" { 3991 return true; 3992 } 3993 if sparc64 && (ty == "Elf32_Rela" || ty == "Elf64_Rela") { 3994 return true; 3995 } 3996 match ty { 3997 // FIXME(sighandler): `sighandler_t` type is incorrect, see: 3998 // https://github.com/rust-lang/libc/issues/1359 3999 "sighandler_t" => true, 4000 4001 // These cannot be tested when "resolv.h" is included and are tested 4002 // in the `linux_elf.rs` file. 4003 "Elf64_Phdr" | "Elf32_Phdr" => true, 4004 4005 // This type is private on Linux. It is implemented as a C `enum` 4006 // (`c_uint`) and this clashes with the type of the `rlimit` APIs 4007 // which expect a `c_int` even though both are ABI compatible. 4008 "__rlimit_resource_t" => true, 4009 // on Linux, this is a volatile int 4010 "pthread_spinlock_t" => true, 4011 4012 // For internal use only, to define architecture specific ioctl constants with a libc 4013 // specific type. 4014 "Ioctl" => true, 4015 4016 // FIXME: "'__uint128' undeclared" in C 4017 "__uint128" => true, 4018 4019 t => { 4020 if musl { 4021 // LFS64 types have been removed in musl 1.2.4+ 4022 t.ends_with("64") || t.ends_with("64_t") 4023 } else { 4024 false 4025 } 4026 } 4027 } 4028 }); 4029 4030 cfg.skip_struct(move |ty| { 4031 if ty.starts_with("__c_anonymous_") { 4032 return true; 4033 } 4034 4035 // FIXME(linux): CI has old headers 4036 if ty == "ptp_sys_offset_extended" { 4037 return true; 4038 } 4039 4040 // LFS64 types have been removed in musl 1.2.4+ 4041 if musl && (ty.ends_with("64") || ty.ends_with("64_t")) { 4042 return true; 4043 } 4044 4045 // FIXME(linux): sparc64 CI has old headers 4046 if sparc64 && (ty == "uinput_ff_erase" || ty == "uinput_abs_setup") { 4047 return true; 4048 } 4049 4050 // FIXME(#1558): passing by value corrupts the value for reasons not understood. 4051 if (gnu && sparc64) && (ty == "ip_mreqn" || ty == "hwtstamp_config") { 4052 return true; 4053 } 4054 4055 // FIXME(rust-lang/rust#43894): pass by value for structs that are not an even 32/64 bits 4056 // on big-endian systems corrupts the value for unknown reasons. 4057 if (sparc64 || ppc || ppc64 || s390x) 4058 && (ty == "sockaddr_pkt" 4059 || ty == "tpacket_auxdata" 4060 || ty == "tpacket_hdr_variant1" 4061 || ty == "tpacket_req3" 4062 || ty == "tpacket_stats_v3" 4063 || ty == "tpacket_req_u") 4064 { 4065 return true; 4066 } 4067 4068 // FIXME(musl): musl doesn't compile with `struct fanout_args` for unknown reasons. 4069 if musl && ty == "fanout_args" { 4070 return true; 4071 } 4072 if sparc64 && ty == "fanotify_event_info_error" { 4073 return true; 4074 } 4075 4076 match ty { 4077 // These cannot be tested when "resolv.h" is included and are tested 4078 // in the `linux_elf.rs` file. 4079 "Elf64_Phdr" | "Elf32_Phdr" => true, 4080 4081 // On Linux, the type of `ut_tv` field of `struct utmpx` 4082 // can be an anonymous struct, so an extra struct, 4083 // which is absent in glibc, has to be defined. 4084 "__timeval" => true, 4085 4086 // FIXME(union): This is actually a union, not a struct 4087 "sigval" => true, 4088 4089 // This type is tested in the `linux_termios.rs` file since there 4090 // are header conflicts when including them with all the other 4091 // structs. 4092 "termios2" => true, 4093 4094 // FIXME(linux): remove once we set minimum supported glibc version. 4095 // ucontext_t added a new field as of glibc 2.28; our struct definition is 4096 // conservative and omits the field, but that means the size doesn't match for newer 4097 // glibcs (see https://github.com/rust-lang/libc/issues/1410) 4098 "ucontext_t" if gnu => true, 4099 4100 // FIXME(linux): Somehow we cannot include headers correctly in glibc 2.30. 4101 // So let's ignore for now and re-visit later. 4102 // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085 4103 "statx" => true, 4104 "statx_timestamp" => true, 4105 4106 // On Linux, the type of `ut_exit` field of struct `utmpx` 4107 // can be an anonymous struct, so an extra struct, 4108 // which is absent in musl, has to be defined. 4109 "__exit_status" if musl => true, 4110 4111 // clone_args might differ b/w libc versions 4112 "clone_args" => true, 4113 4114 // Might differ between kernel versions 4115 "open_how" => true, 4116 4117 // Linux >= 6.13 (pidfd_info.exit_code: Linux >= 6.15) 4118 // Might differ between kernel versions 4119 "pidfd_info" => true, 4120 4121 "sctp_initmsg" | "sctp_sndrcvinfo" | "sctp_sndinfo" | "sctp_rcvinfo" 4122 | "sctp_nxtinfo" | "sctp_prinfo" | "sctp_authinfo" => true, 4123 4124 // FIXME(linux): requires >= 6.1 kernel headers 4125 "canxl_frame" => true, 4126 4127 // FIXME(linux): The size of `iv` has been changed since Linux v6.0 4128 // https://github.com/torvalds/linux/commit/94dfc73e7cf4a31da66b8843f0b9283ddd6b8381 4129 "af_alg_iv" => true, 4130 4131 // FIXME(linux): Requires >= 5.1 kernel headers. 4132 // Everything that uses install-musl.sh has 4.19 kernel headers. 4133 "tls12_crypto_info_aes_gcm_256" 4134 if (aarch64 || arm || i686 || s390x || x86_64) && musl => 4135 { 4136 true 4137 } 4138 4139 // FIXME(linux): Requires >= 5.11 kernel headers. 4140 // Everything that uses install-musl.sh has 4.19 kernel headers. 4141 "tls12_crypto_info_chacha20_poly1305" 4142 if (aarch64 || arm || i686 || s390x || x86_64) && musl => 4143 { 4144 true 4145 } 4146 4147 // FIXME(linux): Requires >= 5.3 kernel headers. 4148 // Everything that uses install-musl.sh has 4.19 kernel headers. 4149 "xdp_options" if musl => true, 4150 4151 // FIXME(linux): Requires >= 5.4 kernel headers. 4152 // Everything that uses install-musl.sh has 4.19 kernel headers. 4153 "xdp_ring_offset" | "xdp_mmap_offsets" if musl => true, 4154 4155 // FIXME(linux): Requires >= 6.8 kernel headers. 4156 // A field was added in 6.8. 4157 // https://github.com/torvalds/linux/commit/341ac980eab90ac1f6c22ee9f9da83ed9604d899 4158 // The previous version of the struct was removed in 6.11 due to a bug. 4159 // https://github.com/torvalds/linux/commit/32654bbd6313b4cfc82297e6634fa9725c3c900f 4160 "xdp_umem_reg" => true, 4161 4162 // FIXME(linux): Requires >= 5.9 kernel headers. 4163 // Everything that uses install-musl.sh has 4.19 kernel headers. 4164 "xdp_statistics" if musl => true, 4165 4166 // FIXME(linux): Requires >= 6.8 kernel headers. 4167 "xsk_tx_metadata" 4168 | "__c_anonymous_xsk_tx_metadata_union" 4169 | "xsk_tx_metadata_request" 4170 | "xsk_tx_metadata_completion" => true, 4171 4172 // A new field was added in kernel 5.4, this is the old version for backwards compatibility. 4173 // https://github.com/torvalds/linux/commit/77cd0d7b3f257fd0e3096b4fdcff1a7d38e99e10 4174 "xdp_ring_offset_v1" | "xdp_mmap_offsets_v1" => true, 4175 4176 // Multiple new fields were added in kernel 5.9, this is the old version for backwards compatibility. 4177 // https://github.com/torvalds/linux/commit/77cd0d7b3f257fd0e3096b4fdcff1a7d38e99e10 4178 "xdp_statistics_v1" => true, 4179 4180 // A new field was added in kernel 5.4, this is the old version for backwards compatibility. 4181 // https://github.com/torvalds/linux/commit/c05cd3645814724bdeb32a2b4d953b12bdea5f8c 4182 "xdp_umem_reg_v1" => true, 4183 4184 // Is defined in `<linux/sched/types.h>` but if this file is included at the same time 4185 // as `<sched.h>`, the `struct sched_param` is defined twice, causing the compilation to 4186 // fail. The problem doesn't seem to be present in more recent versions of the linux 4187 // kernel so we can drop this and test the type once this new version is used in CI. 4188 "sched_attr" => true, 4189 4190 // FIXME(linux): Requires >= 6.9 kernel headers. 4191 "epoll_params" => true, 4192 4193 // FIXME(linux): Requires >= 6.12 kernel headers. 4194 "dmabuf_cmsg" | "dmabuf_token" => true, 4195 4196 // FIXME(linux): Requires >= 6.12 kernel headers. 4197 "mnt_ns_info" => true, 4198 4199 // FIXME(linux): Requires >= 6.4 kernel headers. 4200 "ptrace_sud_config" => true, 4201 4202 _ => false, 4203 } 4204 }); 4205 4206 cfg.skip_const(move |name| { 4207 if !gnu { 4208 // Skip definitions from the kernel on non-glibc Linux targets. 4209 // They're libc-independent, so we only need to check them on one 4210 // libc. We don't want to break CI if musl or another libc doesn't 4211 // have the definitions yet. (We do still want to check them on 4212 // every glibc target, though, as some of them can vary by 4213 // architecture.) 4214 // 4215 // This is not an exhaustive list of kernel constants, just a list 4216 // of prefixes of all those that have appeared here or that get 4217 // updated regularly and seem likely to cause breakage. 4218 if name.starts_with("AF_") 4219 || name.starts_with("ARPHRD_") 4220 || name.starts_with("EPOLL") 4221 || name.starts_with("F_") 4222 || name.starts_with("FALLOC_FL_") 4223 || name.starts_with("IFLA_") 4224 || name.starts_with("KEXEC_") 4225 || name.starts_with("MS_") 4226 || name.starts_with("MSG_") 4227 || name.starts_with("OPEN_TREE_") 4228 || name.starts_with("P_") 4229 || name.starts_with("PF_") 4230 || name.starts_with("PIDFD_") 4231 || name.starts_with("RLIMIT_") 4232 || name.starts_with("RTEXT_FILTER_") 4233 || name.starts_with("SOL_") 4234 || name.starts_with("STATX_") 4235 || name.starts_with("SW_") 4236 || name.starts_with("SYS_") 4237 || name.starts_with("TCP_") 4238 || name.starts_with("UINPUT_") 4239 || name.starts_with("VMADDR_") 4240 { 4241 return true; 4242 } 4243 } 4244 if musl { 4245 // FIXME(linux): Requires >= 5.0 kernel headers 4246 if name == "SECCOMP_GET_NOTIF_SIZES" 4247 || name == "SECCOMP_FILTER_FLAG_NEW_LISTENER" 4248 || name == "SECCOMP_FILTER_FLAG_TSYNC_ESRCH" 4249 || name == "SECCOMP_USER_NOTIF_FLAG_CONTINUE" // requires >= 5.5 4250 || name == "SECCOMP_ADDFD_FLAG_SETFD" // requires >= 5.9 4251 || name == "SECCOMP_ADDFD_FLAG_SEND" // requires >= 5.9 4252 || name == "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV" // requires >= 5.19 4253 { 4254 return true; 4255 } 4256 // FIXME(linux): Requires >= 4.20 kernel headers 4257 if name == "PTP_SYS_OFFSET_EXTENDED" { 4258 return true; 4259 } 4260 // FIXME(linux): Requires >= 5.4 kernel headers 4261 if name == "PTP_CLOCK_GETCAPS2" 4262 || name == "PTP_ENABLE_PPS2" 4263 || name == "PTP_EXTTS_REQUEST2" 4264 || name == "PTP_PEROUT_REQUEST2" 4265 || name == "PTP_PIN_GETFUNC2" 4266 || name == "PTP_PIN_SETFUNC2" 4267 || name == "PTP_SYS_OFFSET2" 4268 || name == "PTP_SYS_OFFSET_PRECISE2" 4269 || name == "PTP_SYS_OFFSET_EXTENDED2" 4270 { 4271 return true; 4272 } 4273 // FIXME(linux): Requires >= 5.4.1 kernel headers 4274 if name.starts_with("J1939") 4275 || name.starts_with("RTEXT_FILTER_") 4276 || name.starts_with("SO_J1939") 4277 || name.starts_with("SCM_J1939") 4278 { 4279 return true; 4280 } 4281 // FIXME(linux): Requires >= 5.10 kernel headers 4282 if name.starts_with("MEMBARRIER_CMD_REGISTER") 4283 || name.starts_with("MEMBARRIER_CMD_PRIVATE") 4284 { 4285 return true; 4286 } 4287 // LFS64 types have been removed in musl 1.2.4+ 4288 if name.starts_with("RLIM64") { 4289 return true; 4290 } 4291 // CI fails because musl targets use Linux v4 kernel 4292 if name.starts_with("NI_IDN") { 4293 return true; 4294 } 4295 // FIXME: Requires >= 6.3 kernel headers 4296 if loongarch64 && (name == "MFD_NOEXEC_SEAL" || name == "MFD_EXEC") { 4297 return true; 4298 } 4299 // FIXME: Requires >= 6.3 (6.6) kernel headers 4300 if name == "PR_GET_MDWE" || name == "PR_MDWE_NO_INHERIT" || name == "PR_MDWE_REFUSE_EXEC_GAIN" || name == "PR_SET_MDWE" { 4301 return true; 4302 } 4303 // FIXME(musl): Requires musl >= 1.2 4304 if name == "SO_PREFER_BUSY_POLL" 4305 || name == "SO_BUSY_POLL_BUDGET" 4306 { 4307 return true; 4308 } 4309 // FIXME(musl): Not in musl yet 4310 if name == "SO_NETNS_COOKIE" 4311 || name == "SO_BUF_LOCK" 4312 || name == "SO_RESERVE_MEM" 4313 || name == "SO_TXREHASH" 4314 || name == "SO_RCVMARK" 4315 || name == "SO_PASSPIDFD" 4316 || name == "SO_PEERPIDFD" 4317 || name == "SO_DEVMEM_LINEAR" 4318 || name == "SO_DEVMEM_DMABUF" 4319 || name == "SO_DEVMEM_DONTNEED" 4320 { 4321 return true; 4322 } 4323 // FIXME(musl): Not in musl yet 4324 if name == "SCM_DEVMEM_LINEAR" 4325 || name == "SCM_DEVMEM_DMABUF" 4326 { 4327 return true; 4328 } 4329 } 4330 match name { 4331 // These constants are not available if gnu headers have been included 4332 // and can therefore not be tested here 4333 // 4334 // The IPV6 constants are tested in the `linux_ipv6.rs` tests: 4335 | "IPV6_FLOWINFO" 4336 | "IPV6_FLOWLABEL_MGR" 4337 | "IPV6_FLOWINFO_SEND" 4338 | "IPV6_FLOWINFO_FLOWLABEL" 4339 | "IPV6_FLOWINFO_PRIORITY" 4340 // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: 4341 | "F_CANCELLK" 4342 | "F_ADD_SEALS" 4343 | "F_GET_SEALS" 4344 | "F_SEAL_SEAL" 4345 | "F_SEAL_SHRINK" 4346 | "F_SEAL_GROW" 4347 | "F_SEAL_WRITE" 4348 | "F_SEAL_FUTURE_WRITE" 4349 | "F_SEAL_EXEC" => true, 4350 // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests 4351 // because including `linux/if_arp.h` causes some conflicts: 4352 "ARPHRD_CAN" => true, 4353 4354 // FIXME(deprecated): deprecated: not available in any header 4355 // See: https://github.com/rust-lang/libc/issues/1356 4356 "ENOATTR" => true, 4357 4358 // FIXME(deprecated): SIGUNUSED was removed in glibc 2.26 4359 // Users should use SIGSYS instead. 4360 "SIGUNUSED" => true, 4361 4362 // FIXME(linux): conflicts with glibc headers and is tested in 4363 // `linux_termios.rs` below: 4364 | "BOTHER" 4365 | "IBSHIFT" 4366 | "TCGETS2" 4367 | "TCSETS2" 4368 | "TCSETSW2" 4369 | "TCSETSF2" => true, 4370 4371 // FIXME(musl): on musl the pthread types are defined a little differently 4372 // - these constants are used by the glibc implementation. 4373 n if musl && n.contains("__SIZEOF_PTHREAD") => true, 4374 4375 // FIXME(linux): It was extended to 4096 since glibc 2.31 (Linux 5.4). 4376 // We should do so after a while. 4377 "SOMAXCONN" if gnu => true, 4378 4379 // deprecated: not available from Linux kernel 5.6: 4380 "VMADDR_CID_RESERVED" => true, 4381 4382 // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP: 4383 | "IPPROTO_MAX" 4384 | "IPPROTO_ETHERNET" 4385 | "IPPROTO_MPTCP" => true, 4386 4387 // FIXME(linux): Not yet implemented on sparc64 4388 "SYS_clone3" if sparc64 => true, 4389 4390 // FIXME(linux): Not defined on ARM, gnueabihf, musl, PowerPC, riscv64, s390x, and sparc64. 4391 "SYS_memfd_secret" if arm | gnueabihf | musl | ppc | riscv64 | s390x | sparc64 => true, 4392 4393 // FIXME(linux): Added in Linux 5.16 4394 // https://github.com/torvalds/linux/commit/039c0ec9bb77446d7ada7f55f90af9299b28ca49 4395 "SYS_futex_waitv" => true, 4396 4397 // FIXME(linux): Added in Linux 5.17 4398 // https://github.com/torvalds/linux/commit/c6018b4b254971863bd0ad36bb5e7d0fa0f0ddb0 4399 "SYS_set_mempolicy_home_node" => true, 4400 4401 // FIXME(linux): Added in Linux 5.18 4402 // https://github.com/torvalds/linux/commit/8b5413647262dda8d8d0e07e14ea1de9ac7cf0b2 4403 "NFQA_PRIORITY" => true, 4404 4405 // FIXME(linux): requires more recent kernel headers on CI 4406 | "UINPUT_VERSION" 4407 | "SW_MAX" 4408 | "SW_CNT" 4409 if ppc64 || riscv64 => true, 4410 4411 // FIXME(linux): requires more recent kernel headers on CI 4412 "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV" if sparc64 => true, 4413 4414 // FIXME(linux): Not currently available in headers on ARM and musl. 4415 "NETLINK_GET_STRICT_CHK" if arm => true, 4416 4417 // Skip as this signal codes and trap reasons need newer headers 4418 "SI_DETHREAD" | "TRAP_PERF" => true, 4419 4420 // kernel constants not available in uclibc 1.0.34 4421 | "EXTPROC" 4422 | "IPPROTO_BEETPH" 4423 | "IPPROTO_MPLS" 4424 | "IPV6_HDRINCL" 4425 | "IPV6_MULTICAST_ALL" 4426 | "IPV6_PMTUDISC_INTERFACE" 4427 | "IPV6_PMTUDISC_OMIT" 4428 | "IPV6_ROUTER_ALERT_ISOLATE" 4429 | "PACKET_MR_UNICAST" 4430 | "RUSAGE_THREAD" 4431 | "SHM_EXEC" 4432 | "UDP_GRO" 4433 | "UDP_SEGMENT" 4434 if uclibc => true, 4435 4436 // headers conflicts with linux/pidfd.h 4437 "PIDFD_NONBLOCK" => true, 4438 // Linux >= 6.9 4439 "PIDFD_THREAD" 4440 | "PIDFD_SIGNAL_THREAD" 4441 | "PIDFD_SIGNAL_THREAD_GROUP" 4442 | "PIDFD_SIGNAL_PROCESS_GROUP" => true, 4443 // Linux >= 6.11 4444 "PIDFD_GET_CGROUP_NAMESPACE" 4445 | "PIDFD_GET_IPC_NAMESPACE" 4446 | "PIDFD_GET_MNT_NAMESPACE" 4447 | "PIDFD_GET_NET_NAMESPACE" 4448 | "PIDFD_GET_PID_NAMESPACE" 4449 | "PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE" 4450 | "PIDFD_GET_TIME_NAMESPACE" 4451 | "PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE" 4452 | "PIDFD_GET_USER_NAMESPACE" 4453 | "PIDFD_GET_UTS_NAMESPACE" => true, 4454 // Linux >= 6.13 4455 "PIDFD_GET_INFO" 4456 | "PIDFD_INFO_PID" 4457 | "PIDFD_INFO_CREDS" 4458 | "PIDFD_INFO_CGROUPID" 4459 | "PIDFD_INFO_SIZE_VER0" => true, 4460 // Linux >= 6.15 4461 "PIDFD_INFO_EXIT" | "PIDFD_SELF" | "PIDFD_SELF_PROCESS" => true, 4462 4463 // is a private value for kernel usage normally 4464 "FUSE_SUPER_MAGIC" => true, 4465 4466 // linux 5.17 min 4467 "PR_SET_VMA" | "PR_SET_VMA_ANON_NAME" => true, 4468 4469 // present in recent kernels only 4470 "PR_SCHED_CORE" | "PR_SCHED_CORE_CREATE" | "PR_SCHED_CORE_GET" | "PR_SCHED_CORE_MAX" | "PR_SCHED_CORE_SCOPE_PROCESS_GROUP" | "PR_SCHED_CORE_SCOPE_THREAD" | "PR_SCHED_CORE_SCOPE_THREAD_GROUP" | "PR_SCHED_CORE_SHARE_FROM" | "PR_SCHED_CORE_SHARE_TO" => true, 4471 4472 // present in recent kernels only >= 5.13 4473 "PR_PAC_SET_ENABLED_KEYS" | "PR_PAC_GET_ENABLED_KEYS" => true, 4474 // present in recent kernels only >= 5.19 4475 "PR_SME_SET_VL" | "PR_SME_GET_VL" | "PR_SME_VL_LEN_MAX" | "PR_SME_SET_VL_INHERIT" | "PR_SME_SET_VL_ONE_EXEC" => true, 4476 4477 // Added in Linux 5.14 4478 "FUTEX_LOCK_PI2" => true, 4479 4480 // Added in linux 6.1 4481 "STATX_DIOALIGN" 4482 | "CAN_RAW_XL_FRAMES" 4483 | "CANXL_HDR_SIZE" 4484 | "CANXL_MAX_DLC" 4485 | "CANXL_MAX_DLC_MASK" 4486 | "CANXL_MAX_DLEN" 4487 | "CANXL_MAX_MTU" 4488 | "CANXL_MIN_DLC" 4489 | "CANXL_MIN_DLEN" 4490 | "CANXL_MIN_MTU" 4491 | "CANXL_MTU" 4492 | "CANXL_PRIO_BITS" 4493 | "CANXL_PRIO_MASK" 4494 | "CANXL_SEC" 4495 | "CANXL_XLF" 4496 => true, 4497 4498 // FIXME(linux): Parts of netfilter/nfnetlink*.h require more recent kernel headers: 4499 | "RTNLGRP_MCTP_IFADDR" // linux v5.17+ 4500 | "RTNLGRP_TUNNEL" // linux v5.18+ 4501 | "RTNLGRP_STATS" // linux v5.18+ 4502 => true, 4503 4504 // FIXME(linux): The below is no longer const in glibc 2.34: 4505 // https://github.com/bminor/glibc/commit/5d98a7dae955bafa6740c26eaba9c86060ae0344 4506 | "PTHREAD_STACK_MIN" 4507 | "SIGSTKSZ" 4508 | "MINSIGSTKSZ" 4509 if gnu => true, 4510 4511 // FIXME(linux): Linux >= 5.16: 4512 // https://github.com/torvalds/linux/commit/42df6e1d221dddc0f2acf2be37e68d553ad65f96 4513 "NF_NETDEV_EGRESS" if sparc64 => true, 4514 // value changed 4515 "NF_NETDEV_NUMHOOKS" if sparc64 => true, 4516 4517 // FIXME(linux): requires Linux >= v5.8 4518 "IF_LINK_MODE_TESTING" if sparc64 => true, 4519 4520 // DIFF(main): fixed in 1.0 with e9abac9ac2 4521 "CLONE_CLEAR_SIGHAND" | "CLONE_INTO_CGROUP" => true, 4522 4523 // kernel 6.1 minimum 4524 "MADV_COLLAPSE" => true, 4525 4526 // kernel 6.2 minimum 4527 "TUN_F_USO4" | "TUN_F_USO6" | "IFF_NO_CARRIER" => true, 4528 4529 // FIXME(linux): Requires more recent kernel headers 4530 | "IFLA_PARENT_DEV_NAME" // linux v5.13+ 4531 | "IFLA_PARENT_DEV_BUS_NAME" // linux v5.13+ 4532 | "IFLA_GRO_MAX_SIZE" // linux v5.16+ 4533 | "IFLA_TSO_MAX_SIZE" // linux v5.18+ 4534 | "IFLA_TSO_MAX_SEGS" // linux v5.18+ 4535 | "IFLA_ALLMULTI" // linux v6.0+ 4536 | "MADV_DONTNEED_LOCKED" // linux v5.18+ 4537 => true, 4538 "SCTP_FUTURE_ASSOC" | "SCTP_CURRENT_ASSOC" | "SCTP_ALL_ASSOC" | "SCTP_PEER_ADDR_THLDS_V2" => true, // linux 5.5+ 4539 4540 // kernel 6.5 minimum 4541 "MOVE_MOUNT_BENEATH" => true, 4542 // FIXME(linux): Requires linux 6.1 4543 "ALG_SET_KEY_BY_KEY_SERIAL" | "ALG_SET_DRBG_ENTROPY" => true, 4544 4545 // FIXME(linux): Requires more recent kernel headers 4546 | "FAN_FS_ERROR" // linux v5.16+ 4547 | "FAN_RENAME" // linux v5.17+ 4548 | "FAN_REPORT_TARGET_FID" // linux v5.17+ 4549 | "FAN_REPORT_DFID_NAME_TARGET" // linux v5.17+ 4550 | "FAN_MARK_EVICTABLE" // linux v5.19+ 4551 | "FAN_MARK_IGNORE" // linux v6.0+ 4552 | "FAN_MARK_IGNORE_SURV" // linux v6.0+ 4553 | "FAN_EVENT_INFO_TYPE_ERROR" // linux v5.16+ 4554 | "FAN_EVENT_INFO_TYPE_OLD_DFID_NAME" // linux v5.17+ 4555 | "FAN_EVENT_INFO_TYPE_NEW_DFID_NAME" // linux v5.17+ 4556 | "FAN_RESPONSE_INFO_NONE" // linux v5.16+ 4557 | "FAN_RESPONSE_INFO_AUDIT_RULE" // linux v5.16+ 4558 | "FAN_INFO" // linux v5.16+ 4559 => true, 4560 4561 // musl doesn't use <linux/fanotify.h> in <sys/fanotify.h> 4562 "FAN_REPORT_PIDFD" 4563 | "FAN_REPORT_DIR_FID" 4564 | "FAN_REPORT_NAME" 4565 | "FAN_REPORT_DFID_NAME" 4566 | "FAN_EVENT_INFO_TYPE_DFID_NAME" 4567 | "FAN_EVENT_INFO_TYPE_DFID" 4568 | "FAN_EVENT_INFO_TYPE_PIDFD" 4569 | "FAN_NOPIDFD" 4570 | "FAN_EPIDFD" 4571 if musl => true, 4572 4573 // FIXME(linux): Requires linux 6.5 4574 "NFT_MSG_MAX" => true, 4575 4576 // FIXME(linux): Requires >= 6.6 kernel headers. 4577 "XDP_USE_SG" 4578 | "XDP_PKT_CONTD" 4579 => 4580 { 4581 true 4582 } 4583 4584 // FIXME(linux): Requires >= 6.6 kernel headers. 4585 "PR_MDWE_NO_INHERIT" => true, 4586 4587 // FIXME(linux): Requires >= 6.8 kernel headers. 4588 "XDP_UMEM_TX_SW_CSUM" 4589 | "XDP_TXMD_FLAGS_TIMESTAMP" 4590 | "XDP_TXMD_FLAGS_CHECKSUM" 4591 | "XDP_TX_METADATA" 4592 => 4593 { 4594 true 4595 } 4596 4597 // FIXME(linux): Requires >= 6.11 kernel headers. 4598 "XDP_UMEM_TX_METADATA_LEN" 4599 => 4600 { 4601 true 4602 } 4603 4604 // FIXME(linux): Requires >= 6.11 kernel headers. 4605 "NS_GET_MNTNS_ID" | "NS_GET_PID_FROM_PIDNS" | "NS_GET_TGID_FROM_PIDNS" | "NS_GET_PID_IN_PIDNS" | "NS_GET_TGID_IN_PIDNS" => true, 4606 // FIXME(linux): Requires >= 6.12 kernel headers. 4607 "MNT_NS_INFO_SIZE_VER0" | "NS_MNT_GET_INFO" | "NS_MNT_GET_NEXT" | "NS_MNT_GET_PREV" => true, 4608 4609 // FIXME(linux): Requires >= 6.6 kernel headers. 4610 "SYS_fchmodat2" => true, 4611 4612 // FIXME(linux): Requires >= 6.10 kernel headers. 4613 "SYS_mseal" => true, 4614 4615 // FIXME(linux): seems to not be available all the time (from <include/linux/sched.h>: 4616 "PF_VCPU" 4617 | "PF_IDLE" 4618 | "PF_EXITING" 4619 | "PF_POSTCOREDUMP" 4620 | "PF_IO_WORKER" 4621 | "PF_WQ_WORKER" 4622 | "PF_FORKNOEXEC" 4623 | "PF_MCE_PROCESS" 4624 | "PF_SUPERPRIV" 4625 | "PF_DUMPCORE" 4626 | "PF_SIGNALED" 4627 | "PF_MEMALLOC" 4628 | "PF_NPROC_EXCEEDED" 4629 | "PF_USED_MATH" 4630 | "PF_USER_WORKER" 4631 | "PF_NOFREEZE" 4632 | "PF_KSWAPD" 4633 | "PF_MEMALLOC_NOFS" 4634 | "PF_MEMALLOC_NOIO" 4635 | "PF_LOCAL_THROTTLE" 4636 | "PF_KTHREAD" 4637 | "PF_RANDOMIZE" 4638 | "PF_NO_SETAFFINITY" 4639 | "PF_MCE_EARLY" 4640 | "PF_MEMALLOC_PIN" 4641 | "PF_BLOCK_TS" 4642 | "PF_SUSPEND_TASK" => true, 4643 4644 // FIXME(linux): Requires >= 6.9 kernel headers. 4645 "EPIOCSPARAMS" 4646 | "EPIOCGPARAMS" => true, 4647 4648 // FIXME(linux): Requires >= 6.11 kernel headers. 4649 "MAP_DROPPABLE" => true, 4650 4651 // FIXME(linux): Requires >= 6.2 kernel headers. 4652 "SOF_TIMESTAMPING_OPT_ID_TCP" => true, 4653 4654 // FIXME(linux): Requires >= 6.12 kernel headers. 4655 "SOF_TIMESTAMPING_OPT_RX_FILTER" => true, 4656 4657 // FIXME(linux): Requires >= 6.12 kernel headers. 4658 "SO_DEVMEM_LINEAR" 4659 | "SO_DEVMEM_DMABUF" 4660 | "SO_DEVMEM_DONTNEED" 4661 | "SCM_DEVMEM_LINEAR" 4662 | "SCM_DEVMEM_DMABUF" => true, 4663 // FIXME(linux): Requires >= 6.4 kernel headers. 4664 "PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG" | "PTRACE_GET_SYSCALL_USER_DISPATCH_CONFIG" => true, 4665 4666 _ => false, 4667 } 4668 }); 4669 4670 cfg.skip_fn(move |name| { 4671 // skip those that are manually verified 4672 match name { 4673 // FIXME: https://github.com/rust-lang/libc/issues/1272 4674 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 4675 4676 // There are two versions of the sterror_r function, see 4677 // 4678 // https://linux.die.net/man/3/strerror_r 4679 // 4680 // An XSI-compliant version provided if: 4681 // 4682 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) 4683 // && ! _GNU_SOURCE 4684 // 4685 // and a GNU specific version provided if _GNU_SOURCE is defined. 4686 // 4687 // libc provides bindings for the XSI-compliant version, which is 4688 // preferred for portable applications. 4689 // 4690 // We skip the test here since here _GNU_SOURCE is defined, and 4691 // test the XSI version below. 4692 "strerror_r" => true, 4693 4694 // FIXME(linux): Our API is unsound. The Rust API allows aliasing 4695 // pointers, but the C API requires pointers not to alias. 4696 // We should probably be at least using `&`/`&mut` here, see: 4697 // https://github.com/gnzlbg/ctest/issues/68 4698 "lio_listio" if musl => true, 4699 4700 // Needs glibc 2.34 or later. 4701 "posix_spawn_file_actions_addclosefrom_np" if gnu && sparc64 => true, 4702 // Needs glibc 2.35 or later. 4703 "posix_spawn_file_actions_addtcsetpgrp_np" if gnu && sparc64 => true, 4704 4705 // FIXME(linux): Deprecated since glibc 2.30. Remove fn once upstream does. 4706 "sysctl" if gnu => true, 4707 4708 // FIXME(linux): It now takes c_void instead of timezone since glibc 2.31. 4709 "gettimeofday" if gnu => true, 4710 4711 // These are all implemented as static inline functions in uclibc, so 4712 // they cannot be linked against. 4713 // If implementations are required, they might need to be implemented 4714 // in this crate. 4715 "posix_spawnattr_init" if uclibc => true, 4716 "posix_spawnattr_destroy" if uclibc => true, 4717 "posix_spawnattr_getsigdefault" if uclibc => true, 4718 "posix_spawnattr_setsigdefault" if uclibc => true, 4719 "posix_spawnattr_getsigmask" if uclibc => true, 4720 "posix_spawnattr_setsigmask" if uclibc => true, 4721 "posix_spawnattr_getflags" if uclibc => true, 4722 "posix_spawnattr_setflags" if uclibc => true, 4723 "posix_spawnattr_getpgroup" if uclibc => true, 4724 "posix_spawnattr_setpgroup" if uclibc => true, 4725 "posix_spawnattr_getschedpolicy" if uclibc => true, 4726 "posix_spawnattr_setschedpolicy" if uclibc => true, 4727 "posix_spawnattr_getschedparam" if uclibc => true, 4728 "posix_spawnattr_setschedparam" if uclibc => true, 4729 "posix_spawn_file_actions_init" if uclibc => true, 4730 "posix_spawn_file_actions_destroy" if uclibc => true, 4731 4732 // uclibc defines the flags type as a uint, but dependent crates 4733 // assume it's a int instead. 4734 "getnameinfo" if uclibc => true, 4735 4736 // FIXME(musl): This needs musl 1.2.2 or later. 4737 "gettid" if musl => true, 4738 4739 // Needs glibc 2.33 or later. 4740 "mallinfo2" => true, 4741 4742 "reallocarray" if musl => true, 4743 4744 // Not defined in uclibc as of 1.0.34 4745 "gettid" if uclibc => true, 4746 4747 // Needs musl 1.2.3 or later. 4748 "pthread_getname_np" if musl => true, 4749 4750 // pthread_sigqueue uses sigval, which was initially declared 4751 // as a struct but should be defined as a union. However due 4752 // to the issues described here: https://github.com/rust-lang/libc/issues/2816 4753 // it can't be changed from struct. 4754 "pthread_sigqueue" => true, 4755 4756 // There are two versions of basename(3) on Linux with glibc, see 4757 // 4758 // https://man7.org/linux/man-pages/man3/basename.3.html 4759 // 4760 // If libgen.h is included, then the POSIX version will be available; 4761 // If _GNU_SOURCE is defined and string.h is included, then the GNU one 4762 // will be used. 4763 // 4764 // libc exposes both of them, providing a prefix to differentiate between 4765 // them. 4766 // 4767 // Because the name with prefix is not a valid symbol in C, we have to 4768 // skip the tests. 4769 "posix_basename" if gnu => true, 4770 "gnu_basename" if gnu => true, 4771 4772 // FIXME(linux): function pointers changed since Ubuntu 23.10 4773 "strtol" | "strtoll" | "strtoul" | "strtoull" | "fscanf" | "scanf" | "sscanf" => true, 4774 4775 // Added in musl 1.2.5 4776 "preadv2" | "pwritev2" if musl => true, 4777 4778 _ => false, 4779 } 4780 }); 4781 4782 cfg.skip_field_type(move |struct_, field| { 4783 // This is a weird union, don't check the type. 4784 (struct_ == "ifaddrs" && field == "ifa_ifu") || 4785 // sighandler_t type is super weird 4786 (struct_ == "sigaction" && field == "sa_sigaction") || 4787 // __timeval type is a patch which doesn't exist in glibc 4788 (struct_ == "utmpx" && field == "ut_tv") || 4789 // sigval is actually a union, but we pretend it's a struct 4790 (struct_ == "sigevent" && field == "sigev_value") || 4791 // this one is an anonymous union 4792 (struct_ == "ff_effect" && field == "u") || 4793 // `__exit_status` type is a patch which is absent in musl 4794 (struct_ == "utmpx" && field == "ut_exit" && musl) || 4795 // `can_addr` is an anonymous union 4796 (struct_ == "sockaddr_can" && field == "can_addr") || 4797 // `anonymous_1` is an anonymous union 4798 (struct_ == "ptp_perout_request" && field == "anonymous_1") || 4799 // `anonymous_2` is an anonymous union 4800 (struct_ == "ptp_perout_request" && field == "anonymous_2") || 4801 // FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers 4802 // FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers 4803 // the rsv field shrunk when those fields got added, so is omitted too 4804 (struct_ == "ptp_clock_caps" && (loongarch64 || sparc64) && (["adjust_phase", "max_phase_adj", "rsv"].contains(&field))) 4805 }); 4806 4807 cfg.volatile_item(|i| { 4808 use ctest::VolatileItemKind::*; 4809 match i { 4810 // aio_buf is a volatile void** but since we cannot express that in 4811 // Rust types, we have to explicitly tell the checker about it here: 4812 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 4813 _ => false, 4814 } 4815 }); 4816 4817 cfg.skip_field(move |struct_, field| { 4818 // this is actually a union on linux, so we can't represent it well and 4819 // just insert some padding. 4820 (struct_ == "siginfo_t" && field == "_pad") || 4821 // musl names this __dummy1 but it's still there 4822 (musl && struct_ == "glob_t" && field == "gl_flags") || 4823 // musl seems to define this as an *anonymous* bitfield 4824 (musl && struct_ == "statvfs" && field == "__f_unused") || 4825 // sigev_notify_thread_id is actually part of a sigev_un union 4826 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 4827 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release 4828 // has them yet. 4829 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 4830 field == "_pad2" || 4831 field == "ssi_syscall" || 4832 field == "ssi_call_addr" || 4833 field == "ssi_arch")) || 4834 // FIXME(musl): After musl 1.1.24, it have only one field `sched_priority`, 4835 // while other fields become reserved. 4836 (struct_ == "sched_param" && [ 4837 "sched_ss_low_priority", 4838 "sched_ss_repl_period", 4839 "sched_ss_init_budget", 4840 "sched_ss_max_repl", 4841 ].contains(&field) && musl) || 4842 // FIXME(musl): After musl 1.1.24, the type becomes `int` instead of `unsigned short`. 4843 (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) || 4844 // glibc uses unnamed fields here and Rust doesn't support that yet 4845 (struct_ == "timex" && field.starts_with("__unused")) || 4846 // FIXME(linux): It now takes mode_t since glibc 2.31 on some targets. 4847 (struct_ == "ipc_perm" && field == "mode" 4848 && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32) 4849 ) || 4850 // the `u` field is in fact an anonymous union 4851 (gnu && struct_ == "ptrace_syscall_info" && (field == "u" || field == "pad")) || 4852 // the vregs field is a `__uint128_t` C's type. 4853 (struct_ == "user_fpsimd_struct" && field == "vregs") || 4854 // Linux >= 5.11 tweaked the `svm_zero` field of the `sockaddr_vm` struct. 4855 // https://github.com/torvalds/linux/commit/dc8eeef73b63ed8988224ba6b5ed19a615163a7f 4856 (struct_ == "sockaddr_vm" && field == "svm_zero") || 4857 // the `ifr_ifru` field is an anonymous union 4858 (struct_ == "ifreq" && field == "ifr_ifru") || 4859 // the `ifc_ifcu` field is an anonymous union 4860 (struct_ == "ifconf" && field == "ifc_ifcu") || 4861 // glibc uses a single array `uregs` instead of individual fields. 4862 (struct_ == "user_regs" && arm) || 4863 // the `ifr_ifrn` field is an anonymous union 4864 (struct_ == "iwreq" && field == "ifr_ifrn") || 4865 // the `key` field is a zero-sized array 4866 (struct_ == "iw_encode_ext" && field == "key") || 4867 // the `tcpi_snd_rcv_wscale` map two bitfield fields stored in a u8 4868 (struct_ == "tcp_info" && field == "tcpi_snd_rcv_wscale") || 4869 // the `tcpi_delivery_fastopen_bitfields` map two bitfield fields stored in a u8 4870 (musl && struct_ == "tcp_info" && field == "tcpi_delivery_fastopen_bitfields") || 4871 // either fsid_t or int[2] type 4872 (struct_ == "fanotify_event_info_fid" && field == "fsid") || 4873 // `handle` is a VLA 4874 (struct_ == "fanotify_event_info_fid" && field == "handle") || 4875 // `anonymous_1` is an anonymous union 4876 (struct_ == "ptp_perout_request" && field == "anonymous_1") || 4877 // `anonymous_2` is an anonymous union 4878 (struct_ == "ptp_perout_request" && field == "anonymous_2") || 4879 // FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers 4880 // FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers 4881 // the rsv field shrunk when those fields got added, so is omitted too 4882 (struct_ == "ptp_clock_caps" && (loongarch64 || sparc64) && (["adjust_phase", "max_phase_adj", "rsv"].contains(&field))) || 4883 // invalid application of 'sizeof' to incomplete type 'long unsigned int[]' 4884 (musl && struct_ == "mcontext_t" && field == "__extcontext" && loongarch64) || 4885 // FIXME(#4121): a new field was added from `f_spare` 4886 (struct_ == "statvfs" && field == "__f_spare") || 4887 (struct_ == "statvfs64" && field == "__f_spare") || 4888 // the `xsk_tx_metadata_union` field is an anonymous union 4889 (struct_ == "xsk_tx_metadata" && field == "xsk_tx_metadata_union") || 4890 // FIXME(musl): After musl 1.2.0, the type becomes `int` instead of `long`. 4891 (struct_ == "utmpx" && field == "ut_session") 4892 }); 4893 4894 cfg.skip_roundtrip(move |s| match s { 4895 // FIXME(1.0): 4896 "mcontext_t" if s390x => true, 4897 // FIXME(union): This is actually a union. 4898 "fpreg_t" if s390x => true, 4899 4900 // The test doesn't work on some env: 4901 "ipv6_mreq" 4902 | "ip_mreq_source" 4903 | "sockaddr_in6" 4904 | "sockaddr_ll" 4905 | "in_pktinfo" 4906 | "arpreq" 4907 | "arpreq_old" 4908 | "sockaddr_un" 4909 | "ff_constant_effect" 4910 | "ff_ramp_effect" 4911 | "ff_condition_effect" 4912 | "Elf32_Ehdr" 4913 | "Elf32_Chdr" 4914 | "ucred" 4915 | "in6_pktinfo" 4916 | "sockaddr_nl" 4917 | "termios" 4918 | "nlmsgerr" 4919 if sparc64 && gnu => 4920 { 4921 true 4922 } 4923 4924 // The following types contain Flexible Array Member fields which have unspecified calling 4925 // convention. The roundtripping tests deliberately pass the structs by value to check "by 4926 // value" layout consistency, but this would be UB for the these types. 4927 "inotify_event" => true, 4928 "fanotify_event_info_fid" => true, 4929 "cmsghdr" => true, 4930 4931 // FIXME(linux): the call ABI of max_align_t is incorrect on these platforms: 4932 "max_align_t" if i686 || ppc64 => true, 4933 4934 _ => false, 4935 }); 4936 4937 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 4938 4939 test_linux_like_apis(target); 4940 } 4941 4942 // This function tests APIs that are incompatible to test when other APIs 4943 // are included (e.g. because including both sets of headers clashes) 4944 fn test_linux_like_apis(target: &str) { 4945 let gnu = target.contains("gnu"); 4946 let musl = target.contains("musl") || target.contains("ohos"); 4947 let linux = target.contains("linux"); 4948 let wali = target.contains("linux") && target.contains("wasm32"); 4949 let emscripten = target.contains("emscripten"); 4950 let android = target.contains("android"); 4951 assert!(linux || android || emscripten); 4952 4953 if linux || android || emscripten { 4954 // test strerror_r from the `string.h` header 4955 let mut cfg = ctest_cfg(); 4956 config_gnu_bits(target, &mut cfg); 4957 cfg.skip_type(|_| true).skip_static(|_| true); 4958 4959 headers! { cfg: "string.h" } 4960 cfg.skip_fn(|f| match f { 4961 "strerror_r" => false, 4962 _ => true, 4963 }) 4964 .skip_const(|_| true) 4965 .skip_struct(|_| true); 4966 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_strerror_r.rs"); 4967 } 4968 4969 if linux || android || emscripten { 4970 // test fcntl - see: 4971 // http://man7.org/linux/man-pages/man2/fcntl.2.html 4972 let mut cfg = ctest_cfg(); 4973 config_gnu_bits(target, &mut cfg); 4974 4975 if musl { 4976 cfg.header("fcntl.h"); 4977 } else { 4978 cfg.header("linux/fcntl.h"); 4979 } 4980 4981 cfg.skip_type(|_| true) 4982 .skip_static(|_| true) 4983 .skip_struct(|_| true) 4984 .skip_fn(|_| true) 4985 .skip_const(move |name| match name { 4986 // test fcntl constants: 4987 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" 4988 | "F_SEAL_GROW" | "F_SEAL_WRITE" => false, 4989 _ => true, 4990 }) 4991 .type_name(move |ty, is_struct, is_union| match ty { 4992 t if is_struct => format!("struct {t}"), 4993 t if is_union => format!("union {t}"), 4994 t => t.to_string(), 4995 }); 4996 4997 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_fcntl.rs"); 4998 } 4999 5000 if (linux && !wali) || android { 5001 // test termios 5002 let mut cfg = ctest_cfg(); 5003 config_gnu_bits(target, &mut cfg); 5004 cfg.header("asm/termbits.h"); 5005 cfg.header("linux/termios.h"); 5006 cfg.skip_type(|_| true) 5007 .skip_static(|_| true) 5008 .skip_fn(|_| true) 5009 .skip_const(|c| match c { 5010 "BOTHER" | "IBSHIFT" => false, 5011 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => false, 5012 _ => true, 5013 }) 5014 .skip_struct(|s| s != "termios2") 5015 .type_name(move |ty, is_struct, is_union| match ty { 5016 "Ioctl" if gnu => "unsigned long".to_string(), 5017 "Ioctl" => "int".to_string(), 5018 t if is_struct => format!("struct {t}"), 5019 t if is_union => format!("union {t}"), 5020 t => t.to_string(), 5021 }); 5022 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_termios.rs"); 5023 } 5024 5025 if linux || android { 5026 // test IPV6_ constants: 5027 let mut cfg = ctest_cfg(); 5028 config_gnu_bits(target, &mut cfg); 5029 headers! { 5030 cfg: 5031 "linux/in6.h" 5032 } 5033 cfg.skip_type(|_| true) 5034 .skip_static(|_| true) 5035 .skip_fn(|_| true) 5036 .skip_const(|_| true) 5037 .skip_struct(|_| true) 5038 .skip_const(move |name| match name { 5039 "IPV6_FLOWINFO" 5040 | "IPV6_FLOWLABEL_MGR" 5041 | "IPV6_FLOWINFO_SEND" 5042 | "IPV6_FLOWINFO_FLOWLABEL" 5043 | "IPV6_FLOWINFO_PRIORITY" => false, 5044 _ => true, 5045 }) 5046 .type_name(move |ty, is_struct, is_union| match ty { 5047 t if is_struct => format!("struct {t}"), 5048 t if is_union => format!("union {t}"), 5049 t => t.to_string(), 5050 }); 5051 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_ipv6.rs"); 5052 } 5053 5054 if (linux && !wali) || android { 5055 // Test Elf64_Phdr and Elf32_Phdr 5056 // These types have a field called `p_type`, but including 5057 // "resolve.h" defines a `p_type` macro that expands to `__p_type` 5058 // making the tests for these fails when both are included. 5059 let mut cfg = ctest_cfg(); 5060 config_gnu_bits(target, &mut cfg); 5061 cfg.header("elf.h"); 5062 cfg.skip_fn(|_| true) 5063 .skip_static(|_| true) 5064 .skip_const(|_| true) 5065 .type_name(move |ty, _is_struct, _is_union| ty.to_string()) 5066 .skip_struct(move |ty| match ty { 5067 "Elf64_Phdr" | "Elf32_Phdr" => false, 5068 _ => true, 5069 }) 5070 .skip_type(move |ty| match ty { 5071 "Elf64_Phdr" | "Elf32_Phdr" => false, 5072 _ => true, 5073 }); 5074 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_elf.rs"); 5075 } 5076 5077 if (linux && !wali) || android { 5078 // Test `ARPHRD_CAN`. 5079 let mut cfg = ctest_cfg(); 5080 config_gnu_bits(target, &mut cfg); 5081 cfg.header("linux/if_arp.h"); 5082 cfg.skip_fn(|_| true) 5083 .skip_static(|_| true) 5084 .skip_const(move |name| match name { 5085 "ARPHRD_CAN" => false, 5086 _ => true, 5087 }) 5088 .skip_struct(|_| true) 5089 .skip_type(|_| true); 5090 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_if_arp.rs"); 5091 } 5092 } 5093 5094 fn which_freebsd() -> Option<i32> { 5095 if let Ok(version) = env::var("RUST_LIBC_UNSTABLE_FREEBSD_VERSION") { 5096 let vers = version.parse().unwrap(); 5097 println!("cargo:warning=setting FreeBSD version to {vers}"); 5098 return Some(vers); 5099 } 5100 5101 let output = std::process::Command::new("freebsd-version") 5102 .output() 5103 .ok()?; 5104 5105 if !output.status.success() { 5106 return None; 5107 } 5108 5109 let stdout = String::from_utf8(output.stdout).ok()?; 5110 5111 match &stdout { 5112 s if s.starts_with("10") => Some(10), 5113 s if s.starts_with("11") => Some(11), 5114 s if s.starts_with("12") => Some(12), 5115 s if s.starts_with("13") => Some(13), 5116 s if s.starts_with("14") => Some(14), 5117 s if s.starts_with("15") => Some(15), 5118 _ => None, 5119 } 5120 } 5121 5122 fn test_haiku(target: &str) { 5123 assert!(target.contains("haiku")); 5124 5125 let mut cfg = ctest_cfg(); 5126 cfg.flag("-Wno-deprecated-declarations"); 5127 cfg.define("__USE_GNU", Some("1")); 5128 cfg.define("_GNU_SOURCE", None); 5129 cfg.language(ctest::Lang::CXX); 5130 5131 // POSIX API 5132 headers! { cfg: 5133 "alloca.h", 5134 "arpa/inet.h", 5135 "arpa/nameser.h", 5136 "arpa/nameser_compat.h", 5137 "assert.h", 5138 "complex.h", 5139 "ctype.h", 5140 "dirent.h", 5141 "div_t.h", 5142 "dlfcn.h", 5143 "endian.h", 5144 "errno.h", 5145 "fcntl.h", 5146 "fenv.h", 5147 "fnmatch.h", 5148 "fts.h", 5149 "ftw.h", 5150 "getopt.h", 5151 "glob.h", 5152 "grp.h", 5153 "inttypes.h", 5154 "iovec.h", 5155 "langinfo.h", 5156 "libgen.h", 5157 "libio.h", 5158 "limits.h", 5159 "locale.h", 5160 "malloc.h", 5161 "malloc_debug.h", 5162 "math.h", 5163 "memory.h", 5164 "monetary.h", 5165 "net/if.h", 5166 "net/if_dl.h", 5167 "net/if_media.h", 5168 "net/if_tun.h", 5169 "net/if_types.h", 5170 "net/route.h", 5171 "netdb.h", 5172 "netinet/in.h", 5173 "netinet/ip.h", 5174 "netinet/ip6.h", 5175 "netinet/ip_icmp.h", 5176 "netinet/ip_var.h", 5177 "netinet/tcp.h", 5178 "netinet/udp.h", 5179 "netinet6/in6.h", 5180 "nl_types.h", 5181 "null.h", 5182 "poll.h", 5183 "pthread.h", 5184 "pwd.h", 5185 "regex.h", 5186 "resolv.h", 5187 "sched.h", 5188 "search.h", 5189 "semaphore.h", 5190 "setjmp.h", 5191 "shadow.h", 5192 "signal.h", 5193 "size_t.h", 5194 "spawn.h", 5195 "stdint.h", 5196 "stdio.h", 5197 "stdlib.h", 5198 "string.h", 5199 "strings.h", 5200 "sys/cdefs.h", 5201 "sys/file.h", 5202 "sys/ioctl.h", 5203 "sys/ipc.h", 5204 "sys/mman.h", 5205 "sys/msg.h", 5206 "sys/param.h", 5207 "sys/poll.h", 5208 "sys/resource.h", 5209 "sys/select.h", 5210 "sys/sem.h", 5211 "sys/socket.h", 5212 "sys/sockio.h", 5213 "sys/stat.h", 5214 "sys/statvfs.h", 5215 "sys/time.h", 5216 "sys/timeb.h", 5217 "sys/times.h", 5218 "sys/types.h", 5219 "sys/uio.h", 5220 "sys/un.h", 5221 "sys/utsname.h", 5222 "sys/wait.h", 5223 "syslog.h", 5224 "tar.h", 5225 "termios.h", 5226 "time.h", 5227 "uchar.h", 5228 "unistd.h", 5229 "utime.h", 5230 "utmpx.h", 5231 "wchar.h", 5232 "wchar_t.h", 5233 "wctype.h" 5234 } 5235 5236 // BSD Extensions 5237 headers! { cfg: 5238 "ifaddrs.h", 5239 "libutil.h", 5240 "link.h", 5241 "pty.h", 5242 "stdlib.h", 5243 "stringlist.h", 5244 "sys/link_elf.h", 5245 } 5246 5247 // Native API 5248 headers! { cfg: 5249 "kernel/OS.h", 5250 "kernel/fs_attr.h", 5251 "kernel/fs_index.h", 5252 "kernel/fs_info.h", 5253 "kernel/fs_query.h", 5254 "kernel/fs_volume.h", 5255 "kernel/image.h", 5256 "kernel/scheduler.h", 5257 "storage/FindDirectory.h", 5258 "storage/StorageDefs.h", 5259 "support/Errors.h", 5260 "support/SupportDefs.h", 5261 "support/TypeConstants.h" 5262 } 5263 5264 cfg.skip_struct(move |ty| { 5265 if ty.starts_with("__c_anonymous_") { 5266 return true; 5267 } 5268 match ty { 5269 // FIXME(union): actually a union 5270 "sigval" => true, 5271 // FIXME(haiku): locale_t does not exist on Haiku 5272 "locale_t" => true, 5273 // FIXME(haiku): rusage has a different layout on Haiku 5274 "rusage" => true, 5275 // FIXME(haiku): complains that rust aligns on 4 byte boundary, but 5276 // Haiku does not align it at all. 5277 "in6_addr" => true, 5278 // The d_name attribute is an array of 1 on Haiku, with the 5279 // intention that the developer allocates a larger or smaller 5280 // piece of memory depending on the expected/actual size of the name. 5281 // Other platforms have sensible defaults. In Rust, the d_name field 5282 // is sized as the _POSIX_MAX_PATH, so that path names will fit in 5283 // newly allocated dirent objects. This breaks the automated tests. 5284 "dirent" => true, 5285 // The following structs contain function pointers, which cannot be initialized 5286 // with mem::zeroed(), so skip the automated test 5287 "image_info" | "thread_info" => true, 5288 5289 "Elf64_Phdr" => true, 5290 5291 // is an union 5292 "cpuid_info" => true, 5293 5294 _ => false, 5295 } 5296 }); 5297 5298 cfg.skip_type(move |ty| { 5299 match ty { 5300 // FIXME(haiku): locale_t does not exist on Haiku 5301 "locale_t" => true, 5302 // These cause errors, to be reviewed in the future 5303 "sighandler_t" => true, 5304 "pthread_t" => true, 5305 "pthread_condattr_t" => true, 5306 "pthread_mutexattr_t" => true, 5307 "pthread_rwlockattr_t" => true, 5308 _ => false, 5309 } 5310 }); 5311 5312 cfg.skip_fn(move |name| { 5313 // skip those that are manually verified 5314 match name { 5315 // FIXME(haiku): https://github.com/rust-lang/libc/issues/1272 5316 "execv" | "execve" | "execvp" | "execvpe" => true, 5317 // FIXME: does not exist on haiku 5318 "open_wmemstream" => true, 5319 "mlockall" | "munlockall" => true, 5320 "tcgetsid" => true, 5321 "cfsetspeed" => true, 5322 // ignore for now, will be part of Haiku R1 beta 3 5323 "mlock" | "munlock" => true, 5324 // returns const char * on Haiku 5325 "strsignal" => true, 5326 // uses an enum as a parameter argument, which is incorrectly 5327 // translated into a struct argument 5328 "find_path" => true, 5329 5330 "get_cpuid" => true, 5331 5332 // uses varargs parameter 5333 "ioctl" => true, 5334 5335 _ => false, 5336 } 5337 }); 5338 5339 cfg.skip_const(move |name| { 5340 match name { 5341 // FIXME(haiku): these constants do not exist on Haiku 5342 "DT_UNKNOWN" | "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" 5343 | "DT_SOCK" => true, 5344 "USRQUOTA" | "GRPQUOTA" => true, 5345 "SIGIOT" => true, 5346 "ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM" | "ATF_PUBL" 5347 | "ATF_USETRAILERS" => true, 5348 // Haiku does not have MAP_FILE, but rustc requires it 5349 "MAP_FILE" => true, 5350 // The following does not exist on Haiku but is required by 5351 // several crates 5352 "FIOCLEX" => true, 5353 // just skip this one, it is not defined on Haiku beta 2 but 5354 // since it is meant as a mask and not a parameter it can exist 5355 // here 5356 "LOG_PRIMASK" => true, 5357 // not defined on Haiku, but [get|set]priority is, so they are 5358 // useful 5359 "PRIO_MIN" | "PRIO_MAX" => true, 5360 // 5361 _ => false, 5362 } 5363 }); 5364 5365 cfg.skip_field(move |struct_, field| { 5366 match (struct_, field) { 5367 // FIXME(time): the stat struct actually has timespec members, whereas 5368 // the current representation has these unpacked. 5369 ("stat", "st_atime") => true, 5370 ("stat", "st_atime_nsec") => true, 5371 ("stat", "st_mtime") => true, 5372 ("stat", "st_mtime_nsec") => true, 5373 ("stat", "st_ctime") => true, 5374 ("stat", "st_ctime_nsec") => true, 5375 ("stat", "st_crtime") => true, 5376 ("stat", "st_crtime_nsec") => true, 5377 5378 // these are actually unions, but we cannot represent it well 5379 ("siginfo_t", "sigval") => true, 5380 ("sem_t", "named_sem_id") => true, 5381 ("sigaction", "sa_sigaction") => true, 5382 ("sigevent", "sigev_value") => true, 5383 ("fpu_state", "_fpreg") => true, 5384 ("cpu_topology_node_info", "data") => true, 5385 // these fields have a simplified data definition in libc 5386 ("fpu_state", "_xmm") => true, 5387 ("savefpu", "_fp_ymm") => true, 5388 5389 // skip these enum-type fields 5390 ("thread_info", "state") => true, 5391 ("image_info", "image_type") => true, 5392 _ => false, 5393 } 5394 }); 5395 5396 cfg.skip_roundtrip(move |s| match s { 5397 // FIXME(1.0): for some reason the roundtrip check fails for cpu_info 5398 "cpu_info" => true, 5399 _ => false, 5400 }); 5401 5402 cfg.type_name(move |ty, is_struct, is_union| { 5403 match ty { 5404 // Just pass all these through, no need for a "struct" prefix 5405 "area_info" 5406 | "port_info" 5407 | "port_message_info" 5408 | "team_info" 5409 | "sem_info" 5410 | "team_usage_info" 5411 | "thread_info" 5412 | "cpu_info" 5413 | "system_info" 5414 | "object_wait_info" 5415 | "image_info" 5416 | "attr_info" 5417 | "index_info" 5418 | "fs_info" 5419 | "FILE" 5420 | "DIR" 5421 | "Dl_info" 5422 | "topology_level_type" 5423 | "cpu_topology_node_info" 5424 | "cpu_topology_root_info" 5425 | "cpu_topology_package_info" 5426 | "cpu_topology_core_info" => ty.to_string(), 5427 5428 // enums don't need a prefix 5429 "directory_which" | "path_base_directory" | "cpu_platform" | "cpu_vendor" => { 5430 ty.to_string() 5431 } 5432 5433 // is actually a union 5434 "sigval" => "union sigval".to_string(), 5435 t if is_union => format!("union {t}"), 5436 t if t.ends_with("_t") => t.to_string(), 5437 t if is_struct => format!("struct {t}"), 5438 t => t.to_string(), 5439 } 5440 }); 5441 5442 cfg.field_name(move |struct_, field| { 5443 match field { 5444 // Field is named `type` in C but that is a Rust keyword, 5445 // so these fields are translated to `type_` in the bindings. 5446 "type_" if struct_ == "object_wait_info" => "type".to_string(), 5447 "type_" if struct_ == "sem_t" => "type".to_string(), 5448 "type_" if struct_ == "attr_info" => "type".to_string(), 5449 "type_" if struct_ == "index_info" => "type".to_string(), 5450 "type_" if struct_ == "cpu_topology_node_info" => "type".to_string(), 5451 "image_type" if struct_ == "image_info" => "type".to_string(), 5452 s => s.to_string(), 5453 } 5454 }); 5455 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 5456 } 5457