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