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