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