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