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