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