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