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