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