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