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_MCE_PROCESS" 2066 | "PF_SUPERPRIV" 2067 | "PF_DUMPCORE" 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_BLOCK_TS" 2084 | "PF_SUSPEND_TASK" => true, 2085 2086 _ => false, 2087 } 2088 }); 2089 2090 cfg.skip_fn(move |name| { 2091 // skip those that are manually verified 2092 match name { 2093 // FIXME: https://github.com/rust-lang/libc/issues/1272 2094 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2095 2096 // There are two versions of the sterror_r function, see 2097 // 2098 // https://linux.die.net/man/3/strerror_r 2099 // 2100 // An XSI-compliant version provided if: 2101 // 2102 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE 2103 // 2104 // and a GNU specific version provided if _GNU_SOURCE is defined. 2105 // 2106 // libc provides bindings for the XSI-compliant version, which is 2107 // preferred for portable applications. 2108 // 2109 // We skip the test here since here _GNU_SOURCE is defined, and 2110 // test the XSI version below. 2111 "strerror_r" => true, 2112 "reallocarray" => true, 2113 "__system_property_wait" => true, 2114 2115 // Added in API level 30, but tests use level 28. 2116 "memfd_create" | "mlock2" | "renameat2" | "statx" | "statx_timestamp" => true, 2117 2118 // Added in glibc 2.25. 2119 "getentropy" => true, 2120 2121 // Added in API level 28, but some tests use level 24. 2122 "getrandom" => true, 2123 2124 // Added in API level 28, but some tests use level 24. 2125 "syncfs" => true, 2126 2127 // Added in API level 28, but some tests use level 24. 2128 "pthread_attr_getinheritsched" | "pthread_attr_setinheritsched" => true, 2129 // Added in API level 28, but some tests use level 24. 2130 "fread_unlocked" | "fwrite_unlocked" | "fgets_unlocked" | "fflush_unlocked" => true, 2131 2132 // Added in API level 28, but some tests use level 24. 2133 "aligned_alloc" => true, 2134 2135 // Added in API level 26, but some tests use level 24. 2136 "getgrent" => true, 2137 2138 // Added in API level 26, but some tests use level 24. 2139 "setgrent" => true, 2140 2141 // Added in API level 26, but some tests use level 24. 2142 "endgrent" => true, 2143 2144 // FIXME: bad function pointers: 2145 "isalnum" | "isalpha" | "iscntrl" | "isdigit" | "isgraph" | "islower" | "isprint" 2146 | "ispunct" | "isspace" | "isupper" | "isxdigit" | "isblank" | "tolower" 2147 | "toupper" => true, 2148 2149 _ => false, 2150 } 2151 }); 2152 2153 cfg.skip_field_type(move |struct_, field| { 2154 // This is a weird union, don't check the type. 2155 (struct_ == "ifaddrs" && field == "ifa_ifu") || 2156 // sigval is actually a union, but we pretend it's a struct 2157 (struct_ == "sigevent" && field == "sigev_value") || 2158 // this one is an anonymous union 2159 (struct_ == "ff_effect" && field == "u") || 2160 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 2161 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 2162 (struct_ == "sigaction" && field == "sa_sigaction") || 2163 // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet. 2164 (struct_ == "signalfd_siginfo" && field == "ssi_call_addr") || 2165 // FIXME: Seems the type has been changed on NDK r26b 2166 (struct_ == "flock64" && (field == "l_start" || field == "l_len")) 2167 }); 2168 2169 cfg.skip_field(|struct_, field| { 2170 match (struct_, field) { 2171 // conflicting with `p_type` macro from <resolve.h>. 2172 ("Elf32_Phdr", "p_type") => true, 2173 ("Elf64_Phdr", "p_type") => true, 2174 2175 // this is actually a union on linux, so we can't represent it well and 2176 // just insert some padding. 2177 ("siginfo_t", "_pad") => true, 2178 ("ifreq", "ifr_ifru") => true, 2179 ("ifconf", "ifc_ifcu") => true, 2180 2181 _ => false, 2182 } 2183 }); 2184 2185 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 2186 2187 test_linux_like_apis(target); 2188 } 2189 2190 fn test_freebsd(target: &str) { 2191 assert!(target.contains("freebsd")); 2192 let mut cfg = ctest_cfg(); 2193 2194 let freebsd_ver = which_freebsd(); 2195 2196 match freebsd_ver { 2197 Some(12) => cfg.cfg("freebsd12", None), 2198 Some(13) => cfg.cfg("freebsd13", None), 2199 Some(14) => cfg.cfg("freebsd14", None), 2200 Some(15) => cfg.cfg("freebsd15", None), 2201 _ => &mut cfg, 2202 }; 2203 2204 // For sched linux compat fn 2205 cfg.define("_WITH_CPU_SET_T", None); 2206 // Required for `getline`: 2207 cfg.define("_WITH_GETLINE", None); 2208 // Required for making freebsd11_stat available in the headers 2209 cfg.define("_WANT_FREEBSD11_STAT", None); 2210 2211 let freebsd13 = match freebsd_ver { 2212 Some(n) if n >= 13 => true, 2213 _ => false, 2214 }; 2215 let freebsd14 = match freebsd_ver { 2216 Some(n) if n >= 14 => true, 2217 _ => false, 2218 }; 2219 let freebsd15 = match freebsd_ver { 2220 Some(n) if n >= 15 => true, 2221 _ => false, 2222 }; 2223 2224 headers! { cfg: 2225 "aio.h", 2226 "arpa/inet.h", 2227 "bsm/audit.h", 2228 "ctype.h", 2229 "dirent.h", 2230 "dlfcn.h", 2231 "elf.h", 2232 "errno.h", 2233 "execinfo.h", 2234 "fcntl.h", 2235 "fnmatch.h", 2236 "getopt.h", 2237 "glob.h", 2238 "grp.h", 2239 "iconv.h", 2240 "ifaddrs.h", 2241 "kenv.h", 2242 "langinfo.h", 2243 "libgen.h", 2244 "libutil.h", 2245 "limits.h", 2246 "link.h", 2247 "locale.h", 2248 "machine/elf.h", 2249 "machine/reg.h", 2250 "malloc_np.h", 2251 "memstat.h", 2252 "mqueue.h", 2253 "net/bpf.h", 2254 "net/if.h", 2255 "net/if_arp.h", 2256 "net/if_dl.h", 2257 "net/if_mib.h", 2258 "net/route.h", 2259 "netdb.h", 2260 "netinet/ip.h", 2261 "netinet/in.h", 2262 "netinet/sctp.h", 2263 "netinet/tcp.h", 2264 "netinet/udp.h", 2265 "poll.h", 2266 "pthread.h", 2267 "pthread_np.h", 2268 "pwd.h", 2269 "regex.h", 2270 "resolv.h", 2271 "sched.h", 2272 "semaphore.h", 2273 "signal.h", 2274 "spawn.h", 2275 "stddef.h", 2276 "stdint.h", 2277 "stdio.h", 2278 "stdlib.h", 2279 "string.h", 2280 "sys/capsicum.h", 2281 "sys/auxv.h", 2282 "sys/cpuset.h", 2283 "sys/domainset.h", 2284 "sys/eui64.h", 2285 "sys/event.h", 2286 [freebsd13]:"sys/eventfd.h", 2287 "sys/extattr.h", 2288 "sys/file.h", 2289 "sys/ioctl.h", 2290 "sys/ipc.h", 2291 "sys/jail.h", 2292 "sys/mman.h", 2293 "sys/mount.h", 2294 "sys/msg.h", 2295 "sys/procctl.h", 2296 "sys/procdesc.h", 2297 "sys/ptrace.h", 2298 "sys/queue.h", 2299 "sys/random.h", 2300 "sys/reboot.h", 2301 "sys/resource.h", 2302 "sys/rtprio.h", 2303 "sys/sem.h", 2304 "sys/shm.h", 2305 "sys/socket.h", 2306 "sys/stat.h", 2307 "sys/statvfs.h", 2308 "sys/sysctl.h", 2309 "sys/thr.h", 2310 "sys/time.h", 2311 [freebsd14 || freebsd15]:"sys/timerfd.h", 2312 "sys/times.h", 2313 "sys/timex.h", 2314 "sys/types.h", 2315 "sys/proc.h", 2316 "kvm.h", // must be after "sys/types.h" 2317 "sys/ucontext.h", 2318 "sys/uio.h", 2319 "sys/ktrace.h", 2320 "sys/umtx.h", 2321 "sys/un.h", 2322 "sys/user.h", 2323 "sys/utsname.h", 2324 "sys/uuid.h", 2325 "sys/vmmeter.h", 2326 "sys/wait.h", 2327 "libprocstat.h", 2328 "devstat.h", 2329 "syslog.h", 2330 "termios.h", 2331 "time.h", 2332 "ufs/ufs/quota.h", 2333 "unistd.h", 2334 "utime.h", 2335 "utmpx.h", 2336 "wchar.h", 2337 } 2338 2339 cfg.type_name(move |ty, is_struct, is_union| { 2340 match ty { 2341 // Just pass all these through, no need for a "struct" prefix 2342 "FILE" 2343 | "fd_set" 2344 | "Dl_info" 2345 | "DIR" 2346 | "Elf32_Phdr" 2347 | "Elf64_Phdr" 2348 | "Elf32_Auxinfo" 2349 | "Elf64_Auxinfo" 2350 | "devstat_select_mode" 2351 | "devstat_support_flags" 2352 | "devstat_type_flags" 2353 | "devstat_match_flags" 2354 | "devstat_priority" => ty.to_string(), 2355 2356 // FIXME: https://github.com/rust-lang/libc/issues/1273 2357 "sighandler_t" => "sig_t".to_string(), 2358 2359 t if is_union => format!("union {}", t), 2360 2361 t if t.ends_with("_t") => t.to_string(), 2362 2363 // sigval is a struct in Rust, but a union in C: 2364 "sigval" => format!("union sigval"), 2365 2366 // put `struct` in front of all structs:. 2367 t if is_struct => format!("struct {}", t), 2368 2369 t => t.to_string(), 2370 } 2371 }); 2372 2373 cfg.field_name(move |struct_, field| { 2374 match field { 2375 // Our stat *_nsec fields normally don't actually exist but are part 2376 // of a timeval struct 2377 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2378 s.replace("e_nsec", ".tv_nsec") 2379 } 2380 // Field is named `type` in C but that is a Rust keyword, 2381 // so these fields are translated to `type_` in the bindings. 2382 "type_" if struct_ == "rtprio" => "type".to_string(), 2383 "type_" if struct_ == "sockstat" => "type".to_string(), 2384 "type_" if struct_ == "devstat_match_table" => "type".to_string(), 2385 s => s.to_string(), 2386 } 2387 }); 2388 2389 cfg.skip_const(move |name| { 2390 match name { 2391 // These constants were introduced in FreeBSD 13: 2392 "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" 2393 | "F_SEAL_WRITE" 2394 if Some(13) > freebsd_ver => 2395 { 2396 true 2397 } 2398 2399 // These constants were introduced in FreeBSD 13: 2400 "EFD_CLOEXEC" | "EFD_NONBLOCK" | "EFD_SEMAPHORE" if Some(13) > freebsd_ver => true, 2401 2402 // These constants were introduced in FreeBSD 12: 2403 "AT_RESOLVE_BENEATH" | "O_RESOLVE_BENEATH" if Some(12) > freebsd_ver => true, 2404 2405 // These constants were introduced in FreeBSD 13: 2406 "O_DSYNC" | "O_PATH" | "O_EMPTY_PATH" | "AT_EMPTY_PATH" if Some(13) > freebsd_ver => { 2407 true 2408 } 2409 2410 // These aliases were introduced in FreeBSD 13: 2411 // (note however that the constants themselves work on any version) 2412 "CLOCK_BOOTTIME" | "CLOCK_REALTIME_COARSE" | "CLOCK_MONOTONIC_COARSE" 2413 if Some(13) > freebsd_ver => 2414 { 2415 true 2416 } 2417 2418 // FIXME: These are deprecated - remove in a couple of releases. 2419 // These constants were removed in FreeBSD 11 (svn r273250) but will 2420 // still be accepted and ignored at runtime. 2421 "MAP_RENAME" | "MAP_NORESERVE" => true, 2422 2423 // FIXME: These are deprecated - remove in a couple of releases. 2424 // These constants were removed in FreeBSD 11 (svn r262489), 2425 // and they've never had any legitimate use outside of the 2426 // base system anyway. 2427 "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "USER_MAXID" => true, 2428 2429 // Deprecated and removed in FreeBSD 15. It was never actually implemented. 2430 "TCP_MAXPEAKRATE" => true, 2431 2432 // FIXME: This is deprecated - remove in a couple of releases. 2433 // This was removed in FreeBSD 14 (git 1b4701fe1e8) and never 2434 // should've been used anywhere anyway. 2435 "TDF_UNUSED23" => true, 2436 2437 // Removed in FreeBSD 15 2438 "TDF_CANSWAP" | "TDF_SWAPINREQ" => true, 2439 2440 // Unaccessible in FreeBSD 15 2441 "TDI_SWAPPED" | "P_SWAPPINGOUT" | "P_SWAPPINGIN" => true, 2442 2443 // Removed in FreeBSD 14 (git a6b55ee6be1) 2444 "IFF_KNOWSEPOCH" => true, 2445 2446 // Removed in FreeBSD 14 (git 7ff9ae90f0b) 2447 "IFF_NOGROUP" => true, 2448 2449 // FIXME: These are deprecated - remove in a couple of releases. 2450 // These symbols are not stable across OS-versions. They were 2451 // changed for FreeBSD 14 in git revisions b62848b0c3f and 2452 // 2cf7870864e. 2453 "PRI_MAX_ITHD" | "PRI_MIN_REALTIME" | "PRI_MAX_REALTIME" | "PRI_MIN_KERN" 2454 | "PRI_MAX_KERN" | "PSWP" | "PVM" | "PINOD" | "PRIBIO" | "PVFS" | "PZERO" | "PSOCK" 2455 | "PWAIT" | "PLOCK" | "PPAUSE" | "PRI_MIN_TIMESHARE" | "PUSER" | "PI_AV" | "PI_NET" 2456 | "PI_DISK" | "PI_TTY" | "PI_DULL" | "PI_SOFT" => true, 2457 2458 // This constant changed in FreeBSD 15 (git 3458bbd397783). It was never intended to 2459 // be stable, and probably shouldn't be bound by libc at all. 2460 "RLIM_NLIMITS" => true, 2461 2462 // This symbol changed in FreeBSD 14 (git 051e7d78b03), but the new 2463 // version should be safe to use on older releases. 2464 "IFCAP_CANTCHANGE" => true, 2465 2466 // These were removed in FreeBSD 14 (git c6d31b8306e) 2467 "TDF_ASTPENDING" | "TDF_NEEDSUSPCHK" | "TDF_NEEDRESCHED" | "TDF_NEEDSIGCHK" 2468 | "TDF_ALRMPEND" | "TDF_PROFPEND" | "TDF_MACPEND" => true, 2469 2470 // This constant was removed in FreeBSD 13 (svn r363622), and never 2471 // had any legitimate use outside of the base system anyway. 2472 "CTL_P1003_1B_MAXID" => true, 2473 2474 // This was renamed in FreeBSD 12.2 and 13 (r352486). 2475 "CTL_UNSPEC" | "CTL_SYSCTL" => true, 2476 2477 // This was renamed in FreeBSD 12.2 and 13 (r350749). 2478 "IPPROTO_SEP" | "IPPROTO_DCCP" => true, 2479 2480 // This was changed to 96(0x60) in FreeBSD 13: 2481 // https://github.com/freebsd/freebsd/ 2482 // commit/06b00ceaa914a3907e4e27bad924f44612bae1d7 2483 "MINCORE_SUPER" if Some(13) <= freebsd_ver => true, 2484 2485 // Added in FreeBSD 13.0 (r356667) 2486 "GRND_INSECURE" if Some(13) > freebsd_ver => true, 2487 2488 // Added in FreeBSD 13.0 (r349609) 2489 "PROC_PROTMAX_CTL" 2490 | "PROC_PROTMAX_STATUS" 2491 | "PROC_PROTMAX_FORCE_ENABLE" 2492 | "PROC_PROTMAX_FORCE_DISABLE" 2493 | "PROC_PROTMAX_NOFORCE" 2494 | "PROC_PROTMAX_ACTIVE" 2495 | "PROC_NO_NEW_PRIVS_CTL" 2496 | "PROC_NO_NEW_PRIVS_STATUS" 2497 | "PROC_NO_NEW_PRIVS_ENABLE" 2498 | "PROC_NO_NEW_PRIVS_DISABLE" 2499 | "PROC_WXMAP_CTL" 2500 | "PROC_WXMAP_STATUS" 2501 | "PROC_WX_MAPPINGS_PERMIT" 2502 | "PROC_WX_MAPPINGS_DISALLOW_EXEC" 2503 | "PROC_WXORX_ENFORCE" 2504 if Some(13) > freebsd_ver => 2505 { 2506 true 2507 } 2508 2509 // Added in FreeBSD 13.0 (r367776 and r367287) 2510 "SCM_CREDS2" | "LOCAL_CREDS_PERSISTENT" if Some(13) > freebsd_ver => true, 2511 2512 // Added in FreeBSD 14 2513 "SPACECTL_DEALLOC" if Some(14) > freebsd_ver => true, 2514 2515 // Added in FreeBSD 13. 2516 "KERN_PROC_SIGFASTBLK" 2517 | "USER_LOCALBASE" 2518 | "TDP_SIGFASTBLOCK" 2519 | "TDP_UIOHELD" 2520 | "TDP_SIGFASTPENDING" 2521 | "TDP2_COMPAT32RB" 2522 | "P2_PROTMAX_ENABLE" 2523 | "P2_PROTMAX_DISABLE" 2524 | "CTLFLAG_NEEDGIANT" 2525 | "CTL_SYSCTL_NEXTNOSKIP" 2526 if Some(13) > freebsd_ver => 2527 { 2528 true 2529 } 2530 2531 // Added in freebsd 14. 2532 "IFCAP_MEXTPG" if Some(14) > freebsd_ver => true, 2533 // Added in freebsd 13. 2534 "IFCAP_TXTLS4" | "IFCAP_TXTLS6" | "IFCAP_VXLAN_HWCSUM" | "IFCAP_VXLAN_HWTSO" 2535 | "IFCAP_TXTLS_RTLMT" | "IFCAP_TXTLS" 2536 if Some(13) > freebsd_ver => 2537 { 2538 true 2539 } 2540 // Added in FreeBSD 13. 2541 "PS_FST_TYPE_EVENTFD" if Some(13) > freebsd_ver => true, 2542 2543 // Added in FreeBSD 14. 2544 "MNT_RECURSE" | "MNT_DEFERRED" if Some(14) > freebsd_ver => true, 2545 2546 // Added in FreeBSD 13. 2547 "MNT_EXTLS" | "MNT_EXTLSCERT" | "MNT_EXTLSCERTUSER" | "MNT_NOCOVER" 2548 | "MNT_EMPTYDIR" 2549 if Some(13) > freebsd_ver => 2550 { 2551 true 2552 } 2553 2554 // Added in FreeBSD 14. 2555 "PT_COREDUMP" | "PC_ALL" | "PC_COMPRESS" | "PT_GETREGSET" | "PT_SETREGSET" 2556 | "PT_SC_REMOTE" 2557 if Some(14) > freebsd_ver => 2558 { 2559 true 2560 } 2561 2562 // Added in FreeBSD 14. 2563 "F_KINFO" => true, // FIXME: depends how frequent freebsd 14 is updated on CI, this addition went this week only. 2564 "SHM_RENAME_NOREPLACE" 2565 | "SHM_RENAME_EXCHANGE" 2566 | "SHM_LARGEPAGE_ALLOC_DEFAULT" 2567 | "SHM_LARGEPAGE_ALLOC_NOWAIT" 2568 | "SHM_LARGEPAGE_ALLOC_HARD" 2569 | "MFD_CLOEXEC" 2570 | "MFD_ALLOW_SEALING" 2571 | "MFD_HUGETLB" 2572 | "MFD_HUGE_MASK" 2573 | "MFD_HUGE_64KB" 2574 | "MFD_HUGE_512KB" 2575 | "MFD_HUGE_1MB" 2576 | "MFD_HUGE_2MB" 2577 | "MFD_HUGE_8MB" 2578 | "MFD_HUGE_16MB" 2579 | "MFD_HUGE_32MB" 2580 | "MFD_HUGE_256MB" 2581 | "MFD_HUGE_512MB" 2582 | "MFD_HUGE_1GB" 2583 | "MFD_HUGE_2GB" 2584 | "MFD_HUGE_16GB" 2585 if Some(13) > freebsd_ver => 2586 { 2587 true 2588 } 2589 2590 // Flags introduced in FreeBSD 14. 2591 "TCP_MAXUNACKTIME" 2592 | "TCP_IDLE_REDUCE" 2593 | "TCP_REMOTE_UDP_ENCAPS_PORT" 2594 | "TCP_DELACK" 2595 | "TCP_FIN_IS_RST" 2596 | "TCP_LOG_LIMIT" 2597 | "TCP_SHARED_CWND_ALLOWED" 2598 | "TCP_PROC_ACCOUNTING" 2599 | "TCP_USE_CMP_ACKS" 2600 | "TCP_PERF_INFO" 2601 | "TCP_LRD" 2602 if Some(14) > freebsd_ver => 2603 { 2604 true 2605 } 2606 2607 // Introduced in FreeBSD 14 then removed ? 2608 "TCP_LRD" if freebsd_ver >= Some(15) => true, 2609 2610 // Added in FreeBSD 14 2611 "LIO_READV" | "LIO_WRITEV" | "LIO_VECTORED" if Some(14) > freebsd_ver => true, 2612 2613 // Added in FreeBSD 13 2614 "FIOSSHMLPGCNF" if Some(13) > freebsd_ver => true, 2615 2616 // Added in FreeBSD 14 2617 "IFCAP_NV" if Some(14) > freebsd_ver => true, 2618 2619 // FIXME: Removed in https://reviews.freebsd.org/D38574 and https://reviews.freebsd.org/D38822 2620 // We maybe should deprecate them once a stable release ships them. 2621 "IP_BINDMULTI" | "IP_RSS_LISTEN_BUCKET" => true, 2622 2623 // FIXME: Removed in https://reviews.freebsd.org/D39127. 2624 "KERN_VNODE" => true, 2625 2626 // Added in FreeBSD 14 2627 "EV_KEEPUDATA" if Some(14) > freebsd_ver => true, 2628 2629 // Added in FreeBSD 13.2 2630 "AT_USRSTACKBASE" | "AT_USRSTACKLIM" if Some(13) > freebsd_ver => true, 2631 2632 // Added in FreeBSD 14 2633 "TFD_CLOEXEC" | "TFD_NONBLOCK" | "TFD_TIMER_ABSTIME" | "TFD_TIMER_CANCEL_ON_SET" 2634 if Some(14) > freebsd_ver => 2635 { 2636 true 2637 } 2638 2639 // Added in FreeBSD 14.1 2640 "KCMP_FILE" | "KCMP_FILEOBJ" | "KCMP_FILES" | "KCMP_SIGHAND" | "KCMP_VM" 2641 if Some(14) > freebsd_ver => 2642 { 2643 true 2644 } 2645 2646 // FIXME: Removed in FreeBSD 15: 2647 "LOCAL_CONNWAIT" if freebsd_ver >= Some(15) => true, 2648 2649 // FIXME: The values has been changed in FreeBSD 15: 2650 "CLOCK_BOOTTIME" if Some(15) <= freebsd_ver => true, 2651 2652 // Added in FreeBSD 14.0 2653 "TCP_FUNCTION_ALIAS" if Some(14) > freebsd_ver => true, 2654 2655 // These constants may change or disappear in future OS releases, and they probably 2656 // have no legitimate use in applications anyway. 2657 "CAP_UNUSED0_44" | "CAP_UNUSED0_57" | "CAP_UNUSED1_22" | "CAP_UNUSED1_57" | 2658 "CAP_ALL0" | "CAP_ALL1" => true, 2659 2660 _ => false, 2661 } 2662 }); 2663 2664 cfg.skip_type(move |ty| { 2665 match ty { 2666 // the struct "__kvm" is quite tricky to bind so since we only use a pointer to it 2667 // for now, it doesn't matter too much... 2668 "kvm_t" => true, 2669 // `eventfd(2)` and things come with it are added in FreeBSD 13 2670 "eventfd_t" if Some(13) > freebsd_ver => true, 2671 2672 _ => false, 2673 } 2674 }); 2675 2676 cfg.skip_struct(move |ty| { 2677 if ty.starts_with("__c_anonymous_") { 2678 return true; 2679 } 2680 match ty { 2681 // `procstat` is a private struct 2682 "procstat" => true, 2683 2684 // `spacectl_range` was introduced in FreeBSD 14 2685 "spacectl_range" if Some(14) > freebsd_ver => true, 2686 2687 // `ptrace_coredump` introduced in FreeBSD 14. 2688 "ptrace_coredump" if Some(14) > freebsd_ver => true, 2689 // `ptrace_sc_remote` introduced in FreeBSD 14. 2690 "ptrace_sc_remote" if Some(14) > freebsd_ver => true, 2691 2692 // `sockcred2` is not available in FreeBSD 12. 2693 "sockcred2" if Some(13) > freebsd_ver => true, 2694 // `shm_largepage_conf` was introduced in FreeBSD 13. 2695 "shm_largepage_conf" if Some(13) > freebsd_ver => true, 2696 2697 // Those are private types 2698 "memory_type" => true, 2699 "memory_type_list" => true, 2700 "pidfh" => true, 2701 "sctp_gen_error_cause" 2702 | "sctp_error_missing_param" 2703 | "sctp_remote_error" 2704 | "sctp_assoc_change" 2705 | "sctp_send_failed_event" 2706 | "sctp_stream_reset_event" => true, 2707 2708 // FIXME: Changed in FreeBSD 15 2709 "tcp_info" | "sockstat" if Some(15) >= freebsd_ver => true, 2710 2711 _ => false, 2712 } 2713 }); 2714 2715 cfg.skip_fn(move |name| { 2716 // skip those that are manually verified 2717 match name { 2718 // FIXME: https://github.com/rust-lang/libc/issues/1272 2719 // Also, `execvpe` is introduced in FreeBSD 14.1 2720 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2721 2722 // The `uname` function in the `utsname.h` FreeBSD header is a C 2723 // inline function (has no symbol) that calls the `__xuname` symbol. 2724 // Therefore the function pointer comparison does not make sense for it. 2725 "uname" => true, 2726 2727 // FIXME: Our API is unsound. The Rust API allows aliasing 2728 // pointers, but the C API requires pointers not to alias. 2729 // We should probably be at least using `&`/`&mut` here, see: 2730 // https://github.com/gnzlbg/ctest/issues/68 2731 "lio_listio" => true, 2732 2733 // Those are introduced in FreeBSD 12. 2734 "clock_nanosleep" | "getrandom" | "elf_aux_info" | "setproctitle_fast" 2735 | "timingsafe_bcmp" | "timingsafe_memcmp" 2736 if Some(12) > freebsd_ver => 2737 { 2738 true 2739 } 2740 2741 // Those are introduced in FreeBSD 13. 2742 "memfd_create" 2743 | "shm_create_largepage" 2744 | "shm_rename" 2745 | "getentropy" 2746 | "eventfd" 2747 | "SOCKCRED2SIZE" 2748 | "getlocalbase" 2749 | "aio_readv" 2750 | "aio_writev" 2751 | "copy_file_range" 2752 | "eventfd_read" 2753 | "eventfd_write" 2754 if Some(13) > freebsd_ver => 2755 { 2756 true 2757 } 2758 2759 // Those are introduced in FreeBSD 14. 2760 "sched_getaffinity" | "sched_setaffinity" | "sched_getcpu" | "fspacectl" 2761 if Some(14) > freebsd_ver => 2762 { 2763 true 2764 } 2765 2766 // Those are introduced in FreeBSD 14. 2767 "timerfd_create" | "timerfd_gettime" | "timerfd_settime" if Some(14) > freebsd_ver => { 2768 true 2769 } 2770 2771 // Those are introduced in FreeBSD 14.1. 2772 "kcmp" => true, 2773 2774 _ => false, 2775 } 2776 }); 2777 2778 cfg.volatile_item(|i| { 2779 use ctest::VolatileItemKind::*; 2780 match i { 2781 // aio_buf is a volatile void** but since we cannot express that in 2782 // Rust types, we have to explicitly tell the checker about it here: 2783 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 2784 _ => false, 2785 } 2786 }); 2787 2788 cfg.skip_field(move |struct_, field| { 2789 match (struct_, field) { 2790 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 2791 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 2792 ("sigaction", "sa_sigaction") => true, 2793 2794 // conflicting with `p_type` macro from <resolve.h>. 2795 ("Elf32_Phdr", "p_type") => true, 2796 ("Elf64_Phdr", "p_type") => true, 2797 2798 // not available until FreeBSD 12, and is an anonymous union there. 2799 ("xucred", "cr_pid__c_anonymous_union") => true, 2800 2801 // m_owner field is a volatile __lwpid_t 2802 ("umutex", "m_owner") => true, 2803 // c_has_waiters field is a volatile int32_t 2804 ("ucond", "c_has_waiters") => true, 2805 // is PATH_MAX long but tests can't accept multi array as equivalent. 2806 ("kinfo_vmentry", "kve_path") => true, 2807 2808 // a_un field is a union 2809 ("Elf32_Auxinfo", "a_un") => true, 2810 ("Elf64_Auxinfo", "a_un") => true, 2811 2812 // union fields 2813 ("if_data", "__ifi_epoch") => true, 2814 ("if_data", "__ifi_lastchange") => true, 2815 ("ifreq", "ifr_ifru") => true, 2816 ("ifconf", "ifc_ifcu") => true, 2817 2818 // anonymous struct 2819 ("devstat", "dev_links") => true, 2820 2821 // FIXME: structs too complicated to bind for now... 2822 ("kinfo_proc", "ki_paddr") => true, 2823 ("kinfo_proc", "ki_addr") => true, 2824 ("kinfo_proc", "ki_tracep") => true, 2825 ("kinfo_proc", "ki_textvp") => true, 2826 ("kinfo_proc", "ki_fd") => true, 2827 ("kinfo_proc", "ki_vmspace") => true, 2828 ("kinfo_proc", "ki_pcb") => true, 2829 ("kinfo_proc", "ki_tdaddr") => true, 2830 ("kinfo_proc", "ki_pd") => true, 2831 2832 // Anonymous type. 2833 ("filestat", "next") => true, 2834 2835 // We ignore this field because we needed to use a hack in order to make rust 1.19 2836 // happy... 2837 ("kinfo_proc", "ki_sparestrings") => true, 2838 2839 // `__sem_base` is a private struct field 2840 ("semid_ds", "__sem_base") => true, 2841 2842 // `snap_time` is a `long double`, but it's a nightmare to bind correctly in rust 2843 // for the moment, so it's a best effort thing... 2844 ("statinfo", "snap_time") => true, 2845 ("sctp_sndrcvinfo", "__reserve_pad") => true, 2846 ("sctp_extrcvinfo", "__reserve_pad") => true, 2847 // `tcp_snd_wscale` and `tcp_rcv_wscale` are bitfields 2848 ("tcp_info", "tcp_snd_wscale") => true, 2849 ("tcp_info", "tcp_rcv_wscale") => true, 2850 2851 _ => false, 2852 } 2853 }); 2854 if target.contains("arm") { 2855 cfg.skip_roundtrip(move |s| match s { 2856 // Can't return an array from a C function. 2857 "__gregset_t" => true, 2858 _ => false, 2859 }); 2860 } 2861 2862 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 2863 } 2864 2865 fn test_emscripten(target: &str) { 2866 assert!(target.contains("emscripten")); 2867 2868 let mut cfg = ctest_cfg(); 2869 cfg.define("_GNU_SOURCE", None); // FIXME: ?? 2870 2871 headers! { cfg: 2872 "ctype.h", 2873 "dirent.h", 2874 "dlfcn.h", 2875 "errno.h", 2876 "fcntl.h", 2877 "fnmatch.h", 2878 "glob.h", 2879 "grp.h", 2880 "ifaddrs.h", 2881 "langinfo.h", 2882 "limits.h", 2883 "locale.h", 2884 "malloc.h", 2885 "mntent.h", 2886 "mqueue.h", 2887 "net/ethernet.h", 2888 "net/if.h", 2889 "net/if_arp.h", 2890 "net/route.h", 2891 "netdb.h", 2892 "netinet/in.h", 2893 "netinet/ip.h", 2894 "netinet/tcp.h", 2895 "netinet/udp.h", 2896 "netpacket/packet.h", 2897 "poll.h", 2898 "pthread.h", 2899 "pty.h", 2900 "pwd.h", 2901 "resolv.h", 2902 "sched.h", 2903 "sched.h", 2904 "semaphore.h", 2905 "shadow.h", 2906 "signal.h", 2907 "stddef.h", 2908 "stdint.h", 2909 "stdio.h", 2910 "stdlib.h", 2911 "string.h", 2912 "sys/file.h", 2913 "sys/ioctl.h", 2914 "sys/ipc.h", 2915 "sys/mman.h", 2916 "sys/mount.h", 2917 "sys/msg.h", 2918 "sys/resource.h", 2919 "sys/sem.h", 2920 "sys/shm.h", 2921 "sys/socket.h", 2922 "sys/stat.h", 2923 "sys/statvfs.h", 2924 "sys/syscall.h", 2925 "sys/sysinfo.h", 2926 "sys/time.h", 2927 "sys/times.h", 2928 "sys/types.h", 2929 "sys/uio.h", 2930 "sys/un.h", 2931 "sys/user.h", 2932 "sys/utsname.h", 2933 "sys/vfs.h", 2934 "sys/wait.h", 2935 "sys/xattr.h", 2936 "syslog.h", 2937 "termios.h", 2938 "time.h", 2939 "ucontext.h", 2940 "unistd.h", 2941 "utime.h", 2942 "utmp.h", 2943 "utmpx.h", 2944 "wchar.h", 2945 } 2946 2947 cfg.type_name(move |ty, is_struct, is_union| { 2948 match ty { 2949 // Just pass all these through, no need for a "struct" prefix 2950 "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(), 2951 2952 // LFS64 types have been removed in Emscripten 3.1.44 2953 // https://github.com/emscripten-core/emscripten/pull/19812 2954 "off64_t" => "off_t".to_string(), 2955 2956 // typedefs don't need any keywords 2957 t if t.ends_with("_t") => t.to_string(), 2958 2959 // put `struct` in front of all structs:. 2960 t if is_struct => format!("struct {}", t), 2961 2962 // put `union` in front of all unions: 2963 t if is_union => format!("union {}", t), 2964 2965 t => t.to_string(), 2966 } 2967 }); 2968 2969 cfg.field_name(move |struct_, field| { 2970 match field { 2971 // Our stat *_nsec fields normally don't actually exist but are part 2972 // of a timeval struct 2973 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2974 s.replace("e_nsec", ".tv_nsec") 2975 } 2976 // Rust struct uses raw u64, rather than union 2977 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 2978 s => s.to_string(), 2979 } 2980 }); 2981 2982 cfg.skip_type(move |ty| { 2983 match ty { 2984 // sighandler_t is crazy across platforms 2985 // FIXME: is this necessary? 2986 "sighandler_t" => true, 2987 2988 // No epoll support 2989 // https://github.com/emscripten-core/emscripten/issues/5033 2990 ty if ty.starts_with("epoll") => true, 2991 2992 // LFS64 types have been removed in Emscripten 3.1.44 2993 // https://github.com/emscripten-core/emscripten/pull/19812 2994 t => t.ends_with("64") || t.ends_with("64_t"), 2995 } 2996 }); 2997 2998 cfg.skip_struct(move |ty| { 2999 match ty { 3000 // This is actually a union, not a struct 3001 "sigval" => true, 3002 3003 // FIXME: Investigate why the test fails. 3004 // Skip for now to unblock CI. 3005 "pthread_condattr_t" => true, 3006 "pthread_mutexattr_t" => true, 3007 3008 // No epoll support 3009 // https://github.com/emscripten-core/emscripten/issues/5033 3010 ty if ty.starts_with("epoll") => true, 3011 ty if ty.starts_with("signalfd") => true, 3012 3013 // LFS64 types have been removed in Emscripten 3.1.44 3014 // https://github.com/emscripten-core/emscripten/pull/19812 3015 ty => ty.ends_with("64") || ty.ends_with("64_t"), 3016 } 3017 }); 3018 3019 cfg.skip_fn(move |name| { 3020 match name { 3021 // Emscripten does not support fork/exec/wait or any kind of multi-process support 3022 // https://github.com/emscripten-core/emscripten/blob/3.1.68/tools/system_libs.py#L1100 3023 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" | "wait4" => true, 3024 3025 _ => false, 3026 } 3027 }); 3028 3029 cfg.skip_const(move |name| { 3030 match name { 3031 // FIXME: deprecated - SIGNUNUSED was removed in glibc 2.26 3032 // users should use SIGSYS instead 3033 "SIGUNUSED" => true, 3034 3035 // FIXME: emscripten uses different constants to constructs these 3036 n if n.contains("__SIZEOF_PTHREAD") => true, 3037 3038 // No epoll support 3039 // https://github.com/emscripten-core/emscripten/issues/5033 3040 n if n.starts_with("EPOLL") => true, 3041 3042 // No ptrace.h 3043 // https://github.com/emscripten-core/emscripten/pull/17704 3044 n if n.starts_with("PTRACE_") => true, 3045 3046 // No quota.h 3047 // https://github.com/emscripten-core/emscripten/pull/17704 3048 n if n.starts_with("QIF_") => true, 3049 "USRQUOTA" | "GRPQUOTA" | "Q_GETFMT" | "Q_GETINFO" | "Q_SETINFO" | "Q_SYNC" 3050 | "Q_QUOTAON" | "Q_QUOTAOFF" | "Q_GETQUOTA" | "Q_SETQUOTA" => true, 3051 3052 // `SYS_gettid` was removed in Emscripten v1.39.9 3053 // https://github.com/emscripten-core/emscripten/pull/10439 3054 "SYS_gettid" => true, 3055 3056 // No personality.h 3057 // https://github.com/emscripten-core/emscripten/pull/17704 3058 "ADDR_NO_RANDOMIZE" | "MMAP_PAGE_ZERO" | "ADDR_COMPAT_LAYOUT" | "READ_IMPLIES_EXEC" 3059 | "ADDR_LIMIT_32BIT" | "SHORT_INODE" | "WHOLE_SECONDS" | "STICKY_TIMEOUTS" 3060 | "ADDR_LIMIT_3GB" => true, 3061 3062 // `SIG_IGN` has been changed to -2 since 1 is a valid function address 3063 // https://github.com/emscripten-core/emscripten/pull/14883 3064 "SIG_IGN" => true, 3065 3066 // LFS64 types have been removed in Emscripten 3.1.44 3067 // https://github.com/emscripten-core/emscripten/pull/19812 3068 n if n.starts_with("RLIM64") => true, 3069 3070 _ => false, 3071 } 3072 }); 3073 3074 cfg.skip_field_type(move |struct_, field| { 3075 // This is a weird union, don't check the type. 3076 (struct_ == "ifaddrs" && field == "ifa_ifu") || 3077 // sighandler_t type is super weird 3078 (struct_ == "sigaction" && field == "sa_sigaction") || 3079 // sigval is actually a union, but we pretend it's a struct 3080 (struct_ == "sigevent" && field == "sigev_value") 3081 }); 3082 3083 cfg.skip_field(move |struct_, field| { 3084 // this is actually a union on linux, so we can't represent it well and 3085 // just insert some padding. 3086 (struct_ == "siginfo_t" && field == "_pad") || 3087 // musl names this __dummy1 but it's still there 3088 (struct_ == "glob_t" && field == "gl_flags") || 3089 // FIXME: After musl 1.1.24, it have only one field `sched_priority`, 3090 // while other fields become reserved. 3091 (struct_ == "sched_param" && [ 3092 "sched_ss_low_priority", 3093 "sched_ss_repl_period", 3094 "sched_ss_init_budget", 3095 "sched_ss_max_repl", 3096 ].contains(&field)) 3097 }); 3098 3099 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 3100 } 3101 3102 fn test_neutrino(target: &str) { 3103 assert!(target.contains("nto-qnx")); 3104 3105 let mut cfg = ctest_cfg(); 3106 3107 headers! { cfg: 3108 "ctype.h", 3109 "dirent.h", 3110 "dlfcn.h", 3111 "sys/elf.h", 3112 "fcntl.h", 3113 "fnmatch.h", 3114 "glob.h", 3115 "grp.h", 3116 "iconv.h", 3117 "ifaddrs.h", 3118 "limits.h", 3119 "sys/link.h", 3120 "locale.h", 3121 "sys/malloc.h", 3122 "rcheck/malloc.h", 3123 "malloc.h", 3124 "mqueue.h", 3125 "net/if.h", 3126 "net/if_arp.h", 3127 "net/route.h", 3128 "netdb.h", 3129 "netinet/in.h", 3130 "netinet/ip.h", 3131 "netinet/tcp.h", 3132 "netinet/udp.h", 3133 "netinet/ip_var.h", 3134 "sys/poll.h", 3135 "pthread.h", 3136 "pwd.h", 3137 "regex.h", 3138 "resolv.h", 3139 "sys/sched.h", 3140 "sched.h", 3141 "semaphore.h", 3142 "shadow.h", 3143 "signal.h", 3144 "spawn.h", 3145 "stddef.h", 3146 "stdint.h", 3147 "stdio.h", 3148 "stdlib.h", 3149 "string.h", 3150 "sys/sysctl.h", 3151 "sys/file.h", 3152 "sys/inotify.h", 3153 "sys/ioctl.h", 3154 "sys/ipc.h", 3155 "sys/mman.h", 3156 "sys/mount.h", 3157 "sys/msg.h", 3158 "sys/resource.h", 3159 "sys/sem.h", 3160 "sys/socket.h", 3161 "sys/stat.h", 3162 "sys/statvfs.h", 3163 "sys/swap.h", 3164 "sys/termio.h", 3165 "sys/time.h", 3166 "sys/times.h", 3167 "sys/types.h", 3168 "sys/uio.h", 3169 "sys/un.h", 3170 "sys/utsname.h", 3171 "sys/wait.h", 3172 "syslog.h", 3173 "termios.h", 3174 "time.h", 3175 "sys/time.h", 3176 "ucontext.h", 3177 "unistd.h", 3178 "utime.h", 3179 "utmp.h", 3180 "wchar.h", 3181 "aio.h", 3182 "nl_types.h", 3183 "langinfo.h", 3184 "unix.h", 3185 "nbutil.h", 3186 "aio.h", 3187 "net/bpf.h", 3188 "net/if_dl.h", 3189 "sys/syspage.h", 3190 3191 // TODO: The following header file doesn't appear as part of the default headers 3192 // found in a standard installation of Neutrino 7.1 SDP. The structures/ 3193 // functions dependent on it are currently commented out. 3194 //"sys/asyncmsg.h", 3195 } 3196 3197 // Create and include a header file containing 3198 // items which are not included in any official 3199 // header file. 3200 let internal_header = "internal.h"; 3201 let out_dir = env::var("OUT_DIR").unwrap(); 3202 cfg.header(internal_header); 3203 cfg.include(&out_dir); 3204 std::fs::write( 3205 out_dir.to_owned() + "/" + internal_header, 3206 "#ifndef __internal_h__ 3207 #define __internal_h__ 3208 void __my_thread_exit(const void **); 3209 #endif", 3210 ) 3211 .unwrap(); 3212 3213 cfg.type_name(move |ty, is_struct, is_union| { 3214 match ty { 3215 // Just pass all these through, no need for a "struct" prefix 3216 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 3217 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 3218 | "Elf32_Chdr" | "Elf64_Chdr" | "aarch64_qreg_t" | "syspage_entry_info" 3219 | "syspage_array_info" => ty.to_string(), 3220 3221 "Ioctl" => "int".to_string(), 3222 3223 t if is_union => format!("union {}", t), 3224 3225 t if t.ends_with("_t") => t.to_string(), 3226 3227 // put `struct` in front of all structs:. 3228 t if is_struct => format!("struct {}", t), 3229 3230 t => t.to_string(), 3231 } 3232 }); 3233 3234 cfg.field_name(move |_struct_, field| match field { 3235 "type_" => "type".to_string(), 3236 3237 s => s.to_string(), 3238 }); 3239 3240 cfg.volatile_item(|i| { 3241 use ctest::VolatileItemKind::*; 3242 match i { 3243 // The following fields are volatie but since we cannot express that in 3244 // Rust types, we have to explicitly tell the checker about it here: 3245 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 3246 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec_tod_adjust" => true, 3247 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec" => true, 3248 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec_stable" => true, 3249 StructField(ref n, ref f) if n == "intrspin" && f == "value" => true, 3250 _ => false, 3251 } 3252 }); 3253 3254 cfg.skip_type(move |ty| { 3255 match ty { 3256 // FIXME: `sighandler_t` type is incorrect, see: 3257 // https://github.com/rust-lang/libc/issues/1359 3258 "sighandler_t" => true, 3259 3260 // Does not exist in Neutrino 3261 "locale_t" => true, 3262 3263 _ => false, 3264 } 3265 }); 3266 3267 cfg.skip_struct(move |ty| { 3268 if ty.starts_with("__c_anonymous_") { 3269 return true; 3270 } 3271 match ty { 3272 "Elf64_Phdr" | "Elf32_Phdr" => true, 3273 3274 // FIXME: This is actually a union, not a struct 3275 "sigval" => true, 3276 3277 // union 3278 "_channel_connect_attr" => true, 3279 3280 _ => false, 3281 } 3282 }); 3283 3284 cfg.skip_const(move |name| { 3285 match name { 3286 // These signal "functions" are actually integer values that are casted to a fn ptr 3287 // This causes the compiler to err because of "illegal cast of int to ptr". 3288 "SIG_DFL" => true, 3289 "SIG_IGN" => true, 3290 "SIG_ERR" => true, 3291 3292 _ => false, 3293 } 3294 }); 3295 3296 cfg.skip_fn(move |name| { 3297 // skip those that are manually verified 3298 match name { 3299 // FIXME: https://github.com/rust-lang/libc/issues/1272 3300 "execv" | "execve" | "execvp" | "execvpe" => true, 3301 3302 // wrong signature 3303 "signal" => true, 3304 3305 // wrong signature of callback ptr 3306 "__cxa_atexit" => true, 3307 3308 // FIXME: Our API is unsound. The Rust API allows aliasing 3309 // pointers, but the C API requires pointers not to alias. 3310 // We should probably be at least using `&`/`&mut` here, see: 3311 // https://github.com/gnzlbg/ctest/issues/68 3312 "lio_listio" => true, 3313 3314 // 2 fields are actually unions which we're simply representing 3315 // as structures. 3316 "ChannelConnectAttr" => true, 3317 3318 // fields contains unions 3319 "SignalKillSigval" => true, 3320 "SignalKillSigval_r" => true, 3321 3322 // Not defined in any headers. Defined to work around a 3323 // stack unwinding bug. 3324 "__my_thread_exit" => true, 3325 3326 _ => false, 3327 } 3328 }); 3329 3330 cfg.skip_field_type(move |struct_, field| { 3331 // sigval is actually a union, but we pretend it's a struct 3332 struct_ == "sigevent" && field == "sigev_value" || 3333 // Anonymous structures 3334 struct_ == "_idle_hook" && field == "time" 3335 }); 3336 3337 cfg.skip_field(move |struct_, field| { 3338 (struct_ == "__sched_param" && field == "reserved") || 3339 (struct_ == "sched_param" && field == "reserved") || 3340 (struct_ == "sigevent" && field == "__padding1") || // ensure alignment 3341 (struct_ == "sigevent" && field == "__padding2") || // union 3342 (struct_ == "sigevent" && field == "__sigev_un2") || // union 3343 // sighandler_t type is super weird 3344 (struct_ == "sigaction" && field == "sa_sigaction") || 3345 // does not exist 3346 (struct_ == "syspage_entry" && field == "__reserved") || 3347 false // keep me for smaller diffs when something is added above 3348 }); 3349 3350 cfg.skip_static(move |name| (name == "__dso_handle")); 3351 3352 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 3353 } 3354 3355 fn test_vxworks(target: &str) { 3356 assert!(target.contains("vxworks")); 3357 3358 let mut cfg = ctest::TestGenerator::new(); 3359 headers! { cfg: 3360 "vxWorks.h", 3361 "yvals.h", 3362 "nfs/nfsCommon.h", 3363 "rtpLibCommon.h", 3364 "randomNumGen.h", 3365 "taskLib.h", 3366 "sysLib.h", 3367 "ioLib.h", 3368 "inetLib.h", 3369 "socket.h", 3370 "errnoLib.h", 3371 "ctype.h", 3372 "dirent.h", 3373 "dlfcn.h", 3374 "elf.h", 3375 "fcntl.h", 3376 "grp.h", 3377 "sys/poll.h", 3378 "ifaddrs.h", 3379 "langinfo.h", 3380 "limits.h", 3381 "link.h", 3382 "locale.h", 3383 "sys/stat.h", 3384 "netdb.h", 3385 "pthread.h", 3386 "pwd.h", 3387 "sched.h", 3388 "semaphore.h", 3389 "signal.h", 3390 "stddef.h", 3391 "stdint.h", 3392 "stdio.h", 3393 "stdlib.h", 3394 "string.h", 3395 "sys/file.h", 3396 "sys/ioctl.h", 3397 "sys/socket.h", 3398 "sys/time.h", 3399 "sys/times.h", 3400 "sys/types.h", 3401 "sys/uio.h", 3402 "sys/un.h", 3403 "sys/utsname.h", 3404 "sys/wait.h", 3405 "netinet/tcp.h", 3406 "syslog.h", 3407 "termios.h", 3408 "time.h", 3409 "ucontext.h", 3410 "unistd.h", 3411 "utime.h", 3412 "wchar.h", 3413 "errno.h", 3414 "sys/mman.h", 3415 "pathLib.h", 3416 "mqueue.h", 3417 } 3418 // FIXME 3419 cfg.skip_const(move |name| match name { 3420 // sighandler_t weirdness 3421 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" 3422 // This is not defined in vxWorks 3423 | "RTLD_DEFAULT" => true, 3424 _ => false, 3425 }); 3426 // FIXME 3427 cfg.skip_type(move |ty| match ty { 3428 "stat64" | "sighandler_t" | "off64_t" => true, 3429 _ => false, 3430 }); 3431 3432 cfg.skip_field_type(move |struct_, field| match (struct_, field) { 3433 ("siginfo_t", "si_value") | ("stat", "st_size") | ("sigaction", "sa_u") => true, 3434 _ => false, 3435 }); 3436 3437 cfg.skip_roundtrip(move |s| match s { 3438 _ => false, 3439 }); 3440 3441 cfg.type_name(move |ty, is_struct, is_union| match ty { 3442 "DIR" | "FILE" | "Dl_info" | "RTP_DESC" => ty.to_string(), 3443 t if is_union => format!("union {}", t), 3444 t if t.ends_with("_t") => t.to_string(), 3445 t if is_struct => format!("struct {}", t), 3446 t => t.to_string(), 3447 }); 3448 3449 // FIXME 3450 cfg.skip_fn(move |name| match name { 3451 // sigval 3452 "sigqueue" | "_sigqueue" 3453 // sighandler_t 3454 | "signal" 3455 // not used in static linking by default 3456 | "dlerror" => true, 3457 _ => false, 3458 }); 3459 3460 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 3461 } 3462 3463 fn test_linux(target: &str) { 3464 assert!(target.contains("linux")); 3465 3466 // target_env 3467 let gnu = target.contains("gnu"); 3468 let musl = target.contains("musl") || target.contains("ohos"); 3469 let uclibc = target.contains("uclibc"); 3470 3471 match (gnu, musl, uclibc) { 3472 (true, false, false) => (), 3473 (false, true, false) => (), 3474 (false, false, true) => (), 3475 (_, _, _) => panic!( 3476 "linux target lib is gnu: {}, musl: {}, uclibc: {}", 3477 gnu, musl, uclibc 3478 ), 3479 } 3480 3481 let arm = target.contains("arm"); 3482 let aarch64 = target.contains("aarch64"); 3483 let i686 = target.contains("i686"); 3484 let ppc = target.contains("powerpc"); 3485 let ppc64 = target.contains("powerpc64"); 3486 let s390x = target.contains("s390x"); 3487 let sparc64 = target.contains("sparc64"); 3488 let x32 = target.contains("x32"); 3489 let x86_32 = target.contains("i686"); 3490 let x86_64 = target.contains("x86_64"); 3491 let aarch64_musl = aarch64 && musl; 3492 let gnueabihf = target.contains("gnueabihf"); 3493 let x86_64_gnux32 = target.contains("gnux32") && x86_64; 3494 let riscv64 = target.contains("riscv64"); 3495 let loongarch64 = target.contains("loongarch64"); 3496 let uclibc = target.contains("uclibc"); 3497 3498 let mut cfg = ctest_cfg(); 3499 cfg.define("_GNU_SOURCE", None); 3500 // This macro re-defines fscanf,scanf,sscanf to link to the symbols that are 3501 // deprecated since glibc >= 2.29. This allows Rust binaries to link against 3502 // glibc versions older than 2.29. 3503 cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None); 3504 3505 headers! { cfg: 3506 "ctype.h", 3507 "dirent.h", 3508 "dlfcn.h", 3509 "elf.h", 3510 "fcntl.h", 3511 "fnmatch.h", 3512 "getopt.h", 3513 "glob.h", 3514 [gnu]: "gnu/libc-version.h", 3515 "grp.h", 3516 "iconv.h", 3517 "ifaddrs.h", 3518 "langinfo.h", 3519 "libgen.h", 3520 "limits.h", 3521 "link.h", 3522 "linux/sysctl.h", 3523 "locale.h", 3524 "malloc.h", 3525 "mntent.h", 3526 "mqueue.h", 3527 "net/ethernet.h", 3528 "net/if.h", 3529 "net/if_arp.h", 3530 "net/route.h", 3531 "netdb.h", 3532 "netinet/in.h", 3533 "netinet/ip.h", 3534 "netinet/tcp.h", 3535 "netinet/udp.h", 3536 "poll.h", 3537 "pthread.h", 3538 "pty.h", 3539 "pwd.h", 3540 "regex.h", 3541 "resolv.h", 3542 "sched.h", 3543 "semaphore.h", 3544 "shadow.h", 3545 "signal.h", 3546 "spawn.h", 3547 "stddef.h", 3548 "stdint.h", 3549 "stdio.h", 3550 "stdlib.h", 3551 "string.h", 3552 "sys/epoll.h", 3553 "sys/eventfd.h", 3554 "sys/file.h", 3555 "sys/fsuid.h", 3556 "sys/klog.h", 3557 "sys/inotify.h", 3558 "sys/ioctl.h", 3559 "sys/ipc.h", 3560 "sys/mman.h", 3561 "sys/mount.h", 3562 "sys/msg.h", 3563 "sys/personality.h", 3564 "sys/prctl.h", 3565 "sys/ptrace.h", 3566 "sys/quota.h", 3567 "sys/random.h", 3568 "sys/reboot.h", 3569 "sys/resource.h", 3570 "sys/sem.h", 3571 "sys/sendfile.h", 3572 "sys/shm.h", 3573 "sys/signalfd.h", 3574 "sys/socket.h", 3575 "sys/stat.h", 3576 "sys/statvfs.h", 3577 "sys/swap.h", 3578 "sys/syscall.h", 3579 "sys/time.h", 3580 "sys/timerfd.h", 3581 "sys/times.h", 3582 "sys/timex.h", 3583 "sys/types.h", 3584 "sys/uio.h", 3585 "sys/un.h", 3586 "sys/user.h", 3587 "sys/utsname.h", 3588 "sys/vfs.h", 3589 "sys/wait.h", 3590 "syslog.h", 3591 "termios.h", 3592 "time.h", 3593 "ucontext.h", 3594 "unistd.h", 3595 "utime.h", 3596 "utmp.h", 3597 "utmpx.h", 3598 "wchar.h", 3599 "errno.h", 3600 // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit 3601 // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162 3602 // Also unavailable on gnueabihf with glibc 2.30. 3603 // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6b33f373c7b9199e00ba5fbafd94ac9bfb4337b1 3604 [(x86_64 || x86_32 || arm) && !gnueabihf]: "sys/io.h", 3605 // `sys/reg.h` is only available on x86 and x86_64 3606 [x86_64 || x86_32]: "sys/reg.h", 3607 // sysctl system call is deprecated and not available on musl 3608 // It is also unsupported in x32, deprecated since glibc 2.30: 3609 [!(x32 || musl || gnu)]: "sys/sysctl.h", 3610 // <execinfo.h> is not supported by musl: 3611 // https://www.openwall.com/lists/musl/2015/04/09/3 3612 // <execinfo.h> is not present on uclibc. 3613 [!(musl || uclibc)]: "execinfo.h", 3614 } 3615 3616 // Include linux headers at the end: 3617 headers! { 3618 cfg: 3619 [loongarch64 || riscv64]: "asm/hwcap.h", 3620 "asm/mman.h", 3621 [gnu]: "linux/aio_abi.h", 3622 "linux/can.h", 3623 "linux/can/raw.h", 3624 "linux/can/j1939.h", 3625 "linux/dccp.h", 3626 "linux/errqueue.h", 3627 "linux/falloc.h", 3628 "linux/filter.h", 3629 "linux/fs.h", 3630 "linux/futex.h", 3631 "linux/genetlink.h", 3632 "linux/if.h", 3633 "linux/if_addr.h", 3634 "linux/if_alg.h", 3635 "linux/if_ether.h", 3636 "linux/if_packet.h", 3637 "linux/if_tun.h", 3638 "linux/if_xdp.h", 3639 "linux/input.h", 3640 "linux/ipv6.h", 3641 "linux/kexec.h", 3642 "linux/keyctl.h", 3643 "linux/magic.h", 3644 "linux/memfd.h", 3645 "linux/membarrier.h", 3646 "linux/mempolicy.h", 3647 "linux/mman.h", 3648 "linux/module.h", 3649 "linux/mount.h", 3650 "linux/net_tstamp.h", 3651 "linux/netfilter/nfnetlink.h", 3652 "linux/netfilter/nfnetlink_log.h", 3653 "linux/netfilter/nfnetlink_queue.h", 3654 "linux/netfilter/nf_tables.h", 3655 "linux/netfilter_arp.h", 3656 "linux/netfilter_bridge.h", 3657 "linux/netfilter_ipv4.h", 3658 "linux/netfilter_ipv6.h", 3659 "linux/netfilter_ipv6/ip6_tables.h", 3660 "linux/netlink.h", 3661 "linux/openat2.h", 3662 // FIXME: some items require Linux >= 5.6: 3663 "linux/ptp_clock.h", 3664 "linux/ptrace.h", 3665 "linux/quota.h", 3666 "linux/random.h", 3667 "linux/reboot.h", 3668 "linux/rtnetlink.h", 3669 "linux/sched.h", 3670 "linux/sctp.h", 3671 "linux/seccomp.h", 3672 "linux/sock_diag.h", 3673 "linux/sockios.h", 3674 "linux/tls.h", 3675 "linux/uinput.h", 3676 "linux/vm_sockets.h", 3677 "linux/wait.h", 3678 "linux/wireless.h", 3679 "sys/fanotify.h", 3680 // <sys/auxv.h> is not present on uclibc 3681 [!uclibc]: "sys/auxv.h", 3682 [gnu || musl]: "linux/close_range.h", 3683 } 3684 3685 // note: aio.h must be included before sys/mount.h 3686 headers! { 3687 cfg: 3688 "sys/xattr.h", 3689 "sys/sysinfo.h", 3690 // AIO is not supported by uclibc: 3691 [!uclibc]: "aio.h", 3692 } 3693 3694 cfg.type_name(move |ty, is_struct, is_union| { 3695 match ty { 3696 // Just pass all these through, no need for a "struct" prefix 3697 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 3698 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 3699 | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(), 3700 3701 "Ioctl" if gnu => "unsigned long".to_string(), 3702 "Ioctl" => "int".to_string(), 3703 3704 // LFS64 types have been removed in musl 1.2.4+ 3705 "off64_t" if musl => "off_t".to_string(), 3706 3707 // typedefs don't need any keywords 3708 t if t.ends_with("_t") => t.to_string(), 3709 // put `struct` in front of all structs:. 3710 t if is_struct => format!("struct {}", t), 3711 // put `union` in front of all unions: 3712 t if is_union => format!("union {}", t), 3713 3714 t => t.to_string(), 3715 } 3716 }); 3717 3718 cfg.field_name(move |struct_, field| { 3719 match field { 3720 // Our stat *_nsec fields normally don't actually exist but are part 3721 // of a timeval struct 3722 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 3723 s.replace("e_nsec", ".tv_nsec") 3724 } 3725 // FIXME: epoll_event.data is actually a union in C, but in Rust 3726 // it is only a u64 because we only expose one field 3727 // http://man7.org/linux/man-pages/man2/epoll_wait.2.html 3728 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 3729 // The following structs have a field called `type` in C, 3730 // but `type` is a Rust keyword, so these fields are translated 3731 // to `type_` in Rust. 3732 "type_" 3733 if struct_ == "input_event" 3734 || struct_ == "input_mask" 3735 || struct_ == "ff_effect" => 3736 { 3737 "type".to_string() 3738 } 3739 3740 s => s.to_string(), 3741 } 3742 }); 3743 3744 cfg.skip_type(move |ty| { 3745 // FIXME: very recent additions to musl, not yet released. 3746 // also apparently some glibc versions 3747 if ty == "Elf32_Relr" || ty == "Elf64_Relr" { 3748 return true; 3749 } 3750 if sparc64 && (ty == "Elf32_Rela" || ty == "Elf64_Rela") { 3751 return true; 3752 } 3753 match ty { 3754 // FIXME: `sighandler_t` type is incorrect, see: 3755 // https://github.com/rust-lang/libc/issues/1359 3756 "sighandler_t" => true, 3757 3758 // These cannot be tested when "resolv.h" is included and are tested 3759 // in the `linux_elf.rs` file. 3760 "Elf64_Phdr" | "Elf32_Phdr" => true, 3761 3762 // This type is private on Linux. It is implemented as a C `enum` 3763 // (`c_uint`) and this clashes with the type of the `rlimit` APIs 3764 // which expect a `c_int` even though both are ABI compatible. 3765 "__rlimit_resource_t" => true, 3766 // on Linux, this is a volatile int 3767 "pthread_spinlock_t" => true, 3768 3769 // For internal use only, to define architecture specific ioctl constants with a libc 3770 // specific type. 3771 "Ioctl" => true, 3772 3773 // FIXME: "'__uint128' undeclared" in C 3774 "__uint128" => true, 3775 3776 t => { 3777 if musl { 3778 // LFS64 types have been removed in musl 1.2.4+ 3779 t.ends_with("64") || t.ends_with("64_t") 3780 } else { 3781 false 3782 } 3783 } 3784 } 3785 }); 3786 3787 cfg.skip_struct(move |ty| { 3788 if ty.starts_with("__c_anonymous_") { 3789 return true; 3790 } 3791 3792 // FIXME: CI has old headers 3793 if ty == "ptp_sys_offset_extended" { 3794 return true; 3795 } 3796 3797 // LFS64 types have been removed in musl 1.2.4+ 3798 if musl && (ty.ends_with("64") || ty.ends_with("64_t")) { 3799 return true; 3800 } 3801 3802 // FIXME: sparc64 CI has old headers 3803 if sparc64 && (ty == "uinput_ff_erase" || ty == "uinput_abs_setup") { 3804 return true; 3805 } 3806 3807 // FIXME(#1558): passing by value corrupts the value for reasons not understood. 3808 if (gnu && sparc64) && (ty == "ip_mreqn" || ty == "hwtstamp_config") { 3809 return true; 3810 } 3811 3812 // FIXME(rust-lang/rust#43894): pass by value for structs that are not an even 32/64 bits 3813 // on big-endian systems corrupts the value for unknown reasons. 3814 if (sparc64 || ppc || ppc64 || s390x) 3815 && (ty == "sockaddr_pkt" 3816 || ty == "tpacket_auxdata" 3817 || ty == "tpacket_hdr_variant1" 3818 || ty == "tpacket_req3" 3819 || ty == "tpacket_stats_v3" 3820 || ty == "tpacket_req_u") 3821 { 3822 return true; 3823 } 3824 3825 // FIXME: musl doesn't compile with `struct fanout_args` for unknown reasons. 3826 if musl && ty == "fanout_args" { 3827 return true; 3828 } 3829 if sparc64 && ty == "fanotify_event_info_error" { 3830 return true; 3831 } 3832 3833 match ty { 3834 // These cannot be tested when "resolv.h" is included and are tested 3835 // in the `linux_elf.rs` file. 3836 "Elf64_Phdr" | "Elf32_Phdr" => true, 3837 3838 // On Linux, the type of `ut_tv` field of `struct utmpx` 3839 // can be an anonymous struct, so an extra struct, 3840 // which is absent in glibc, has to be defined. 3841 "__timeval" => true, 3842 3843 // FIXME: This is actually a union, not a struct 3844 "sigval" => true, 3845 3846 // This type is tested in the `linux_termios.rs` file since there 3847 // are header conflicts when including them with all the other 3848 // structs. 3849 "termios2" => true, 3850 3851 // FIXME: remove once we set minimum supported glibc version. 3852 // ucontext_t added a new field as of glibc 2.28; our struct definition is 3853 // conservative and omits the field, but that means the size doesn't match for newer 3854 // glibcs (see https://github.com/rust-lang/libc/issues/1410) 3855 "ucontext_t" if gnu => true, 3856 3857 // FIXME: Somehow we cannot include headers correctly in glibc 2.30. 3858 // So let's ignore for now and re-visit later. 3859 // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085 3860 "statx" => true, 3861 "statx_timestamp" => true, 3862 3863 // On Linux, the type of `ut_exit` field of struct `utmpx` 3864 // can be an anonymous struct, so an extra struct, 3865 // which is absent in musl, has to be defined. 3866 "__exit_status" if musl => true, 3867 3868 // clone_args might differ b/w libc versions 3869 "clone_args" => true, 3870 3871 // Might differ between kernel versions 3872 "open_how" => true, 3873 3874 "sctp_initmsg" | "sctp_sndrcvinfo" | "sctp_sndinfo" | "sctp_rcvinfo" 3875 | "sctp_nxtinfo" | "sctp_prinfo" | "sctp_authinfo" => true, 3876 3877 // FIXME: requires >= 6.1 kernel headers 3878 "canxl_frame" => true, 3879 3880 // FIXME: The size of `iv` has been changed since Linux v6.0 3881 // https://github.com/torvalds/linux/commit/94dfc73e7cf4a31da66b8843f0b9283ddd6b8381 3882 "af_alg_iv" => true, 3883 3884 // FIXME: Requires >= 5.1 kernel headers. 3885 // Everything that uses install-musl.sh has 4.19 kernel headers. 3886 "tls12_crypto_info_aes_gcm_256" 3887 if (aarch64 || arm || i686 || s390x || x86_64) && musl => 3888 { 3889 true 3890 } 3891 3892 // FIXME: Requires >= 5.11 kernel headers. 3893 // Everything that uses install-musl.sh has 4.19 kernel headers. 3894 "tls12_crypto_info_chacha20_poly1305" 3895 if (aarch64 || arm || i686 || s390x || x86_64) && musl => 3896 { 3897 true 3898 } 3899 3900 // FIXME: Requires >= 5.3 kernel headers. 3901 // Everything that uses install-musl.sh has 4.19 kernel headers. 3902 "xdp_options" if musl => true, 3903 3904 // FIXME: Requires >= 5.4 kernel headers. 3905 // Everything that uses install-musl.sh has 4.19 kernel headers. 3906 "xdp_ring_offset" | "xdp_mmap_offsets" if musl => true, 3907 3908 // FIXME: Requires >= 6.8 kernel headers. 3909 // A field was added in 6.8. 3910 // https://github.com/torvalds/linux/commit/341ac980eab90ac1f6c22ee9f9da83ed9604d899 3911 // The previous version of the struct was removed in 6.11 due to a bug. 3912 // https://github.com/torvalds/linux/commit/32654bbd6313b4cfc82297e6634fa9725c3c900f 3913 "xdp_umem_reg" => true, 3914 3915 // FIXME: Requires >= 5.9 kernel headers. 3916 // Everything that uses install-musl.sh has 4.19 kernel headers. 3917 "xdp_statistics" if musl => true, 3918 3919 // FIXME: Requires >= 6.8 kernel headers. 3920 "xsk_tx_metadata" 3921 | "__c_anonymous_xsk_tx_metadata_union" 3922 | "xsk_tx_metadata_request" 3923 | "xsk_tx_metadata_completion" => true, 3924 3925 // A new field was added in kernel 5.4, this is the old version for backwards compatibility. 3926 // https://github.com/torvalds/linux/commit/77cd0d7b3f257fd0e3096b4fdcff1a7d38e99e10 3927 "xdp_ring_offset_v1" | "xdp_mmap_offsets_v1" => true, 3928 3929 // Multiple new fields were added in kernel 5.9, this is the old version for backwards compatibility. 3930 // https://github.com/torvalds/linux/commit/77cd0d7b3f257fd0e3096b4fdcff1a7d38e99e10 3931 "xdp_statistics_v1" => true, 3932 3933 // A new field was added in kernel 5.4, this is the old version for backwards compatibility. 3934 // https://github.com/torvalds/linux/commit/c05cd3645814724bdeb32a2b4d953b12bdea5f8c 3935 "xdp_umem_reg_v1" => true, 3936 3937 // Is defined in `<linux/sched/types.h>` but if this file is included at the same time 3938 // as `<sched.h>`, the `struct sched_param` is defined twice, causing the compilation to 3939 // fail. The problem doesn't seem to be present in more recent versions of the linux 3940 // kernel so we can drop this and test the type once this new version is used in CI. 3941 "sched_attr" => true, 3942 3943 // FIXME: Requires >= 6.9 kernel headers. 3944 "epoll_params" => true, 3945 3946 _ => false, 3947 } 3948 }); 3949 3950 cfg.skip_const(move |name| { 3951 if !gnu { 3952 // Skip definitions from the kernel on non-glibc Linux targets. 3953 // They're libc-independent, so we only need to check them on one 3954 // libc. We don't want to break CI if musl or another libc doesn't 3955 // have the definitions yet. (We do still want to check them on 3956 // every glibc target, though, as some of them can vary by 3957 // architecture.) 3958 // 3959 // This is not an exhaustive list of kernel constants, just a list 3960 // of prefixes of all those that have appeared here or that get 3961 // updated regularly and seem likely to cause breakage. 3962 if name.starts_with("AF_") 3963 || name.starts_with("ARPHRD_") 3964 || name.starts_with("EPOLL") 3965 || name.starts_with("F_") 3966 || name.starts_with("FALLOC_FL_") 3967 || name.starts_with("IFLA_") 3968 || name.starts_with("KEXEC_") 3969 || name.starts_with("MS_") 3970 || name.starts_with("MSG_") 3971 || name.starts_with("OPEN_TREE_") 3972 || name.starts_with("P_") 3973 || name.starts_with("PF_") 3974 || name.starts_with("RLIMIT_") 3975 || name.starts_with("RTEXT_FILTER_") 3976 || name.starts_with("SOL_") 3977 || name.starts_with("STATX_") 3978 || name.starts_with("SW_") 3979 || name.starts_with("SYS_") 3980 || name.starts_with("TCP_") 3981 || name.starts_with("UINPUT_") 3982 || name.starts_with("VMADDR_") 3983 { 3984 return true; 3985 } 3986 } 3987 if musl { 3988 // FIXME: Requires >= 5.0 kernel headers 3989 if name == "SECCOMP_GET_NOTIF_SIZES" 3990 || name == "SECCOMP_FILTER_FLAG_NEW_LISTENER" 3991 || name == "SECCOMP_FILTER_FLAG_TSYNC_ESRCH" 3992 || name == "SECCOMP_USER_NOTIF_FLAG_CONTINUE" // requires >= 5.5 3993 || name == "SECCOMP_ADDFD_FLAG_SETFD" // requires >= 5.9 3994 || name == "SECCOMP_ADDFD_FLAG_SEND" // requires >= 5.9 3995 || name == "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV" // requires >= 5.19 3996 { 3997 return true; 3998 } 3999 // FIXME: Requires >= 4.20 kernel headers 4000 if name == "PTP_SYS_OFFSET_EXTENDED" { 4001 return true; 4002 } 4003 // FIXME: Requires >= 5.4 kernel headers 4004 if name == "PTP_CLOCK_GETCAPS2" 4005 || name == "PTP_ENABLE_PPS2" 4006 || name == "PTP_EXTTS_REQUEST2" 4007 || name == "PTP_PEROUT_REQUEST2" 4008 || name == "PTP_PIN_GETFUNC2" 4009 || name == "PTP_PIN_SETFUNC2" 4010 || name == "PTP_SYS_OFFSET2" 4011 || name == "PTP_SYS_OFFSET_PRECISE2" 4012 || name == "PTP_SYS_OFFSET_EXTENDED2" 4013 { 4014 return true; 4015 } 4016 // FIXME: Requires >= 5.4.1 kernel headers 4017 if name.starts_with("J1939") 4018 || name.starts_with("RTEXT_FILTER_") 4019 || name.starts_with("SO_J1939") 4020 || name.starts_with("SCM_J1939") 4021 { 4022 return true; 4023 } 4024 // FIXME: Requires >= 5.10 kernel headers 4025 if name.starts_with("MEMBARRIER_CMD_REGISTER") 4026 || name.starts_with("MEMBARRIER_CMD_PRIVATE") 4027 { 4028 return true; 4029 } 4030 // LFS64 types have been removed in musl 1.2.4+ 4031 if name.starts_with("RLIM64") { 4032 return true; 4033 } 4034 // CI fails because musl targets use Linux v4 kernel 4035 if name.starts_with("NI_IDN") { 4036 return true; 4037 } 4038 // FIXME: Requires >= 6.3 kernel headers 4039 if loongarch64 && (name == "MFD_NOEXEC_SEAL" || name == "MFD_EXEC") { 4040 return true; 4041 } 4042 } 4043 match name { 4044 // These constants are not available if gnu headers have been included 4045 // and can therefore not be tested here 4046 // 4047 // The IPV6 constants are tested in the `linux_ipv6.rs` tests: 4048 | "IPV6_FLOWINFO" 4049 | "IPV6_FLOWLABEL_MGR" 4050 | "IPV6_FLOWINFO_SEND" 4051 | "IPV6_FLOWINFO_FLOWLABEL" 4052 | "IPV6_FLOWINFO_PRIORITY" 4053 // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: 4054 | "F_CANCELLK" 4055 | "F_ADD_SEALS" 4056 | "F_GET_SEALS" 4057 | "F_SEAL_SEAL" 4058 | "F_SEAL_SHRINK" 4059 | "F_SEAL_GROW" 4060 | "F_SEAL_WRITE" => true, 4061 // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests 4062 // because including `linux/if_arp.h` causes some conflicts: 4063 "ARPHRD_CAN" => true, 4064 4065 // FIXME: deprecated: not available in any header 4066 // See: https://github.com/rust-lang/libc/issues/1356 4067 "ENOATTR" => true, 4068 4069 // FIXME: SIGUNUSED was removed in glibc 2.26 4070 // Users should use SIGSYS instead. 4071 "SIGUNUSED" => true, 4072 4073 // FIXME: conflicts with glibc headers and is tested in 4074 // `linux_termios.rs` below: 4075 | "BOTHER" 4076 | "IBSHIFT" 4077 | "TCGETS2" 4078 | "TCSETS2" 4079 | "TCSETSW2" 4080 | "TCSETSF2" => true, 4081 4082 // FIXME: on musl the pthread types are defined a little differently 4083 // - these constants are used by the glibc implementation. 4084 n if musl && n.contains("__SIZEOF_PTHREAD") => true, 4085 4086 // FIXME: It was extended to 4096 since glibc 2.31 (Linux 5.4). 4087 // We should do so after a while. 4088 "SOMAXCONN" if gnu => true, 4089 4090 // deprecated: not available from Linux kernel 5.6: 4091 "VMADDR_CID_RESERVED" => true, 4092 4093 // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP: 4094 | "IPPROTO_MAX" 4095 | "IPPROTO_ETHERNET" 4096 | "IPPROTO_MPTCP" => true, 4097 4098 // FIXME: Not yet implemented on sparc64 4099 "SYS_clone3" if sparc64 => true, 4100 4101 // FIXME: Not defined on ARM, gnueabihf, musl, PowerPC, riscv64, s390x, and sparc64. 4102 "SYS_memfd_secret" if arm | gnueabihf | musl | ppc | riscv64 | s390x | sparc64 => true, 4103 4104 // FIXME: Added in Linux 5.16 4105 // https://github.com/torvalds/linux/commit/039c0ec9bb77446d7ada7f55f90af9299b28ca49 4106 "SYS_futex_waitv" => true, 4107 4108 // FIXME: Added in Linux 5.17 4109 // https://github.com/torvalds/linux/commit/c6018b4b254971863bd0ad36bb5e7d0fa0f0ddb0 4110 "SYS_set_mempolicy_home_node" => true, 4111 4112 // FIXME: Added in Linux 5.18 4113 // https://github.com/torvalds/linux/commit/8b5413647262dda8d8d0e07e14ea1de9ac7cf0b2 4114 "NFQA_PRIORITY" => true, 4115 4116 // FIXME: requires more recent kernel headers on CI 4117 | "UINPUT_VERSION" 4118 | "SW_MAX" 4119 | "SW_CNT" 4120 if ppc64 || riscv64 => true, 4121 4122 // FIXME: requires more recent kernel headers on CI 4123 | "MFD_EXEC" 4124 | "MFD_NOEXEC_SEAL" 4125 | "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV" 4126 if sparc64 => true, 4127 4128 // FIXME: Not currently available in headers on ARM and musl. 4129 "NETLINK_GET_STRICT_CHK" if arm => true, 4130 4131 // kernel constants not available in uclibc 1.0.34 4132 | "EXTPROC" 4133 | "IPPROTO_BEETPH" 4134 | "IPPROTO_MPLS" 4135 | "IPV6_HDRINCL" 4136 | "IPV6_MULTICAST_ALL" 4137 | "IPV6_PMTUDISC_INTERFACE" 4138 | "IPV6_PMTUDISC_OMIT" 4139 | "IPV6_ROUTER_ALERT_ISOLATE" 4140 | "PACKET_MR_UNICAST" 4141 | "RUSAGE_THREAD" 4142 | "SHM_EXEC" 4143 | "UDP_GRO" 4144 | "UDP_SEGMENT" 4145 if uclibc => true, 4146 4147 // headers conflicts with linux/pidfd.h 4148 "PIDFD_NONBLOCK" => true, 4149 4150 // is a private value for kernel usage normally 4151 "FUSE_SUPER_MAGIC" => true, 4152 4153 // linux 5.17 min 4154 "PR_SET_VMA" | "PR_SET_VMA_ANON_NAME" => true, 4155 4156 // present in recent kernels only 4157 "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, 4158 4159 // present in recent kernels only >= 5.13 4160 "PR_PAC_SET_ENABLED_KEYS" | "PR_PAC_GET_ENABLED_KEYS" => true, 4161 // present in recent kernels only >= 5.19 4162 "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, 4163 4164 // Added in Linux 5.14 4165 "FUTEX_LOCK_PI2" => true, 4166 4167 // Added in linux 6.1 4168 "STATX_DIOALIGN" 4169 | "CAN_RAW_XL_FRAMES" 4170 | "CANXL_HDR_SIZE" 4171 | "CANXL_MAX_DLC" 4172 | "CANXL_MAX_DLC_MASK" 4173 | "CANXL_MAX_DLEN" 4174 | "CANXL_MAX_MTU" 4175 | "CANXL_MIN_DLC" 4176 | "CANXL_MIN_DLEN" 4177 | "CANXL_MIN_MTU" 4178 | "CANXL_MTU" 4179 | "CANXL_PRIO_BITS" 4180 | "CANXL_PRIO_MASK" 4181 | "CANXL_SEC" 4182 | "CANXL_XLF" 4183 => true, 4184 4185 // FIXME: Parts of netfilter/nfnetlink*.h require more recent kernel headers: 4186 | "RTNLGRP_MCTP_IFADDR" // linux v5.17+ 4187 | "RTNLGRP_TUNNEL" // linux v5.18+ 4188 | "RTNLGRP_STATS" // linux v5.18+ 4189 => true, 4190 4191 // FIXME: The below is no longer const in glibc 2.34: 4192 // https://github.com/bminor/glibc/commit/5d98a7dae955bafa6740c26eaba9c86060ae0344 4193 | "PTHREAD_STACK_MIN" 4194 | "SIGSTKSZ" 4195 | "MINSIGSTKSZ" 4196 if gnu => true, 4197 4198 // FIXME: Linux >= 5.16: 4199 // https://github.com/torvalds/linux/commit/42df6e1d221dddc0f2acf2be37e68d553ad65f96 4200 "NF_NETDEV_EGRESS" if sparc64 => true, 4201 // value changed 4202 "NF_NETDEV_NUMHOOKS" if sparc64 => true, 4203 4204 // FIXME: requires Linux >= v5.8 4205 "IF_LINK_MODE_TESTING" if sparc64 => true, 4206 4207 // DIFF(main): fixed in 1.0 with e9abac9ac2 4208 "CLONE_CLEAR_SIGHAND" | "CLONE_INTO_CGROUP" => true, 4209 4210 // kernel 6.1 minimum 4211 "MADV_COLLAPSE" => true, 4212 4213 // kernel 6.2 minimum 4214 "TUN_F_USO4" | "TUN_F_USO6" | "IFF_NO_CARRIER" => true, 4215 4216 // FIXME: Requires more recent kernel headers 4217 | "IFLA_PARENT_DEV_NAME" // linux v5.13+ 4218 | "IFLA_PARENT_DEV_BUS_NAME" // linux v5.13+ 4219 | "IFLA_GRO_MAX_SIZE" // linux v5.16+ 4220 | "IFLA_TSO_MAX_SIZE" // linux v5.18+ 4221 | "IFLA_TSO_MAX_SEGS" // linux v5.18+ 4222 | "IFLA_ALLMULTI" // linux v6.0+ 4223 | "MADV_DONTNEED_LOCKED" // linux v5.18+ 4224 => true, 4225 "SCTP_FUTURE_ASSOC" | "SCTP_CURRENT_ASSOC" | "SCTP_ALL_ASSOC" | "SCTP_PEER_ADDR_THLDS_V2" => true, // linux 5.5+ 4226 4227 // kernel 6.5 minimum 4228 "MOVE_MOUNT_BENEATH" => true, 4229 // FIXME: Requires linux 6.1 4230 "ALG_SET_KEY_BY_KEY_SERIAL" | "ALG_SET_DRBG_ENTROPY" => true, 4231 4232 // FIXME: Requires more recent kernel headers 4233 | "FAN_FS_ERROR" // linux v5.16+ 4234 | "FAN_RENAME" // linux v5.17+ 4235 | "FAN_REPORT_TARGET_FID" // linux v5.17+ 4236 | "FAN_REPORT_DFID_NAME_TARGET" // linux v5.17+ 4237 | "FAN_MARK_EVICTABLE" // linux v5.19+ 4238 | "FAN_MARK_IGNORE" // linux v6.0+ 4239 | "FAN_MARK_IGNORE_SURV" // linux v6.0+ 4240 | "FAN_EVENT_INFO_TYPE_ERROR" // linux v5.16+ 4241 | "FAN_EVENT_INFO_TYPE_OLD_DFID_NAME" // linux v5.17+ 4242 | "FAN_EVENT_INFO_TYPE_NEW_DFID_NAME" // linux v5.17+ 4243 | "FAN_RESPONSE_INFO_NONE" // linux v5.16+ 4244 | "FAN_RESPONSE_INFO_AUDIT_RULE" // linux v5.16+ 4245 | "FAN_INFO" // linux v5.16+ 4246 => true, 4247 4248 // musl doesn't use <linux/fanotify.h> in <sys/fanotify.h> 4249 "FAN_REPORT_PIDFD" 4250 | "FAN_REPORT_DIR_FID" 4251 | "FAN_REPORT_NAME" 4252 | "FAN_REPORT_DFID_NAME" 4253 | "FAN_EVENT_INFO_TYPE_DFID_NAME" 4254 | "FAN_EVENT_INFO_TYPE_DFID" 4255 | "FAN_EVENT_INFO_TYPE_PIDFD" 4256 | "FAN_NOPIDFD" 4257 | "FAN_EPIDFD" 4258 if musl => true, 4259 4260 // FIXME: Requires linux 6.5 4261 "NFT_MSG_MAX" => true, 4262 4263 // FIXME: Requires >= 6.6 kernel headers. 4264 "XDP_USE_SG" 4265 | "XDP_PKT_CONTD" 4266 => 4267 { 4268 true 4269 } 4270 4271 // FIXME: Requires >= 6.8 kernel headers. 4272 "XDP_UMEM_TX_SW_CSUM" 4273 | "XDP_TXMD_FLAGS_TIMESTAMP" 4274 | "XDP_TXMD_FLAGS_CHECKSUM" 4275 | "XDP_TX_METADATA" 4276 => 4277 { 4278 true 4279 } 4280 4281 // FIXME: Requires >= 6.11 kernel headers. 4282 "XDP_UMEM_TX_METADATA_LEN" 4283 => 4284 { 4285 true 4286 } 4287 4288 // FIXME: Requires >= 6.6 kernel headers. 4289 "SYS_fchmodat2" => true, 4290 4291 // FIXME: Requires >= 6.10 kernel headers. 4292 "SYS_mseal" => true, 4293 4294 // FIXME: seems to not be available all the time (from <include/linux/sched.h>: 4295 "PF_VCPU" 4296 | "PF_IDLE" 4297 | "PF_EXITING" 4298 | "PF_POSTCOREDUMP" 4299 | "PF_IO_WORKER" 4300 | "PF_WQ_WORKER" 4301 | "PF_FORKNOEXEC" 4302 | "PF_MCE_PROCESS" 4303 | "PF_SUPERPRIV" 4304 | "PF_DUMPCORE" 4305 | "PF_SIGNALED" 4306 | "PF_MEMALLOC" 4307 | "PF_NPROC_EXCEEDED" 4308 | "PF_USED_MATH" 4309 | "PF_USER_WORKER" 4310 | "PF_NOFREEZE" 4311 | "PF_KSWAPD" 4312 | "PF_MEMALLOC_NOFS" 4313 | "PF_MEMALLOC_NOIO" 4314 | "PF_LOCAL_THROTTLE" 4315 | "PF_KTHREAD" 4316 | "PF_RANDOMIZE" 4317 | "PF_NO_SETAFFINITY" 4318 | "PF_MCE_EARLY" 4319 | "PF_MEMALLOC_PIN" 4320 | "PF_BLOCK_TS" 4321 | "PF_SUSPEND_TASK" => true, 4322 4323 // FIXME: Requires >= 6.9 kernel headers. 4324 "EPIOCSPARAMS" 4325 | "EPIOCGPARAMS" => true, 4326 4327 // FIXME: Requires >= 6.11 kernel headers. 4328 "MAP_DROPPABLE" => true, 4329 4330 _ => false, 4331 } 4332 }); 4333 4334 cfg.skip_fn(move |name| { 4335 // skip those that are manually verified 4336 match name { 4337 // FIXME: https://github.com/rust-lang/libc/issues/1272 4338 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 4339 4340 // There are two versions of the sterror_r function, see 4341 // 4342 // https://linux.die.net/man/3/strerror_r 4343 // 4344 // An XSI-compliant version provided if: 4345 // 4346 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) 4347 // && ! _GNU_SOURCE 4348 // 4349 // and a GNU specific version provided if _GNU_SOURCE is defined. 4350 // 4351 // libc provides bindings for the XSI-compliant version, which is 4352 // preferred for portable applications. 4353 // 4354 // We skip the test here since here _GNU_SOURCE is defined, and 4355 // test the XSI version below. 4356 "strerror_r" => true, 4357 4358 // FIXME: Our API is unsound. The Rust API allows aliasing 4359 // pointers, but the C API requires pointers not to alias. 4360 // We should probably be at least using `&`/`&mut` here, see: 4361 // https://github.com/gnzlbg/ctest/issues/68 4362 "lio_listio" if musl => true, 4363 4364 // Needs glibc 2.34 or later. 4365 "posix_spawn_file_actions_addclosefrom_np" if gnu && sparc64 => true, 4366 // Needs glibc 2.35 or later. 4367 "posix_spawn_file_actions_addtcsetpgrp_np" if gnu && sparc64 => true, 4368 4369 // FIXME: Deprecated since glibc 2.30. Remove fn once upstream does. 4370 "sysctl" if gnu => true, 4371 4372 // FIXME: It now takes c_void instead of timezone since glibc 2.31. 4373 "gettimeofday" if gnu => true, 4374 4375 // These are all implemented as static inline functions in uclibc, so 4376 // they cannot be linked against. 4377 // If implementations are required, they might need to be implemented 4378 // in this crate. 4379 "posix_spawnattr_init" if uclibc => true, 4380 "posix_spawnattr_destroy" if uclibc => true, 4381 "posix_spawnattr_getsigdefault" if uclibc => true, 4382 "posix_spawnattr_setsigdefault" if uclibc => true, 4383 "posix_spawnattr_getsigmask" if uclibc => true, 4384 "posix_spawnattr_setsigmask" if uclibc => true, 4385 "posix_spawnattr_getflags" if uclibc => true, 4386 "posix_spawnattr_setflags" if uclibc => true, 4387 "posix_spawnattr_getpgroup" if uclibc => true, 4388 "posix_spawnattr_setpgroup" if uclibc => true, 4389 "posix_spawnattr_getschedpolicy" if uclibc => true, 4390 "posix_spawnattr_setschedpolicy" if uclibc => true, 4391 "posix_spawnattr_getschedparam" if uclibc => true, 4392 "posix_spawnattr_setschedparam" if uclibc => true, 4393 "posix_spawn_file_actions_init" if uclibc => true, 4394 "posix_spawn_file_actions_destroy" if uclibc => true, 4395 4396 // uclibc defines the flags type as a uint, but dependent crates 4397 // assume it's a int instead. 4398 "getnameinfo" if uclibc => true, 4399 4400 // FIXME: This needs musl 1.2.2 or later. 4401 "gettid" if musl => true, 4402 4403 // Needs glibc 2.33 or later. 4404 "mallinfo2" => true, 4405 4406 "reallocarray" if musl => true, 4407 4408 // Not defined in uclibc as of 1.0.34 4409 "gettid" if uclibc => true, 4410 4411 // Needs musl 1.2.3 or later. 4412 "pthread_getname_np" if musl => true, 4413 4414 // pthread_sigqueue uses sigval, which was initially declared 4415 // as a struct but should be defined as a union. However due 4416 // to the issues described here: https://github.com/rust-lang/libc/issues/2816 4417 // it can't be changed from struct. 4418 "pthread_sigqueue" => true, 4419 4420 // There are two versions of basename(3) on Linux with glibc, see 4421 // 4422 // https://man7.org/linux/man-pages/man3/basename.3.html 4423 // 4424 // If libgen.h is included, then the POSIX version will be available; 4425 // If _GNU_SOURCE is defined and string.h is included, then the GNU one 4426 // will be used. 4427 // 4428 // libc exposes both of them, providing a prefix to differentiate between 4429 // them. 4430 // 4431 // Because the name with prefix is not a valid symbol in C, we have to 4432 // skip the tests. 4433 "posix_basename" if gnu => true, 4434 "gnu_basename" if gnu => true, 4435 4436 // FIXME: function pointers changed since Ubuntu 23.10 4437 "strtol" | "strtoll" | "strtoul" | "strtoull" | "fscanf" | "scanf" | "sscanf" => true, 4438 4439 // Added in musl 1.2.5 4440 "preadv2" | "pwritev2" if musl => true, 4441 4442 _ => false, 4443 } 4444 }); 4445 4446 cfg.skip_field_type(move |struct_, field| { 4447 // This is a weird union, don't check the type. 4448 (struct_ == "ifaddrs" && field == "ifa_ifu") || 4449 // sighandler_t type is super weird 4450 (struct_ == "sigaction" && field == "sa_sigaction") || 4451 // __timeval type is a patch which doesn't exist in glibc 4452 (struct_ == "utmpx" && field == "ut_tv") || 4453 // sigval is actually a union, but we pretend it's a struct 4454 (struct_ == "sigevent" && field == "sigev_value") || 4455 // this one is an anonymous union 4456 (struct_ == "ff_effect" && field == "u") || 4457 // `__exit_status` type is a patch which is absent in musl 4458 (struct_ == "utmpx" && field == "ut_exit" && musl) || 4459 // `can_addr` is an anonymous union 4460 (struct_ == "sockaddr_can" && field == "can_addr") || 4461 // `anonymous_1` is an anonymous union 4462 (struct_ == "ptp_perout_request" && field == "anonymous_1") || 4463 // `anonymous_2` is an anonymous union 4464 (struct_ == "ptp_perout_request" && field == "anonymous_2") || 4465 // FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers 4466 // FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers 4467 // the rsv field shrunk when those fields got added, so is omitted too 4468 (struct_ == "ptp_clock_caps" && (loongarch64 || sparc64) && (["adjust_phase", "max_phase_adj", "rsv"].contains(&field))) 4469 }); 4470 4471 cfg.volatile_item(|i| { 4472 use ctest::VolatileItemKind::*; 4473 match i { 4474 // aio_buf is a volatile void** but since we cannot express that in 4475 // Rust types, we have to explicitly tell the checker about it here: 4476 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 4477 _ => false, 4478 } 4479 }); 4480 4481 cfg.skip_field(move |struct_, field| { 4482 // this is actually a union on linux, so we can't represent it well and 4483 // just insert some padding. 4484 (struct_ == "siginfo_t" && field == "_pad") || 4485 // musl names this __dummy1 but it's still there 4486 (musl && struct_ == "glob_t" && field == "gl_flags") || 4487 // musl seems to define this as an *anonymous* bitfield 4488 (musl && struct_ == "statvfs" && field == "__f_unused") || 4489 // sigev_notify_thread_id is actually part of a sigev_un union 4490 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 4491 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release 4492 // has them yet. 4493 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 4494 field == "_pad2" || 4495 field == "ssi_syscall" || 4496 field == "ssi_call_addr" || 4497 field == "ssi_arch")) || 4498 // FIXME: After musl 1.1.24, it have only one field `sched_priority`, 4499 // while other fields become reserved. 4500 (struct_ == "sched_param" && [ 4501 "sched_ss_low_priority", 4502 "sched_ss_repl_period", 4503 "sched_ss_init_budget", 4504 "sched_ss_max_repl", 4505 ].contains(&field) && musl) || 4506 // FIXME: After musl 1.1.24, the type becomes `int` instead of `unsigned short`. 4507 (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) || 4508 // glibc uses unnamed fields here and Rust doesn't support that yet 4509 (struct_ == "timex" && field.starts_with("__unused")) || 4510 // FIXME: It now takes mode_t since glibc 2.31 on some targets. 4511 (struct_ == "ipc_perm" && field == "mode" 4512 && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32) 4513 ) || 4514 // the `u` field is in fact an anonymous union 4515 (gnu && struct_ == "ptrace_syscall_info" && (field == "u" || field == "pad")) || 4516 // the vregs field is a `__uint128_t` C's type. 4517 (struct_ == "user_fpsimd_struct" && field == "vregs") || 4518 // Linux >= 5.11 tweaked the `svm_zero` field of the `sockaddr_vm` struct. 4519 // https://github.com/torvalds/linux/commit/dc8eeef73b63ed8988224ba6b5ed19a615163a7f 4520 (struct_ == "sockaddr_vm" && field == "svm_zero") || 4521 // the `ifr_ifru` field is an anonymous union 4522 (struct_ == "ifreq" && field == "ifr_ifru") || 4523 // the `ifc_ifcu` field is an anonymous union 4524 (struct_ == "ifconf" && field == "ifc_ifcu") || 4525 // glibc uses a single array `uregs` instead of individual fields. 4526 (struct_ == "user_regs" && arm) || 4527 // the `ifr_ifrn` field is an anonymous union 4528 (struct_ == "iwreq" && field == "ifr_ifrn") || 4529 // the `key` field is a zero-sized array 4530 (struct_ == "iw_encode_ext" && field == "key") || 4531 // the `tcpi_snd_rcv_wscale` map two bitfield fields stored in a u8 4532 (struct_ == "tcp_info" && field == "tcpi_snd_rcv_wscale") || 4533 // the `tcpi_delivery_fastopen_bitfields` map two bitfield fields stored in a u8 4534 (musl && struct_ == "tcp_info" && field == "tcpi_delivery_fastopen_bitfields") || 4535 // either fsid_t or int[2] type 4536 (struct_ == "fanotify_event_info_fid" && field == "fsid") || 4537 // `handle` is a VLA 4538 (struct_ == "fanotify_event_info_fid" && field == "handle") || 4539 // `anonymous_1` is an anonymous union 4540 (struct_ == "ptp_perout_request" && field == "anonymous_1") || 4541 // `anonymous_2` is an anonymous union 4542 (struct_ == "ptp_perout_request" && field == "anonymous_2") || 4543 // FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers 4544 // FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers 4545 // the rsv field shrunk when those fields got added, so is omitted too 4546 (struct_ == "ptp_clock_caps" && (loongarch64 || sparc64) && (["adjust_phase", "max_phase_adj", "rsv"].contains(&field))) || 4547 // invalid application of 'sizeof' to incomplete type 'long unsigned int[]' 4548 (musl && struct_ == "mcontext_t" && field == "__extcontext" && loongarch64) || 4549 // FIXME(#4121): a new field was added from `f_spare` 4550 (struct_ == "statvfs" && field == "__f_spare") || 4551 (struct_ == "statvfs64" && field == "__f_spare") || 4552 // the `xsk_tx_metadata_union` field is an anonymous union 4553 (struct_ == "xsk_tx_metadata" && field == "xsk_tx_metadata_union") 4554 }); 4555 4556 cfg.skip_roundtrip(move |s| match s { 4557 // FIXME: 4558 "mcontext_t" if s390x => true, 4559 // FIXME: This is actually a union. 4560 "fpreg_t" if s390x => true, 4561 4562 // The test doesn't work on some env: 4563 "ipv6_mreq" 4564 | "ip_mreq_source" 4565 | "sockaddr_in6" 4566 | "sockaddr_ll" 4567 | "in_pktinfo" 4568 | "arpreq" 4569 | "arpreq_old" 4570 | "sockaddr_un" 4571 | "ff_constant_effect" 4572 | "ff_ramp_effect" 4573 | "ff_condition_effect" 4574 | "Elf32_Ehdr" 4575 | "Elf32_Chdr" 4576 | "ucred" 4577 | "in6_pktinfo" 4578 | "sockaddr_nl" 4579 | "termios" 4580 | "nlmsgerr" 4581 if sparc64 && gnu => 4582 { 4583 true 4584 } 4585 4586 // The following types contain Flexible Array Member fields which have unspecified calling 4587 // convention. The roundtripping tests deliberately pass the structs by value to check "by 4588 // value" layout consistency, but this would be UB for the these types. 4589 "inotify_event" => true, 4590 "fanotify_event_info_fid" => true, 4591 "cmsghdr" => true, 4592 4593 // FIXME: the call ABI of max_align_t is incorrect on these platforms: 4594 "max_align_t" if i686 || ppc64 => true, 4595 4596 _ => false, 4597 }); 4598 4599 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 4600 4601 test_linux_like_apis(target); 4602 } 4603 4604 // This function tests APIs that are incompatible to test when other APIs 4605 // are included (e.g. because including both sets of headers clashes) 4606 fn test_linux_like_apis(target: &str) { 4607 let gnu = target.contains("gnu"); 4608 let musl = target.contains("musl") || target.contains("ohos"); 4609 let linux = target.contains("linux"); 4610 let emscripten = target.contains("emscripten"); 4611 let android = target.contains("android"); 4612 assert!(linux || android || emscripten); 4613 4614 if linux || android || emscripten { 4615 // test strerror_r from the `string.h` header 4616 let mut cfg = ctest_cfg(); 4617 cfg.skip_type(|_| true).skip_static(|_| true); 4618 4619 headers! { cfg: "string.h" } 4620 cfg.skip_fn(|f| match f { 4621 "strerror_r" => false, 4622 _ => true, 4623 }) 4624 .skip_const(|_| true) 4625 .skip_struct(|_| true); 4626 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_strerror_r.rs"); 4627 } 4628 4629 if linux || android || emscripten { 4630 // test fcntl - see: 4631 // http://man7.org/linux/man-pages/man2/fcntl.2.html 4632 let mut cfg = ctest_cfg(); 4633 4634 if musl { 4635 cfg.header("fcntl.h"); 4636 } else { 4637 cfg.header("linux/fcntl.h"); 4638 } 4639 4640 cfg.skip_type(|_| true) 4641 .skip_static(|_| true) 4642 .skip_struct(|_| true) 4643 .skip_fn(|_| true) 4644 .skip_const(move |name| match name { 4645 // test fcntl constants: 4646 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" 4647 | "F_SEAL_GROW" | "F_SEAL_WRITE" => false, 4648 _ => true, 4649 }) 4650 .type_name(move |ty, is_struct, is_union| match ty { 4651 t if is_struct => format!("struct {}", t), 4652 t if is_union => format!("union {}", t), 4653 t => t.to_string(), 4654 }); 4655 4656 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_fcntl.rs"); 4657 } 4658 4659 if linux || android { 4660 // test termios 4661 let mut cfg = ctest_cfg(); 4662 cfg.header("asm/termbits.h"); 4663 cfg.header("linux/termios.h"); 4664 cfg.skip_type(|_| true) 4665 .skip_static(|_| true) 4666 .skip_fn(|_| true) 4667 .skip_const(|c| match c { 4668 "BOTHER" | "IBSHIFT" => false, 4669 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => false, 4670 _ => true, 4671 }) 4672 .skip_struct(|s| s != "termios2") 4673 .type_name(move |ty, is_struct, is_union| match ty { 4674 "Ioctl" if gnu => "unsigned long".to_string(), 4675 "Ioctl" => "int".to_string(), 4676 t if is_struct => format!("struct {}", t), 4677 t if is_union => format!("union {}", t), 4678 t => t.to_string(), 4679 }); 4680 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_termios.rs"); 4681 } 4682 4683 if linux || android { 4684 // test IPV6_ constants: 4685 let mut cfg = ctest_cfg(); 4686 headers! { 4687 cfg: 4688 "linux/in6.h" 4689 } 4690 cfg.skip_type(|_| true) 4691 .skip_static(|_| true) 4692 .skip_fn(|_| true) 4693 .skip_const(|_| true) 4694 .skip_struct(|_| true) 4695 .skip_const(move |name| match name { 4696 "IPV6_FLOWINFO" 4697 | "IPV6_FLOWLABEL_MGR" 4698 | "IPV6_FLOWINFO_SEND" 4699 | "IPV6_FLOWINFO_FLOWLABEL" 4700 | "IPV6_FLOWINFO_PRIORITY" => false, 4701 _ => true, 4702 }) 4703 .type_name(move |ty, is_struct, is_union| match ty { 4704 t if is_struct => format!("struct {}", t), 4705 t if is_union => format!("union {}", t), 4706 t => t.to_string(), 4707 }); 4708 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_ipv6.rs"); 4709 } 4710 4711 if linux || android { 4712 // Test Elf64_Phdr and Elf32_Phdr 4713 // These types have a field called `p_type`, but including 4714 // "resolve.h" defines a `p_type` macro that expands to `__p_type` 4715 // making the tests for these fails when both are included. 4716 let mut cfg = ctest_cfg(); 4717 cfg.header("elf.h"); 4718 cfg.skip_fn(|_| true) 4719 .skip_static(|_| true) 4720 .skip_const(|_| true) 4721 .type_name(move |ty, _is_struct, _is_union| ty.to_string()) 4722 .skip_struct(move |ty| match ty { 4723 "Elf64_Phdr" | "Elf32_Phdr" => false, 4724 _ => true, 4725 }) 4726 .skip_type(move |ty| match ty { 4727 "Elf64_Phdr" | "Elf32_Phdr" => false, 4728 _ => true, 4729 }); 4730 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_elf.rs"); 4731 } 4732 4733 if linux || android { 4734 // Test `ARPHRD_CAN`. 4735 let mut cfg = ctest_cfg(); 4736 cfg.header("linux/if_arp.h"); 4737 cfg.skip_fn(|_| true) 4738 .skip_static(|_| true) 4739 .skip_const(move |name| match name { 4740 "ARPHRD_CAN" => false, 4741 _ => true, 4742 }) 4743 .skip_struct(|_| true) 4744 .skip_type(|_| true); 4745 cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_if_arp.rs"); 4746 } 4747 } 4748 4749 fn which_freebsd() -> Option<i32> { 4750 if let Ok(version) = env::var("RUST_LIBC_UNSTABLE_FREEBSD_VERSION") { 4751 let vers = version.parse().unwrap(); 4752 println!("cargo:warning=setting FreeBSD version to {vers}"); 4753 return Some(vers); 4754 } 4755 4756 let output = std::process::Command::new("freebsd-version") 4757 .output() 4758 .ok()?; 4759 4760 if !output.status.success() { 4761 return None; 4762 } 4763 4764 let stdout = String::from_utf8(output.stdout).ok()?; 4765 4766 match &stdout { 4767 s if s.starts_with("10") => Some(10), 4768 s if s.starts_with("11") => Some(11), 4769 s if s.starts_with("12") => Some(12), 4770 s if s.starts_with("13") => Some(13), 4771 s if s.starts_with("14") => Some(14), 4772 s if s.starts_with("15") => Some(15), 4773 _ => None, 4774 } 4775 } 4776 4777 fn test_haiku(target: &str) { 4778 assert!(target.contains("haiku")); 4779 4780 let mut cfg = ctest_cfg(); 4781 cfg.flag("-Wno-deprecated-declarations"); 4782 cfg.define("__USE_GNU", Some("1")); 4783 cfg.define("_GNU_SOURCE", None); 4784 cfg.language(ctest::Lang::CXX); 4785 4786 // POSIX API 4787 headers! { cfg: 4788 "alloca.h", 4789 "arpa/inet.h", 4790 "arpa/nameser.h", 4791 "arpa/nameser_compat.h", 4792 "assert.h", 4793 "complex.h", 4794 "ctype.h", 4795 "dirent.h", 4796 "div_t.h", 4797 "dlfcn.h", 4798 "endian.h", 4799 "errno.h", 4800 "fcntl.h", 4801 "fenv.h", 4802 "fnmatch.h", 4803 "fts.h", 4804 "ftw.h", 4805 "getopt.h", 4806 "glob.h", 4807 "grp.h", 4808 "inttypes.h", 4809 "iovec.h", 4810 "langinfo.h", 4811 "libgen.h", 4812 "libio.h", 4813 "limits.h", 4814 "locale.h", 4815 "malloc.h", 4816 "malloc_debug.h", 4817 "math.h", 4818 "memory.h", 4819 "monetary.h", 4820 "net/if.h", 4821 "net/if_dl.h", 4822 "net/if_media.h", 4823 "net/if_tun.h", 4824 "net/if_types.h", 4825 "net/route.h", 4826 "netdb.h", 4827 "netinet/in.h", 4828 "netinet/ip.h", 4829 "netinet/ip6.h", 4830 "netinet/ip_icmp.h", 4831 "netinet/ip_var.h", 4832 "netinet/tcp.h", 4833 "netinet/udp.h", 4834 "netinet6/in6.h", 4835 "nl_types.h", 4836 "null.h", 4837 "poll.h", 4838 "pthread.h", 4839 "pwd.h", 4840 "regex.h", 4841 "resolv.h", 4842 "sched.h", 4843 "search.h", 4844 "semaphore.h", 4845 "setjmp.h", 4846 "shadow.h", 4847 "signal.h", 4848 "size_t.h", 4849 "spawn.h", 4850 "stdint.h", 4851 "stdio.h", 4852 "stdlib.h", 4853 "string.h", 4854 "strings.h", 4855 "sys/cdefs.h", 4856 "sys/file.h", 4857 "sys/ioctl.h", 4858 "sys/ipc.h", 4859 "sys/mman.h", 4860 "sys/msg.h", 4861 "sys/param.h", 4862 "sys/poll.h", 4863 "sys/resource.h", 4864 "sys/select.h", 4865 "sys/sem.h", 4866 "sys/socket.h", 4867 "sys/sockio.h", 4868 "sys/stat.h", 4869 "sys/statvfs.h", 4870 "sys/time.h", 4871 "sys/timeb.h", 4872 "sys/times.h", 4873 "sys/types.h", 4874 "sys/uio.h", 4875 "sys/un.h", 4876 "sys/utsname.h", 4877 "sys/wait.h", 4878 "syslog.h", 4879 "tar.h", 4880 "termios.h", 4881 "time.h", 4882 "uchar.h", 4883 "unistd.h", 4884 "utime.h", 4885 "utmpx.h", 4886 "wchar.h", 4887 "wchar_t.h", 4888 "wctype.h" 4889 } 4890 4891 // BSD Extensions 4892 headers! { cfg: 4893 "ifaddrs.h", 4894 "libutil.h", 4895 "link.h", 4896 "pty.h", 4897 "stdlib.h", 4898 "stringlist.h", 4899 "sys/link_elf.h", 4900 } 4901 4902 // Native API 4903 headers! { cfg: 4904 "kernel/OS.h", 4905 "kernel/fs_attr.h", 4906 "kernel/fs_index.h", 4907 "kernel/fs_info.h", 4908 "kernel/fs_query.h", 4909 "kernel/fs_volume.h", 4910 "kernel/image.h", 4911 "kernel/scheduler.h", 4912 "storage/FindDirectory.h", 4913 "storage/StorageDefs.h", 4914 "support/Errors.h", 4915 "support/SupportDefs.h", 4916 "support/TypeConstants.h" 4917 } 4918 4919 cfg.skip_struct(move |ty| { 4920 if ty.starts_with("__c_anonymous_") { 4921 return true; 4922 } 4923 match ty { 4924 // FIXME: actually a union 4925 "sigval" => true, 4926 // FIXME: locale_t does not exist on Haiku 4927 "locale_t" => true, 4928 // FIXME: rusage has a different layout on Haiku 4929 "rusage" => true, 4930 // FIXME?: complains that rust aligns on 4 byte boundary, but 4931 // Haiku does not align it at all. 4932 "in6_addr" => true, 4933 // The d_name attribute is an array of 1 on Haiku, with the 4934 // intention that the developer allocates a larger or smaller 4935 // piece of memory depending on the expected/actual size of the name. 4936 // Other platforms have sensible defaults. In Rust, the d_name field 4937 // is sized as the _POSIX_MAX_PATH, so that path names will fit in 4938 // newly allocated dirent objects. This breaks the automated tests. 4939 "dirent" => true, 4940 // The following structs contain function pointers, which cannot be initialized 4941 // with mem::zeroed(), so skip the automated test 4942 "image_info" | "thread_info" => true, 4943 4944 "Elf64_Phdr" => true, 4945 4946 // is an union 4947 "cpuid_info" => true, 4948 4949 _ => false, 4950 } 4951 }); 4952 4953 cfg.skip_type(move |ty| { 4954 match ty { 4955 // FIXME: locale_t does not exist on Haiku 4956 "locale_t" => true, 4957 // These cause errors, to be reviewed in the future 4958 "sighandler_t" => true, 4959 "pthread_t" => true, 4960 "pthread_condattr_t" => true, 4961 "pthread_mutexattr_t" => true, 4962 "pthread_rwlockattr_t" => true, 4963 _ => false, 4964 } 4965 }); 4966 4967 cfg.skip_fn(move |name| { 4968 // skip those that are manually verified 4969 match name { 4970 // FIXME: https://github.com/rust-lang/libc/issues/1272 4971 "execv" | "execve" | "execvp" | "execvpe" => true, 4972 // FIXME: does not exist on haiku 4973 "open_wmemstream" => true, 4974 "mlockall" | "munlockall" => true, 4975 "tcgetsid" => true, 4976 "cfsetspeed" => true, 4977 // ignore for now, will be part of Haiku R1 beta 3 4978 "mlock" | "munlock" => true, 4979 // returns const char * on Haiku 4980 "strsignal" => true, 4981 // uses an enum as a parameter argument, which is incorrectly 4982 // translated into a struct argument 4983 "find_path" => true, 4984 4985 "get_cpuid" => true, 4986 4987 // uses varargs parameter 4988 "ioctl" => true, 4989 4990 _ => false, 4991 } 4992 }); 4993 4994 cfg.skip_const(move |name| { 4995 match name { 4996 // FIXME: these constants do not exist on Haiku 4997 "DT_UNKNOWN" | "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" 4998 | "DT_SOCK" => true, 4999 "USRQUOTA" | "GRPQUOTA" => true, 5000 "SIGIOT" => true, 5001 "ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM" | "ATF_PUBL" 5002 | "ATF_USETRAILERS" => true, 5003 // Haiku does not have MAP_FILE, but rustc requires it 5004 "MAP_FILE" => true, 5005 // The following does not exist on Haiku but is required by 5006 // several crates 5007 "FIOCLEX" => true, 5008 // just skip this one, it is not defined on Haiku beta 2 but 5009 // since it is meant as a mask and not a parameter it can exist 5010 // here 5011 "LOG_PRIMASK" => true, 5012 // not defined on Haiku, but [get|set]priority is, so they are 5013 // useful 5014 "PRIO_MIN" | "PRIO_MAX" => true, 5015 // 5016 _ => false, 5017 } 5018 }); 5019 5020 cfg.skip_field(move |struct_, field| { 5021 match (struct_, field) { 5022 // FIXME: the stat struct actually has timespec members, whereas 5023 // the current representation has these unpacked. 5024 ("stat", "st_atime") => true, 5025 ("stat", "st_atime_nsec") => true, 5026 ("stat", "st_mtime") => true, 5027 ("stat", "st_mtime_nsec") => true, 5028 ("stat", "st_ctime") => true, 5029 ("stat", "st_ctime_nsec") => true, 5030 ("stat", "st_crtime") => true, 5031 ("stat", "st_crtime_nsec") => true, 5032 5033 // these are actually unions, but we cannot represent it well 5034 ("siginfo_t", "sigval") => true, 5035 ("sem_t", "named_sem_id") => true, 5036 ("sigaction", "sa_sigaction") => true, 5037 ("sigevent", "sigev_value") => true, 5038 ("fpu_state", "_fpreg") => true, 5039 ("cpu_topology_node_info", "data") => true, 5040 // these fields have a simplified data definition in libc 5041 ("fpu_state", "_xmm") => true, 5042 ("savefpu", "_fp_ymm") => true, 5043 5044 // skip these enum-type fields 5045 ("thread_info", "state") => true, 5046 ("image_info", "image_type") => true, 5047 _ => false, 5048 } 5049 }); 5050 5051 cfg.skip_roundtrip(move |s| match s { 5052 // FIXME: for some reason the roundtrip check fails for cpu_info 5053 "cpu_info" => true, 5054 _ => false, 5055 }); 5056 5057 cfg.type_name(move |ty, is_struct, is_union| { 5058 match ty { 5059 // Just pass all these through, no need for a "struct" prefix 5060 "area_info" 5061 | "port_info" 5062 | "port_message_info" 5063 | "team_info" 5064 | "sem_info" 5065 | "team_usage_info" 5066 | "thread_info" 5067 | "cpu_info" 5068 | "system_info" 5069 | "object_wait_info" 5070 | "image_info" 5071 | "attr_info" 5072 | "index_info" 5073 | "fs_info" 5074 | "FILE" 5075 | "DIR" 5076 | "Dl_info" 5077 | "topology_level_type" 5078 | "cpu_topology_node_info" 5079 | "cpu_topology_root_info" 5080 | "cpu_topology_package_info" 5081 | "cpu_topology_core_info" => ty.to_string(), 5082 5083 // enums don't need a prefix 5084 "directory_which" | "path_base_directory" | "cpu_platform" | "cpu_vendor" => { 5085 ty.to_string() 5086 } 5087 5088 // is actually a union 5089 "sigval" => format!("union sigval"), 5090 t if is_union => format!("union {}", t), 5091 t if t.ends_with("_t") => t.to_string(), 5092 t if is_struct => format!("struct {}", t), 5093 t => t.to_string(), 5094 } 5095 }); 5096 5097 cfg.field_name(move |struct_, field| { 5098 match field { 5099 // Field is named `type` in C but that is a Rust keyword, 5100 // so these fields are translated to `type_` in the bindings. 5101 "type_" if struct_ == "object_wait_info" => "type".to_string(), 5102 "type_" if struct_ == "sem_t" => "type".to_string(), 5103 "type_" if struct_ == "attr_info" => "type".to_string(), 5104 "type_" if struct_ == "index_info" => "type".to_string(), 5105 "type_" if struct_ == "cpu_topology_node_info" => "type".to_string(), 5106 "image_type" if struct_ == "image_info" => "type".to_string(), 5107 s => s.to_string(), 5108 } 5109 }); 5110 cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs"); 5111 } 5112