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