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/mman.h", 1660 "sys/mount.h", 1661 "sys/personality.h", 1662 "sys/prctl.h", 1663 "sys/ptrace.h", 1664 "sys/random.h", 1665 "sys/reboot.h", 1666 "sys/resource.h", 1667 "sys/sendfile.h", 1668 "sys/signalfd.h", 1669 "sys/socket.h", 1670 "sys/stat.h", 1671 "sys/statvfs.h", 1672 "sys/swap.h", 1673 "sys/syscall.h", 1674 "sys/sysinfo.h", 1675 "sys/system_properties.h", 1676 "sys/time.h", 1677 "sys/timerfd.h", 1678 "sys/times.h", 1679 "sys/types.h", 1680 "sys/ucontext.h", 1681 "sys/uio.h", 1682 "sys/un.h", 1683 "sys/user.h", 1684 "sys/utsname.h", 1685 "sys/vfs.h", 1686 "sys/xattr.h", 1687 "sys/wait.h", 1688 "syslog.h", 1689 "termios.h", 1690 "time.h", 1691 "unistd.h", 1692 "utime.h", 1693 "utmp.h", 1694 "wchar.h", 1695 "xlocale.h", 1696 // time64_t is not defined for 64-bit targets If included it will 1697 // generate the error 'Your time_t is already 64-bit' 1698 [target_pointer_width == 32]: "time64.h", 1699 [x86]: "sys/reg.h", 1700 } 1701 1702 // Include linux headers at the end: 1703 headers! { cfg: 1704 "asm/mman.h", 1705 "linux/auxvec.h", 1706 "linux/dccp.h", 1707 "linux/elf.h", 1708 "linux/errqueue.h", 1709 "linux/falloc.h", 1710 "linux/filter.h", 1711 "linux/futex.h", 1712 "linux/fs.h", 1713 "linux/genetlink.h", 1714 "linux/if_alg.h", 1715 "linux/if_addr.h", 1716 "linux/if_ether.h", 1717 "linux/if_link.h", 1718 "linux/rtnetlink.h", 1719 "linux/if_tun.h", 1720 "linux/kexec.h", 1721 "linux/magic.h", 1722 "linux/membarrier.h", 1723 "linux/memfd.h", 1724 "linux/mempolicy.h", 1725 "linux/module.h", 1726 "linux/mount.h", 1727 "linux/net_tstamp.h", 1728 "linux/netfilter/nfnetlink.h", 1729 "linux/netfilter/nfnetlink_log.h", 1730 "linux/netfilter/nfnetlink_queue.h", 1731 "linux/netfilter/nf_tables.h", 1732 "linux/netfilter_ipv4.h", 1733 "linux/netfilter_ipv6.h", 1734 "linux/netfilter_ipv6/ip6_tables.h", 1735 "linux/netlink.h", 1736 "linux/quota.h", 1737 "linux/reboot.h", 1738 "linux/seccomp.h", 1739 "linux/sched.h", 1740 "linux/sockios.h", 1741 "linux/uinput.h", 1742 "linux/vm_sockets.h", 1743 "linux/wait.h", 1744 1745 } 1746 1747 // Include Android-specific headers: 1748 headers! { cfg: 1749 "android/set_abort_message.h" 1750 } 1751 1752 cfg.type_name(move |ty, is_struct, is_union| { 1753 match ty { 1754 // Just pass all these through, no need for a "struct" prefix 1755 "FILE" | "fd_set" | "Dl_info" | "Elf32_Phdr" | "Elf64_Phdr" => ty.to_string(), 1756 1757 t if is_union => format!("union {}", t), 1758 1759 t if t.ends_with("_t") => t.to_string(), 1760 1761 // sigval is a struct in Rust, but a union in C: 1762 "sigval" => format!("union sigval"), 1763 1764 // put `struct` in front of all structs:. 1765 t if is_struct => format!("struct {}", t), 1766 1767 t => t.to_string(), 1768 } 1769 }); 1770 1771 cfg.field_name(move |struct_, field| { 1772 match field { 1773 // Our stat *_nsec fields normally don't actually exist but are part 1774 // of a timeval struct 1775 s if s.ends_with("_nsec") && struct_.starts_with("stat") => s.to_string(), 1776 // FIXME: appears that `epoll_event.data` is an union 1777 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 1778 // The following structs have a field called `type` in C, 1779 // but `type` is a Rust keyword, so these fields are translated 1780 // to `type_` in Rust. 1781 "type_" 1782 if struct_ == "input_event" 1783 || struct_ == "input_mask" 1784 || struct_ == "ff_effect" => 1785 { 1786 "type".to_string() 1787 } 1788 1789 s => s.to_string(), 1790 } 1791 }); 1792 1793 cfg.skip_type(move |ty| { 1794 match ty { 1795 // FIXME: `sighandler_t` type is incorrect, see: 1796 // https://github.com/rust-lang/libc/issues/1359 1797 "sighandler_t" => true, 1798 1799 // These are tested in the `linux_elf.rs` file. 1800 "Elf64_Phdr" | "Elf32_Phdr" => true, 1801 // These are intended to be opaque 1802 "posix_spawn_file_actions_t" => true, 1803 "posix_spawnattr_t" => true, 1804 _ => false, 1805 } 1806 }); 1807 1808 cfg.skip_struct(move |ty| { 1809 if ty.starts_with("__c_anonymous_") { 1810 return true; 1811 } 1812 match ty { 1813 // These are tested as part of the linux_fcntl tests since there are 1814 // header conflicts when including them with all the other structs. 1815 "termios2" => true, 1816 // uc_sigmask and uc_sigmask64 of ucontext_t are an anonymous union 1817 "ucontext_t" => true, 1818 // 'private' type 1819 "prop_info" => true, 1820 1821 // These are tested in the `linux_elf.rs` file. 1822 "Elf64_Phdr" | "Elf32_Phdr" => true, 1823 1824 // FIXME: The type of `iv` has been changed. 1825 "af_alg_iv" => true, 1826 1827 // FIXME: The size of struct has been changed: 1828 "inotify_event" => true, 1829 // FIXME: The field has been changed: 1830 "sockaddr_vm" => true, 1831 1832 _ => false, 1833 } 1834 }); 1835 1836 cfg.skip_const(move |name| { 1837 match name { 1838 // The IPV6 constants are tested in the `linux_ipv6.rs` tests: 1839 | "IPV6_FLOWINFO" 1840 | "IPV6_FLOWLABEL_MGR" 1841 | "IPV6_FLOWINFO_SEND" 1842 | "IPV6_FLOWINFO_FLOWLABEL" 1843 | "IPV6_FLOWINFO_PRIORITY" 1844 // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: 1845 | "F_CANCELLK" 1846 | "F_ADD_SEALS" 1847 | "F_GET_SEALS" 1848 | "F_SEAL_SEAL" 1849 | "F_SEAL_SHRINK" 1850 | "F_SEAL_GROW" 1851 | "F_SEAL_WRITE" => true, 1852 1853 // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests: 1854 "ARPHRD_CAN" => true, 1855 1856 // FIXME: deprecated: not available in any header 1857 // See: https://github.com/rust-lang/libc/issues/1356 1858 "ENOATTR" => true, 1859 1860 // FIXME: still necessary? 1861 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness 1862 // FIXME: deprecated - removed in glibc 2.26 1863 "SIGUNUSED" => true, 1864 1865 // Needs a newer Android SDK for the definition 1866 "P_PIDFD" => true, 1867 1868 // Requires Linux kernel 5.6 1869 "VMADDR_CID_LOCAL" => true, 1870 1871 // FIXME: conflicts with standard C headers and is tested in 1872 // `linux_termios.rs` below: 1873 "BOTHER" => true, 1874 "IBSHIFT" => true, 1875 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => true, 1876 1877 // is a private value for kernel usage normally 1878 "FUSE_SUPER_MAGIC" => true, 1879 // linux 5.12 min 1880 "MPOL_F_NUMA_BALANCING" => true, 1881 1882 // GRND_INSECURE was added in platform-tools-30.0.0 1883 "GRND_INSECURE" => true, 1884 1885 // kernel 5.10 minimum required 1886 "MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ" | "MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ" => true, 1887 1888 // kernel 5.18 minimum 1889 | "MADV_COLD" 1890 | "MADV_DONTNEED_LOCKED" 1891 | "MADV_PAGEOUT" 1892 | "MADV_POPULATE_READ" 1893 | "MADV_POPULATE_WRITE" => true, 1894 1895 // kernel 5.6 minimum required 1896 "IPPROTO_MPTCP" | "IPPROTO_ETHERNET" => true, 1897 1898 // kernel 6.2 minimum 1899 "TUN_F_USO4" | "TUN_F_USO6" | "IFF_NO_CARRIER" => true, 1900 1901 // FIXME: NDK r22 minimum required 1902 | "FDB_NOTIFY_BIT" 1903 | "FDB_NOTIFY_INACTIVE_BIT" 1904 | "IFLA_ALT_IFNAME" 1905 | "IFLA_PERM_ADDRESS" 1906 | "IFLA_PROP_LIST" 1907 | "IFLA_PROTO_DOWN_REASON" 1908 | "NDA_FDB_EXT_ATTRS" 1909 | "NDA_NH_ID" 1910 | "NFEA_ACTIVITY_NOTIFY" 1911 | "NFEA_DONT_REFRESH" 1912 | "NFEA_UNSPEC" => true, 1913 1914 // FIXME: NDK r23 minimum required 1915 | "IFLA_PARENT_DEV_BUS_NAME" 1916 | "IFLA_PARENT_DEV_NAME" => true, 1917 1918 // FIXME: NDK r25 minimum required 1919 | "IFLA_GRO_MAX_SIZE" 1920 | "NDA_FLAGS_EXT" 1921 | "NTF_EXT_MANAGED" => true, 1922 1923 // FIXME: NDK above r25 required 1924 | "IFLA_ALLMULTI" 1925 | "IFLA_DEVLINK_PORT" 1926 | "IFLA_GRO_IPV4_MAX_SIZE" 1927 | "IFLA_GSO_IPV4_MAX_SIZE" 1928 | "IFLA_TSO_MAX_SEGS" 1929 | "IFLA_TSO_MAX_SIZE" 1930 | "NDA_NDM_STATE_MASK" 1931 | "NDA_NDM_FLAGS_MASK" 1932 | "NDTPA_INTERVAL_PROBE_TIME_MS" 1933 | "NFQA_UNSPEC" 1934 | "NTF_EXT_LOCKED" 1935 | "ALG_SET_DRBG_ENTROPY" => true, 1936 1937 // FIXME: Something has been changed on r26b: 1938 | "IPPROTO_MAX" 1939 | "NFNL_SUBSYS_COUNT" 1940 | "NF_NETDEV_NUMHOOKS" 1941 | "NFT_MSG_MAX" 1942 | "SW_MAX" 1943 | "SW_CNT" => true, 1944 1945 // FIXME: aarch64 env cannot find it: 1946 | "PTRACE_GETREGS" 1947 | "PTRACE_SETREGS" if aarch64 => true, 1948 // FIXME: The value has been changed on r26b: 1949 | "SYS_syscalls" if aarch64 => true, 1950 1951 // From `<include/linux/sched.h>`. 1952 | "PF_VCPU" 1953 | "PF_IDLE" 1954 | "PF_EXITING" 1955 | "PF_POSTCOREDUMP" 1956 | "PF_IO_WORKER" 1957 | "PF_WQ_WORKER" 1958 | "PF_FORKNOEXEC" 1959 | "PF_SUPERPRIV" 1960 | "PF_DUMPCORE" 1961 | "PF_MCE_PROCESS" 1962 | "PF_SIGNALED" 1963 | "PF_MEMALLOC" 1964 | "PF_NPROC_EXCEEDED" 1965 | "PF_USED_MATH" 1966 | "PF_USER_WORKER" 1967 | "PF_NOFREEZE" 1968 | "PF_KSWAPD" 1969 | "PF_MEMALLOC_NOFS" 1970 | "PF_MEMALLOC_NOIO" 1971 | "PF_LOCAL_THROTTLE" 1972 | "PF_KTHREAD" 1973 | "PF_RANDOMIZE" 1974 | "PF_NO_SETAFFINITY" 1975 | "PF_MCE_EARLY" 1976 | "PF_MEMALLOC_PIN" 1977 | "PF_SUSPEND_TASK" => true, 1978 1979 _ => false, 1980 } 1981 }); 1982 1983 cfg.skip_fn(move |name| { 1984 // skip those that are manually verified 1985 match name { 1986 // FIXME: https://github.com/rust-lang/libc/issues/1272 1987 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 1988 1989 // There are two versions of the sterror_r function, see 1990 // 1991 // https://linux.die.net/man/3/strerror_r 1992 // 1993 // An XSI-compliant version provided if: 1994 // 1995 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE 1996 // 1997 // and a GNU specific version provided if _GNU_SOURCE is defined. 1998 // 1999 // libc provides bindings for the XSI-compliant version, which is 2000 // preferred for portable applications. 2001 // 2002 // We skip the test here since here _GNU_SOURCE is defined, and 2003 // test the XSI version below. 2004 "strerror_r" => true, 2005 "reallocarray" => true, 2006 "__system_property_wait" => true, 2007 2008 // Added in API level 30, but tests use level 28. 2009 "mlock2" => true, 2010 2011 // Added in glibc 2.25. 2012 "getentropy" => true, 2013 2014 // Added in API level 28, but some tests use level 24. 2015 "getrandom" => true, 2016 2017 // Added in API level 28, but some tests use level 24. 2018 "syncfs" => true, 2019 2020 // Added in API level 28, but some tests use level 24. 2021 "pthread_attr_getinheritsched" | "pthread_attr_setinheritsched" => true, 2022 // Added in API level 28, but some tests use level 24. 2023 "fread_unlocked" | "fwrite_unlocked" | "fgets_unlocked" | "fflush_unlocked" => true, 2024 2025 // FIXME: bad function pointers: 2026 "isalnum" | "isalpha" | "iscntrl" | "isdigit" | "isgraph" | "islower" | "isprint" 2027 | "ispunct" | "isspace" | "isupper" | "isxdigit" | "isblank" | "tolower" 2028 | "toupper" => true, 2029 2030 _ => false, 2031 } 2032 }); 2033 2034 cfg.skip_field_type(move |struct_, field| { 2035 // This is a weird union, don't check the type. 2036 (struct_ == "ifaddrs" && field == "ifa_ifu") || 2037 // sigval is actually a union, but we pretend it's a struct 2038 (struct_ == "sigevent" && field == "sigev_value") || 2039 // this one is an anonymous union 2040 (struct_ == "ff_effect" && field == "u") || 2041 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 2042 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 2043 (struct_ == "sigaction" && field == "sa_sigaction") || 2044 // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet. 2045 (struct_ == "signalfd_siginfo" && field == "ssi_call_addr") || 2046 // FIXME: Seems the type has been changed on NDK r26b 2047 (struct_ == "flock64" && (field == "l_start" || field == "l_len")) 2048 }); 2049 2050 cfg.skip_field(|struct_, field| { 2051 match (struct_, field) { 2052 // conflicting with `p_type` macro from <resolve.h>. 2053 ("Elf32_Phdr", "p_type") => true, 2054 ("Elf64_Phdr", "p_type") => true, 2055 2056 // this is actually a union on linux, so we can't represent it well and 2057 // just insert some padding. 2058 ("siginfo_t", "_pad") => true, 2059 ("ifreq", "ifr_ifru") => true, 2060 ("ifconf", "ifc_ifcu") => true, 2061 2062 _ => false, 2063 } 2064 }); 2065 2066 cfg.generate("../src/lib.rs", "main.rs"); 2067 2068 test_linux_like_apis(target); 2069 } 2070 2071 fn test_freebsd(target: &str) { 2072 assert!(target.contains("freebsd")); 2073 let mut cfg = ctest_cfg(); 2074 2075 let freebsd_ver = which_freebsd(); 2076 2077 match freebsd_ver { 2078 Some(12) => cfg.cfg("freebsd12", None), 2079 Some(13) => cfg.cfg("freebsd13", None), 2080 Some(14) => cfg.cfg("freebsd14", None), 2081 Some(15) => cfg.cfg("freebsd15", None), 2082 _ => &mut cfg, 2083 }; 2084 2085 // For sched linux compat fn 2086 cfg.define("_WITH_CPU_SET_T", None); 2087 // Required for `getline`: 2088 cfg.define("_WITH_GETLINE", None); 2089 // Required for making freebsd11_stat available in the headers 2090 cfg.define("_WANT_FREEBSD11_STAT", None); 2091 2092 let freebsd13 = match freebsd_ver { 2093 Some(n) if n >= 13 => true, 2094 _ => false, 2095 }; 2096 let freebsd14 = match freebsd_ver { 2097 Some(n) if n >= 14 => true, 2098 _ => false, 2099 }; 2100 let freebsd15 = match freebsd_ver { 2101 Some(n) if n >= 15 => true, 2102 _ => false, 2103 }; 2104 2105 headers! { cfg: 2106 "aio.h", 2107 "arpa/inet.h", 2108 "bsm/audit.h", 2109 "ctype.h", 2110 "dirent.h", 2111 "dlfcn.h", 2112 "elf.h", 2113 "errno.h", 2114 "execinfo.h", 2115 "fcntl.h", 2116 "getopt.h", 2117 "glob.h", 2118 "grp.h", 2119 "iconv.h", 2120 "ifaddrs.h", 2121 "kenv.h", 2122 "langinfo.h", 2123 "libgen.h", 2124 "libutil.h", 2125 "limits.h", 2126 "link.h", 2127 "locale.h", 2128 "machine/elf.h", 2129 "machine/reg.h", 2130 "malloc_np.h", 2131 "memstat.h", 2132 "mqueue.h", 2133 "net/bpf.h", 2134 "net/if.h", 2135 "net/if_arp.h", 2136 "net/if_dl.h", 2137 "net/if_mib.h", 2138 "net/route.h", 2139 "netdb.h", 2140 "netinet/ip.h", 2141 "netinet/in.h", 2142 "netinet/sctp.h", 2143 "netinet/tcp.h", 2144 "netinet/udp.h", 2145 "poll.h", 2146 "pthread.h", 2147 "pthread_np.h", 2148 "pwd.h", 2149 "regex.h", 2150 "resolv.h", 2151 "sched.h", 2152 "semaphore.h", 2153 "signal.h", 2154 "spawn.h", 2155 "stddef.h", 2156 "stdint.h", 2157 "stdio.h", 2158 "stdlib.h", 2159 "string.h", 2160 "sys/capsicum.h", 2161 "sys/auxv.h", 2162 "sys/cpuset.h", 2163 "sys/domainset.h", 2164 "sys/eui64.h", 2165 "sys/event.h", 2166 [freebsd13]:"sys/eventfd.h", 2167 "sys/extattr.h", 2168 "sys/file.h", 2169 "sys/ioctl.h", 2170 "sys/ipc.h", 2171 "sys/jail.h", 2172 "sys/mman.h", 2173 "sys/mount.h", 2174 "sys/msg.h", 2175 "sys/procctl.h", 2176 "sys/procdesc.h", 2177 "sys/ptrace.h", 2178 "sys/queue.h", 2179 "sys/random.h", 2180 "sys/reboot.h", 2181 "sys/resource.h", 2182 "sys/rtprio.h", 2183 "sys/sem.h", 2184 "sys/shm.h", 2185 "sys/socket.h", 2186 "sys/stat.h", 2187 "sys/statvfs.h", 2188 "sys/sysctl.h", 2189 "sys/thr.h", 2190 "sys/time.h", 2191 [freebsd14 || freebsd15]:"sys/timerfd.h", 2192 "sys/times.h", 2193 "sys/timex.h", 2194 "sys/types.h", 2195 "sys/proc.h", 2196 "kvm.h", // must be after "sys/types.h" 2197 "sys/ucontext.h", 2198 "sys/uio.h", 2199 "sys/ktrace.h", 2200 "sys/umtx.h", 2201 "sys/un.h", 2202 "sys/user.h", 2203 "sys/utsname.h", 2204 "sys/uuid.h", 2205 "sys/vmmeter.h", 2206 "sys/wait.h", 2207 "libprocstat.h", 2208 "devstat.h", 2209 "syslog.h", 2210 "termios.h", 2211 "time.h", 2212 "ufs/ufs/quota.h", 2213 "unistd.h", 2214 "utime.h", 2215 "utmpx.h", 2216 "wchar.h", 2217 } 2218 2219 cfg.type_name(move |ty, is_struct, is_union| { 2220 match ty { 2221 // Just pass all these through, no need for a "struct" prefix 2222 "FILE" 2223 | "fd_set" 2224 | "Dl_info" 2225 | "DIR" 2226 | "Elf32_Phdr" 2227 | "Elf64_Phdr" 2228 | "Elf32_Auxinfo" 2229 | "Elf64_Auxinfo" 2230 | "devstat_select_mode" 2231 | "devstat_support_flags" 2232 | "devstat_type_flags" 2233 | "devstat_match_flags" 2234 | "devstat_priority" => ty.to_string(), 2235 2236 // FIXME: https://github.com/rust-lang/libc/issues/1273 2237 "sighandler_t" => "sig_t".to_string(), 2238 2239 t if is_union => format!("union {}", t), 2240 2241 t if t.ends_with("_t") => t.to_string(), 2242 2243 // sigval is a struct in Rust, but a union in C: 2244 "sigval" => format!("union sigval"), 2245 2246 // put `struct` in front of all structs:. 2247 t if is_struct => format!("struct {}", t), 2248 2249 t => t.to_string(), 2250 } 2251 }); 2252 2253 cfg.field_name(move |struct_, field| { 2254 match field { 2255 // Our stat *_nsec fields normally don't actually exist but are part 2256 // of a timeval struct 2257 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2258 s.replace("e_nsec", ".tv_nsec") 2259 } 2260 // Field is named `type` in C but that is a Rust keyword, 2261 // so these fields are translated to `type_` in the bindings. 2262 "type_" if struct_ == "rtprio" => "type".to_string(), 2263 "type_" if struct_ == "sockstat" => "type".to_string(), 2264 "type_" if struct_ == "devstat_match_table" => "type".to_string(), 2265 s => s.to_string(), 2266 } 2267 }); 2268 2269 cfg.skip_const(move |name| { 2270 match name { 2271 // These constants were introduced in FreeBSD 13: 2272 "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" 2273 | "F_SEAL_WRITE" 2274 if Some(13) > freebsd_ver => 2275 { 2276 true 2277 } 2278 2279 // These constants were introduced in FreeBSD 13: 2280 "EFD_CLOEXEC" | "EFD_NONBLOCK" | "EFD_SEMAPHORE" if Some(13) > freebsd_ver => true, 2281 2282 // These constants were introduced in FreeBSD 12: 2283 "AT_RESOLVE_BENEATH" | "O_RESOLVE_BENEATH" if Some(12) > freebsd_ver => true, 2284 2285 // These constants were introduced in FreeBSD 13: 2286 "O_DSYNC" | "O_PATH" | "O_EMPTY_PATH" | "AT_EMPTY_PATH" if Some(13) > freebsd_ver => { 2287 true 2288 } 2289 2290 // These aliases were introduced in FreeBSD 13: 2291 // (note however that the constants themselves work on any version) 2292 "CLOCK_BOOTTIME" | "CLOCK_REALTIME_COARSE" | "CLOCK_MONOTONIC_COARSE" 2293 if Some(13) > freebsd_ver => 2294 { 2295 true 2296 } 2297 2298 // FIXME: These are deprecated - remove in a couple of releases. 2299 // These constants were removed in FreeBSD 11 (svn r273250) but will 2300 // still be accepted and ignored at runtime. 2301 "MAP_RENAME" | "MAP_NORESERVE" => true, 2302 2303 // FIXME: These are deprecated - remove in a couple of releases. 2304 // These constants were removed in FreeBSD 11 (svn r262489), 2305 // and they've never had any legitimate use outside of the 2306 // base system anyway. 2307 "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "USER_MAXID" => true, 2308 2309 // FIXME: This is deprecated - remove in a couple of releases. 2310 // This was removed in FreeBSD 14 (git 1b4701fe1e8) and never 2311 // should've been used anywhere anyway. 2312 "TDF_UNUSED23" => true, 2313 2314 // Removed in FreeBSD 15 2315 "TDF_CANSWAP" | "TDF_SWAPINREQ" => true, 2316 2317 // Unaccessible in FreeBSD 15 2318 "TDI_SWAPPED" | "P_SWAPPINGOUT" | "P_SWAPPINGIN" => true, 2319 2320 // Removed in FreeBSD 14 (git a6b55ee6be1) 2321 "IFF_KNOWSEPOCH" => true, 2322 2323 // Removed in FreeBSD 14 (git 7ff9ae90f0b) 2324 "IFF_NOGROUP" => true, 2325 2326 // FIXME: These are deprecated - remove in a couple of releases. 2327 // These symbols are not stable across OS-versions. They were 2328 // changed for FreeBSD 14 in git revisions b62848b0c3f and 2329 // 2cf7870864e. 2330 "PRI_MAX_ITHD" | "PRI_MIN_REALTIME" | "PRI_MAX_REALTIME" | "PRI_MIN_KERN" 2331 | "PRI_MAX_KERN" | "PSWP" | "PVM" | "PINOD" | "PRIBIO" | "PVFS" | "PZERO" | "PSOCK" 2332 | "PWAIT" | "PLOCK" | "PPAUSE" | "PRI_MIN_TIMESHARE" | "PUSER" | "PI_AV" | "PI_NET" 2333 | "PI_DISK" | "PI_TTY" | "PI_DULL" | "PI_SOFT" => true, 2334 2335 // This symbol changed in FreeBSD 14 (git 051e7d78b03), but the new 2336 // version should be safe to use on older releases. 2337 "IFCAP_CANTCHANGE" => true, 2338 2339 // These were removed in FreeBSD 14 (git c6d31b8306e) 2340 "TDF_ASTPENDING" | "TDF_NEEDSUSPCHK" | "TDF_NEEDRESCHED" | "TDF_NEEDSIGCHK" 2341 | "TDF_ALRMPEND" | "TDF_PROFPEND" | "TDF_MACPEND" => true, 2342 2343 // This constant was removed in FreeBSD 13 (svn r363622), and never 2344 // had any legitimate use outside of the base system anyway. 2345 "CTL_P1003_1B_MAXID" => true, 2346 2347 // This was renamed in FreeBSD 12.2 and 13 (r352486). 2348 "CTL_UNSPEC" | "CTL_SYSCTL" => true, 2349 2350 // This was renamed in FreeBSD 12.2 and 13 (r350749). 2351 "IPPROTO_SEP" | "IPPROTO_DCCP" => true, 2352 2353 // This was changed to 96(0x60) in FreeBSD 13: 2354 // https://github.com/freebsd/freebsd/ 2355 // commit/06b00ceaa914a3907e4e27bad924f44612bae1d7 2356 "MINCORE_SUPER" if Some(13) <= freebsd_ver => true, 2357 2358 // Added in FreeBSD 13.0 (r356667) 2359 "GRND_INSECURE" if Some(13) > freebsd_ver => true, 2360 2361 // Added in FreeBSD 13.0 (r349609) 2362 "PROC_PROTMAX_CTL" 2363 | "PROC_PROTMAX_STATUS" 2364 | "PROC_PROTMAX_FORCE_ENABLE" 2365 | "PROC_PROTMAX_FORCE_DISABLE" 2366 | "PROC_PROTMAX_NOFORCE" 2367 | "PROC_PROTMAX_ACTIVE" 2368 | "PROC_NO_NEW_PRIVS_CTL" 2369 | "PROC_NO_NEW_PRIVS_STATUS" 2370 | "PROC_NO_NEW_PRIVS_ENABLE" 2371 | "PROC_NO_NEW_PRIVS_DISABLE" 2372 | "PROC_WXMAP_CTL" 2373 | "PROC_WXMAP_STATUS" 2374 | "PROC_WX_MAPPINGS_PERMIT" 2375 | "PROC_WX_MAPPINGS_DISALLOW_EXEC" 2376 | "PROC_WXORX_ENFORCE" 2377 if Some(13) > freebsd_ver => 2378 { 2379 true 2380 } 2381 2382 // Added in in FreeBSD 13.0 (r367776 and r367287) 2383 "SCM_CREDS2" | "LOCAL_CREDS_PERSISTENT" if Some(13) > freebsd_ver => true, 2384 2385 // Added in FreeBSD 14 2386 "SPACECTL_DEALLOC" if Some(14) > freebsd_ver => true, 2387 2388 // Added in FreeBSD 13. 2389 "KERN_PROC_SIGFASTBLK" 2390 | "USER_LOCALBASE" 2391 | "TDP_SIGFASTBLOCK" 2392 | "TDP_UIOHELD" 2393 | "TDP_SIGFASTPENDING" 2394 | "TDP2_COMPAT32RB" 2395 | "P2_PROTMAX_ENABLE" 2396 | "P2_PROTMAX_DISABLE" 2397 | "CTLFLAG_NEEDGIANT" 2398 | "CTL_SYSCTL_NEXTNOSKIP" 2399 if Some(13) > freebsd_ver => 2400 { 2401 true 2402 } 2403 2404 // Added in freebsd 14. 2405 "IFCAP_MEXTPG" if Some(14) > freebsd_ver => true, 2406 // Added in freebsd 13. 2407 "IFCAP_TXTLS4" | "IFCAP_TXTLS6" | "IFCAP_VXLAN_HWCSUM" | "IFCAP_VXLAN_HWTSO" 2408 | "IFCAP_TXTLS_RTLMT" | "IFCAP_TXTLS" 2409 if Some(13) > freebsd_ver => 2410 { 2411 true 2412 } 2413 // Added in FreeBSD 13. 2414 "PS_FST_TYPE_EVENTFD" if Some(13) > freebsd_ver => true, 2415 2416 // Added in FreeBSD 14. 2417 "MNT_RECURSE" | "MNT_DEFERRED" if Some(14) > freebsd_ver => true, 2418 2419 // Added in FreeBSD 13. 2420 "MNT_EXTLS" | "MNT_EXTLSCERT" | "MNT_EXTLSCERTUSER" | "MNT_NOCOVER" 2421 | "MNT_EMPTYDIR" 2422 if Some(13) > freebsd_ver => 2423 { 2424 true 2425 } 2426 2427 // Added in FreeBSD 14. 2428 "PT_COREDUMP" | "PC_ALL" | "PC_COMPRESS" | "PT_GETREGSET" | "PT_SETREGSET" 2429 | "PT_SC_REMOTE" 2430 if Some(14) > freebsd_ver => 2431 { 2432 true 2433 } 2434 2435 // Added in FreeBSD 14. 2436 "F_KINFO" => true, // FIXME: depends how frequent freebsd 14 is updated on CI, this addition went this week only. 2437 "SHM_RENAME_NOREPLACE" 2438 | "SHM_RENAME_EXCHANGE" 2439 | "SHM_LARGEPAGE_ALLOC_DEFAULT" 2440 | "SHM_LARGEPAGE_ALLOC_NOWAIT" 2441 | "SHM_LARGEPAGE_ALLOC_HARD" 2442 | "MFD_CLOEXEC" 2443 | "MFD_ALLOW_SEALING" 2444 | "MFD_HUGETLB" 2445 | "MFD_HUGE_MASK" 2446 | "MFD_HUGE_64KB" 2447 | "MFD_HUGE_512KB" 2448 | "MFD_HUGE_1MB" 2449 | "MFD_HUGE_2MB" 2450 | "MFD_HUGE_8MB" 2451 | "MFD_HUGE_16MB" 2452 | "MFD_HUGE_32MB" 2453 | "MFD_HUGE_256MB" 2454 | "MFD_HUGE_512MB" 2455 | "MFD_HUGE_1GB" 2456 | "MFD_HUGE_2GB" 2457 | "MFD_HUGE_16GB" 2458 if Some(13) > freebsd_ver => 2459 { 2460 true 2461 } 2462 2463 // Flags introduced in FreeBSD 14. 2464 "TCP_MAXUNACKTIME" 2465 | "TCP_MAXPEAKRATE" 2466 | "TCP_IDLE_REDUCE" 2467 | "TCP_REMOTE_UDP_ENCAPS_PORT" 2468 | "TCP_DELACK" 2469 | "TCP_FIN_IS_RST" 2470 | "TCP_LOG_LIMIT" 2471 | "TCP_SHARED_CWND_ALLOWED" 2472 | "TCP_PROC_ACCOUNTING" 2473 | "TCP_USE_CMP_ACKS" 2474 | "TCP_PERF_INFO" 2475 | "TCP_LRD" 2476 if Some(14) > freebsd_ver => 2477 { 2478 true 2479 } 2480 2481 // Introduced in FreeBSD 14 then removed ? 2482 "TCP_LRD" if freebsd_ver >= Some(15) => true, 2483 2484 // Added in FreeBSD 14 2485 "LIO_READV" | "LIO_WRITEV" | "LIO_VECTORED" if Some(14) > freebsd_ver => true, 2486 2487 // Added in FreeBSD 13 2488 "FIOSSHMLPGCNF" if Some(13) > freebsd_ver => true, 2489 2490 // Added in FreeBSD 14 2491 "IFCAP_NV" if Some(14) > freebsd_ver => true, 2492 2493 // FIXME: Removed in https://reviews.freebsd.org/D38574 and https://reviews.freebsd.org/D38822 2494 // We maybe should deprecate them once a stable release ships them. 2495 "IP_BINDMULTI" | "IP_RSS_LISTEN_BUCKET" => true, 2496 2497 // FIXME: Removed in https://reviews.freebsd.org/D39127. 2498 "KERN_VNODE" => true, 2499 2500 // Added in FreeBSD 14 2501 "EV_KEEPUDATA" if Some(14) > freebsd_ver => true, 2502 2503 // Added in FreeBSD 13.2 2504 "AT_USRSTACKBASE" | "AT_USRSTACKLIM" if Some(13) > freebsd_ver => true, 2505 2506 // Added in FreeBSD 14 2507 "TFD_CLOEXEC" | "TFD_NONBLOCK" | "TFD_TIMER_ABSTIME" | "TFD_TIMER_CANCEL_ON_SET" 2508 if Some(14) > freebsd_ver => 2509 { 2510 true 2511 } 2512 2513 // FIXME: Removed in FreeBSD 15: 2514 "LOCAL_CONNWAIT" if freebsd_ver >= Some(15) => true, 2515 2516 // FIXME: The values has been changed in FreeBSD 15: 2517 "CLOCK_BOOTTIME" if Some(15) <= freebsd_ver => true, 2518 2519 _ => false, 2520 } 2521 }); 2522 2523 cfg.skip_type(move |ty| { 2524 match ty { 2525 // the struct "__kvm" is quite tricky to bind so since we only use a pointer to it 2526 // for now, it doesn't matter too much... 2527 "kvm_t" => true, 2528 // `eventfd(2)` and things come with it are added in FreeBSD 13 2529 "eventfd_t" if Some(13) > freebsd_ver => true, 2530 2531 _ => false, 2532 } 2533 }); 2534 2535 cfg.skip_struct(move |ty| { 2536 if ty.starts_with("__c_anonymous_") { 2537 return true; 2538 } 2539 match ty { 2540 // `procstat` is a private struct 2541 "procstat" => true, 2542 2543 // `spacectl_range` was introduced in FreeBSD 14 2544 "spacectl_range" if Some(14) > freebsd_ver => true, 2545 2546 // `ptrace_coredump` introduced in FreeBSD 14. 2547 "ptrace_coredump" if Some(14) > freebsd_ver => true, 2548 // `ptrace_sc_remote` introduced in FreeBSD 14. 2549 "ptrace_sc_remote" if Some(14) > freebsd_ver => true, 2550 2551 // `sockcred2` is not available in FreeBSD 12. 2552 "sockcred2" if Some(13) > freebsd_ver => true, 2553 // `shm_largepage_conf` was introduced in FreeBSD 13. 2554 "shm_largepage_conf" if Some(13) > freebsd_ver => true, 2555 2556 // Those are private types 2557 "memory_type" => true, 2558 "memory_type_list" => true, 2559 "pidfh" => true, 2560 "sctp_gen_error_cause" 2561 | "sctp_error_missing_param" 2562 | "sctp_remote_error" 2563 | "sctp_assoc_change" 2564 | "sctp_send_failed_event" 2565 | "sctp_stream_reset_event" => true, 2566 2567 // FIXME: Changed in FreeBSD 15 2568 "tcp_info" | "sockstat" if Some(15) >= freebsd_ver => true, 2569 2570 _ => false, 2571 } 2572 }); 2573 2574 cfg.skip_fn(move |name| { 2575 // skip those that are manually verified 2576 match name { 2577 // FIXME: https://github.com/rust-lang/libc/issues/1272 2578 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2579 2580 // The `uname` function in the `utsname.h` FreeBSD header is a C 2581 // inline function (has no symbol) that calls the `__xuname` symbol. 2582 // Therefore the function pointer comparison does not make sense for it. 2583 "uname" => true, 2584 2585 // FIXME: Our API is unsound. The Rust API allows aliasing 2586 // pointers, but the C API requires pointers not to alias. 2587 // We should probably be at least using `&`/`&mut` here, see: 2588 // https://github.com/gnzlbg/ctest/issues/68 2589 "lio_listio" => true, 2590 2591 // Those are introduced in FreeBSD 12. 2592 "clock_nanosleep" | "getrandom" | "elf_aux_info" | "setproctitle_fast" 2593 | "timingsafe_bcmp" | "timingsafe_memcmp" 2594 if Some(12) > freebsd_ver => 2595 { 2596 true 2597 } 2598 2599 // Those are introduced in FreeBSD 13. 2600 "memfd_create" 2601 | "shm_create_largepage" 2602 | "shm_rename" 2603 | "getentropy" 2604 | "eventfd" 2605 | "SOCKCRED2SIZE" 2606 | "getlocalbase" 2607 | "aio_readv" 2608 | "aio_writev" 2609 | "copy_file_range" 2610 | "eventfd_read" 2611 | "eventfd_write" 2612 if Some(13) > freebsd_ver => 2613 { 2614 true 2615 } 2616 2617 // Those are introduced in FreeBSD 14. 2618 "sched_getaffinity" | "sched_setaffinity" | "sched_getcpu" | "fspacectl" 2619 if Some(14) > freebsd_ver => 2620 { 2621 true 2622 } 2623 2624 // Those are introduced in FreeBSD 14. 2625 "timerfd_create" | "timerfd_gettime" | "timerfd_settime" if Some(14) > freebsd_ver => { 2626 true 2627 } 2628 2629 _ => false, 2630 } 2631 }); 2632 2633 cfg.volatile_item(|i| { 2634 use ctest::VolatileItemKind::*; 2635 match i { 2636 // aio_buf is a volatile void** but since we cannot express that in 2637 // Rust types, we have to explicitly tell the checker about it here: 2638 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 2639 _ => false, 2640 } 2641 }); 2642 2643 cfg.skip_field(move |struct_, field| { 2644 match (struct_, field) { 2645 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 2646 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 2647 ("sigaction", "sa_sigaction") => true, 2648 2649 // conflicting with `p_type` macro from <resolve.h>. 2650 ("Elf32_Phdr", "p_type") => true, 2651 ("Elf64_Phdr", "p_type") => true, 2652 2653 // not available until FreeBSD 12, and is an anonymous union there. 2654 ("xucred", "cr_pid__c_anonymous_union") => true, 2655 2656 // m_owner field is a volatile __lwpid_t 2657 ("umutex", "m_owner") => true, 2658 // c_has_waiters field is a volatile int32_t 2659 ("ucond", "c_has_waiters") => true, 2660 // is PATH_MAX long but tests can't accept multi array as equivalent. 2661 ("kinfo_vmentry", "kve_path") => true, 2662 2663 // a_un field is a union 2664 ("Elf32_Auxinfo", "a_un") => true, 2665 ("Elf64_Auxinfo", "a_un") => true, 2666 2667 // union fields 2668 ("if_data", "__ifi_epoch") => true, 2669 ("if_data", "__ifi_lastchange") => true, 2670 ("ifreq", "ifr_ifru") => true, 2671 ("ifconf", "ifc_ifcu") => true, 2672 2673 // anonymous struct 2674 ("devstat", "dev_links") => true, 2675 2676 // FIXME: structs too complicated to bind for now... 2677 ("kinfo_proc", "ki_paddr") => true, 2678 ("kinfo_proc", "ki_addr") => true, 2679 ("kinfo_proc", "ki_tracep") => true, 2680 ("kinfo_proc", "ki_textvp") => true, 2681 ("kinfo_proc", "ki_fd") => true, 2682 ("kinfo_proc", "ki_vmspace") => true, 2683 ("kinfo_proc", "ki_pcb") => true, 2684 ("kinfo_proc", "ki_tdaddr") => true, 2685 ("kinfo_proc", "ki_pd") => true, 2686 2687 // Anonymous type. 2688 ("filestat", "next") => true, 2689 2690 // We ignore this field because we needed to use a hack in order to make rust 1.19 2691 // happy... 2692 ("kinfo_proc", "ki_sparestrings") => true, 2693 2694 // `__sem_base` is a private struct field 2695 ("semid_ds", "__sem_base") => true, 2696 2697 // `snap_time` is a `long double`, but it's a nightmare to bind correctly in rust 2698 // for the moment, so it's a best effort thing... 2699 ("statinfo", "snap_time") => true, 2700 ("sctp_sndrcvinfo", "__reserve_pad") => true, 2701 ("sctp_extrcvinfo", "__reserve_pad") => true, 2702 // `tcp_snd_wscale` and `tcp_rcv_wscale` are bitfields 2703 ("tcp_info", "tcp_snd_wscale") => true, 2704 ("tcp_info", "tcp_rcv_wscale") => true, 2705 2706 _ => false, 2707 } 2708 }); 2709 2710 cfg.generate("../src/lib.rs", "main.rs"); 2711 } 2712 2713 fn test_emscripten(target: &str) { 2714 assert!(target.contains("emscripten")); 2715 2716 let mut cfg = ctest_cfg(); 2717 cfg.define("_GNU_SOURCE", None); // FIXME: ?? 2718 2719 headers! { cfg: 2720 "aio.h", 2721 "ctype.h", 2722 "dirent.h", 2723 "dlfcn.h", 2724 "errno.h", 2725 "fcntl.h", 2726 "glob.h", 2727 "grp.h", 2728 "ifaddrs.h", 2729 "langinfo.h", 2730 "limits.h", 2731 "locale.h", 2732 "malloc.h", 2733 "mntent.h", 2734 "mqueue.h", 2735 "net/ethernet.h", 2736 "net/if.h", 2737 "net/if_arp.h", 2738 "net/route.h", 2739 "netdb.h", 2740 "netinet/in.h", 2741 "netinet/ip.h", 2742 "netinet/tcp.h", 2743 "netinet/udp.h", 2744 "netpacket/packet.h", 2745 "poll.h", 2746 "pthread.h", 2747 "pty.h", 2748 "pwd.h", 2749 "resolv.h", 2750 "sched.h", 2751 "sched.h", 2752 "semaphore.h", 2753 "shadow.h", 2754 "signal.h", 2755 "stddef.h", 2756 "stdint.h", 2757 "stdio.h", 2758 "stdlib.h", 2759 "string.h", 2760 "sys/epoll.h", 2761 "sys/eventfd.h", 2762 "sys/file.h", 2763 "sys/ioctl.h", 2764 "sys/ipc.h", 2765 "sys/mman.h", 2766 "sys/mount.h", 2767 "sys/msg.h", 2768 "sys/personality.h", 2769 "sys/prctl.h", 2770 "sys/ptrace.h", 2771 "sys/quota.h", 2772 "sys/reboot.h", 2773 "sys/resource.h", 2774 "sys/sem.h", 2775 "sys/shm.h", 2776 "sys/signalfd.h", 2777 "sys/socket.h", 2778 "sys/stat.h", 2779 "sys/statvfs.h", 2780 "sys/swap.h", 2781 "sys/syscall.h", 2782 "sys/sysctl.h", 2783 "sys/sysinfo.h", 2784 "sys/time.h", 2785 "sys/timerfd.h", 2786 "sys/times.h", 2787 "sys/types.h", 2788 "sys/uio.h", 2789 "sys/un.h", 2790 "sys/user.h", 2791 "sys/utsname.h", 2792 "sys/vfs.h", 2793 "sys/wait.h", 2794 "sys/xattr.h", 2795 "syslog.h", 2796 "termios.h", 2797 "time.h", 2798 "ucontext.h", 2799 "unistd.h", 2800 "utime.h", 2801 "utmp.h", 2802 "utmpx.h", 2803 "wchar.h", 2804 } 2805 2806 cfg.type_name(move |ty, is_struct, is_union| { 2807 match ty { 2808 // Just pass all these through, no need for a "struct" prefix 2809 "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(), 2810 2811 "os_unfair_lock" => "struct os_unfair_lock_s".to_string(), 2812 2813 // LFS64 types have been removed in Emscripten 3.1.44+ 2814 // https://github.com/emscripten-core/emscripten/pull/19812 2815 "off64_t" => "off_t".to_string(), 2816 2817 // typedefs don't need any keywords 2818 t if t.ends_with("_t") => t.to_string(), 2819 2820 // put `struct` in front of all structs:. 2821 t if is_struct => format!("struct {}", t), 2822 2823 // put `union` in front of all unions: 2824 t if is_union => format!("union {}", t), 2825 2826 t => t.to_string(), 2827 } 2828 }); 2829 2830 cfg.field_name(move |struct_, field| { 2831 match field { 2832 // Our stat *_nsec fields normally don't actually exist but are part 2833 // of a timeval struct 2834 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2835 s.replace("e_nsec", ".tv_nsec") 2836 } 2837 // FIXME: appears that `epoll_event.data` is an union 2838 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 2839 s => s.to_string(), 2840 } 2841 }); 2842 2843 cfg.skip_type(move |ty| { 2844 match ty { 2845 // sighandler_t is crazy across platforms 2846 // FIXME: is this necessary? 2847 "sighandler_t" => true, 2848 2849 // FIXME: The size has been changed due to musl's time64 2850 "time_t" => true, 2851 2852 // LFS64 types have been removed in Emscripten 3.1.44+ 2853 // https://github.com/emscripten-core/emscripten/pull/19812 2854 t => t.ends_with("64") || t.ends_with("64_t"), 2855 } 2856 }); 2857 2858 cfg.skip_struct(move |ty| { 2859 match ty { 2860 // This is actually a union, not a struct 2861 // FIXME: is this necessary? 2862 "sigval" => true, 2863 2864 // FIXME: It was removed in 2865 // emscripten-core/emscripten@953e414 2866 "pthread_mutexattr_t" => true, 2867 2868 // FIXME: Investigate why the test fails. 2869 // Skip for now to unblock CI. 2870 "pthread_condattr_t" => true, 2871 2872 // FIXME: The size has been changed when upgraded to musl 1.2.2 2873 "pthread_mutex_t" => true, 2874 2875 // FIXME: Lowered from 16 to 8 bytes in 2876 // llvm/llvm-project@d1a96e9 2877 "max_align_t" => true, 2878 2879 // FIXME: The size has been changed due to time64 2880 "utimbuf" | "timeval" | "timespec" | "rusage" | "itimerval" | "sched_param" 2881 | "stat" | "stat64" | "shmid_ds" | "msqid_ds" => true, 2882 2883 // LFS64 types have been removed in Emscripten 3.1.44+ 2884 // https://github.com/emscripten-core/emscripten/pull/19812 2885 ty => ty.ends_with("64") || ty.ends_with("64_t"), 2886 } 2887 }); 2888 2889 cfg.skip_fn(move |name| { 2890 match name { 2891 // Emscripten does not support fork/exec/wait or any kind of multi-process support 2892 // https://github.com/emscripten-core/emscripten/blob/3.1.30/tools/system_libs.py#L973 2893 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" | "wait4" => true, 2894 2895 // FIXME: Remove after emscripten-core/emscripten#18492 is released (> 3.1.30). 2896 "clearenv" => true, 2897 2898 _ => false, 2899 } 2900 }); 2901 2902 cfg.skip_const(move |name| { 2903 match name { 2904 // FIXME: deprecated - SIGNUNUSED was removed in glibc 2.26 2905 // users should use SIGSYS instead 2906 "SIGUNUSED" => true, 2907 2908 // FIXME: emscripten uses different constants to constructs these 2909 n if n.contains("__SIZEOF_PTHREAD") => true, 2910 2911 // FIXME: `SYS_gettid` was removed in 2912 // emscripten-core/emscripten@6d6474e 2913 "SYS_gettid" => true, 2914 2915 // FIXME: These values have been changed 2916 | "POSIX_MADV_DONTNEED" // to 4 2917 | "RLIMIT_NLIMITS" // to 16 2918 | "RLIM_NLIMITS" // to 16 2919 | "IPPROTO_MAX" // to 263 2920 | "F_GETLK" // to 5 2921 | "F_SETLK" // to 6 2922 | "F_SETLKW" // to 7 2923 | "O_TMPFILE" // to 65 2924 | "SIG_IGN" // -1 2925 => true, 2926 2927 // LFS64 types have been removed in Emscripten 3.1.44+ 2928 // https://github.com/emscripten-core/emscripten/pull/19812 2929 n if n.starts_with("RLIM64") => true, 2930 2931 _ => false, 2932 } 2933 }); 2934 2935 cfg.skip_field_type(move |struct_, field| { 2936 // This is a weird union, don't check the type. 2937 // FIXME: is this necessary? 2938 (struct_ == "ifaddrs" && field == "ifa_ifu") || 2939 // sighandler_t type is super weird 2940 // FIXME: is this necessary? 2941 (struct_ == "sigaction" && field == "sa_sigaction") || 2942 // sigval is actually a union, but we pretend it's a struct 2943 // FIXME: is this necessary? 2944 (struct_ == "sigevent" && field == "sigev_value") || 2945 // aio_buf is "volatile void*" and Rust doesn't understand volatile 2946 // FIXME: is this necessary? 2947 (struct_ == "aiocb" && field == "aio_buf") 2948 }); 2949 2950 cfg.skip_field(move |struct_, field| { 2951 // this is actually a union on linux, so we can't represent it well and 2952 // just insert some padding. 2953 // FIXME: is this necessary? 2954 (struct_ == "siginfo_t" && field == "_pad") || 2955 // musl names this __dummy1 but it's still there 2956 // FIXME: is this necessary? 2957 (struct_ == "glob_t" && field == "gl_flags") || 2958 // musl seems to define this as an *anonymous* bitfield 2959 // FIXME: is this necessary? 2960 (struct_ == "statvfs" && field == "__f_unused") || 2961 // sigev_notify_thread_id is actually part of a sigev_un union 2962 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 2963 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet. 2964 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 2965 field == "_pad2" || 2966 field == "ssi_syscall" || 2967 field == "ssi_call_addr" || 2968 field == "ssi_arch")) || 2969 // FIXME: After musl 1.1.24, it have only one field `sched_priority`, 2970 // while other fields become reserved. 2971 (struct_ == "sched_param" && [ 2972 "sched_ss_low_priority", 2973 "sched_ss_repl_period", 2974 "sched_ss_init_budget", 2975 "sched_ss_max_repl", 2976 ].contains(&field)) 2977 }); 2978 2979 // FIXME: test linux like 2980 cfg.generate("../src/lib.rs", "main.rs"); 2981 } 2982 2983 fn test_neutrino(target: &str) { 2984 assert!(target.contains("nto-qnx")); 2985 2986 let mut cfg = ctest_cfg(); 2987 2988 headers! { cfg: 2989 "ctype.h", 2990 "dirent.h", 2991 "dlfcn.h", 2992 "sys/elf.h", 2993 "fcntl.h", 2994 "glob.h", 2995 "grp.h", 2996 "iconv.h", 2997 "ifaddrs.h", 2998 "limits.h", 2999 "sys/link.h", 3000 "locale.h", 3001 "sys/malloc.h", 3002 "rcheck/malloc.h", 3003 "malloc.h", 3004 "mqueue.h", 3005 "net/if.h", 3006 "net/if_arp.h", 3007 "net/route.h", 3008 "netdb.h", 3009 "netinet/in.h", 3010 "netinet/ip.h", 3011 "netinet/tcp.h", 3012 "netinet/udp.h", 3013 "netinet/ip_var.h", 3014 "sys/poll.h", 3015 "pthread.h", 3016 "pwd.h", 3017 "regex.h", 3018 "resolv.h", 3019 "sys/sched.h", 3020 "sched.h", 3021 "semaphore.h", 3022 "shadow.h", 3023 "signal.h", 3024 "spawn.h", 3025 "stddef.h", 3026 "stdint.h", 3027 "stdio.h", 3028 "stdlib.h", 3029 "string.h", 3030 "sys/sysctl.h", 3031 "sys/file.h", 3032 "sys/inotify.h", 3033 "sys/ioctl.h", 3034 "sys/ipc.h", 3035 "sys/mman.h", 3036 "sys/mount.h", 3037 "sys/msg.h", 3038 "sys/resource.h", 3039 "sys/sem.h", 3040 "sys/socket.h", 3041 "sys/stat.h", 3042 "sys/statvfs.h", 3043 "sys/swap.h", 3044 "sys/termio.h", 3045 "sys/time.h", 3046 "sys/times.h", 3047 "sys/types.h", 3048 "sys/uio.h", 3049 "sys/un.h", 3050 "sys/utsname.h", 3051 "sys/wait.h", 3052 "syslog.h", 3053 "termios.h", 3054 "time.h", 3055 "sys/time.h", 3056 "ucontext.h", 3057 "unistd.h", 3058 "utime.h", 3059 "utmp.h", 3060 "wchar.h", 3061 "aio.h", 3062 "nl_types.h", 3063 "langinfo.h", 3064 "unix.h", 3065 "nbutil.h", 3066 "aio.h", 3067 "net/bpf.h", 3068 "net/if_dl.h", 3069 "sys/syspage.h", 3070 3071 // TODO: The following header file doesn't appear as part of the default headers 3072 // found in a standard installation of Neutrino 7.1 SDP. The structures/ 3073 // functions dependent on it are currently commented out. 3074 //"sys/asyncmsg.h", 3075 } 3076 3077 // Create and include a header file containing 3078 // items which are not included in any official 3079 // header file. 3080 let internal_header = "internal.h"; 3081 let out_dir = env::var("OUT_DIR").unwrap(); 3082 cfg.header(internal_header); 3083 cfg.include(&out_dir); 3084 std::fs::write( 3085 out_dir.to_owned() + "/" + internal_header, 3086 "#ifndef __internal_h__ 3087 #define __internal_h__ 3088 void __my_thread_exit(const void **); 3089 #endif", 3090 ) 3091 .unwrap(); 3092 3093 cfg.type_name(move |ty, is_struct, is_union| { 3094 match ty { 3095 // Just pass all these through, no need for a "struct" prefix 3096 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 3097 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 3098 | "Elf32_Chdr" | "Elf64_Chdr" | "aarch64_qreg_t" | "syspage_entry_info" 3099 | "syspage_array_info" => ty.to_string(), 3100 3101 "Ioctl" => "int".to_string(), 3102 3103 t if is_union => format!("union {}", t), 3104 3105 t if t.ends_with("_t") => t.to_string(), 3106 3107 // put `struct` in front of all structs:. 3108 t if is_struct => format!("struct {}", t), 3109 3110 t => t.to_string(), 3111 } 3112 }); 3113 3114 cfg.field_name(move |_struct_, field| match field { 3115 "type_" => "type".to_string(), 3116 3117 s => s.to_string(), 3118 }); 3119 3120 cfg.volatile_item(|i| { 3121 use ctest::VolatileItemKind::*; 3122 match i { 3123 // The following fields are volatie but since we cannot express that in 3124 // Rust types, we have to explicitly tell the checker about it here: 3125 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 3126 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec_tod_adjust" => true, 3127 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec" => true, 3128 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec_stable" => true, 3129 StructField(ref n, ref f) if n == "intrspin" && f == "value" => true, 3130 _ => false, 3131 } 3132 }); 3133 3134 cfg.skip_type(move |ty| { 3135 match ty { 3136 // FIXME: `sighandler_t` type is incorrect, see: 3137 // https://github.com/rust-lang/libc/issues/1359 3138 "sighandler_t" => true, 3139 3140 // Does not exist in Neutrino 3141 "locale_t" => true, 3142 3143 _ => false, 3144 } 3145 }); 3146 3147 cfg.skip_struct(move |ty| { 3148 if ty.starts_with("__c_anonymous_") { 3149 return true; 3150 } 3151 match ty { 3152 "Elf64_Phdr" | "Elf32_Phdr" => true, 3153 3154 // FIXME: This is actually a union, not a struct 3155 "sigval" => true, 3156 3157 // union 3158 "_channel_connect_attr" => true, 3159 3160 _ => false, 3161 } 3162 }); 3163 3164 cfg.skip_const(move |name| { 3165 match name { 3166 // These signal "functions" are actually integer values that are casted to a fn ptr 3167 // This causes the compiler to err because of "illegal cast of int to ptr". 3168 "SIG_DFL" => true, 3169 "SIG_IGN" => true, 3170 "SIG_ERR" => true, 3171 3172 _ => false, 3173 } 3174 }); 3175 3176 cfg.skip_fn(move |name| { 3177 // skip those that are manually verified 3178 match name { 3179 // FIXME: https://github.com/rust-lang/libc/issues/1272 3180 "execv" | "execve" | "execvp" | "execvpe" => true, 3181 3182 // wrong signature 3183 "signal" => true, 3184 3185 // wrong signature of callback ptr 3186 "__cxa_atexit" => true, 3187 3188 // FIXME: Our API is unsound. The Rust API allows aliasing 3189 // pointers, but the C API requires pointers not to alias. 3190 // We should probably be at least using `&`/`&mut` here, see: 3191 // https://github.com/gnzlbg/ctest/issues/68 3192 "lio_listio" => true, 3193 3194 // 2 fields are actually unions which we're simply representing 3195 // as structures. 3196 "ChannelConnectAttr" => true, 3197 3198 // fields contains unions 3199 "SignalKillSigval" => true, 3200 "SignalKillSigval_r" => true, 3201 3202 // Not defined in any headers. Defined to work around a 3203 // stack unwinding bug. 3204 "__my_thread_exit" => true, 3205 3206 _ => false, 3207 } 3208 }); 3209 3210 cfg.skip_field_type(move |struct_, field| { 3211 // sigval is actually a union, but we pretend it's a struct 3212 struct_ == "sigevent" && field == "sigev_value" || 3213 // Anonymous structures 3214 struct_ == "_idle_hook" && field == "time" 3215 }); 3216 3217 cfg.skip_field(move |struct_, field| { 3218 (struct_ == "__sched_param" && field == "reserved") || 3219 (struct_ == "sched_param" && field == "reserved") || 3220 (struct_ == "sigevent" && field == "__padding1") || // ensure alignment 3221 (struct_ == "sigevent" && field == "__padding2") || // union 3222 (struct_ == "sigevent" && field == "__sigev_un2") || // union 3223 // sighandler_t type is super weird 3224 (struct_ == "sigaction" && field == "sa_sigaction") || 3225 // does not exist 3226 (struct_ == "syspage_entry" && field == "__reserved") || 3227 false // keep me for smaller diffs when something is added above 3228 }); 3229 3230 cfg.skip_static(move |name| (name == "__dso_handle")); 3231 3232 cfg.generate("../src/lib.rs", "main.rs"); 3233 } 3234 3235 fn test_vxworks(target: &str) { 3236 assert!(target.contains("vxworks")); 3237 3238 let mut cfg = ctest::TestGenerator::new(); 3239 headers! { cfg: 3240 "vxWorks.h", 3241 "yvals.h", 3242 "nfs/nfsCommon.h", 3243 "rtpLibCommon.h", 3244 "randomNumGen.h", 3245 "taskLib.h", 3246 "sysLib.h", 3247 "ioLib.h", 3248 "inetLib.h", 3249 "socket.h", 3250 "errnoLib.h", 3251 "ctype.h", 3252 "dirent.h", 3253 "dlfcn.h", 3254 "elf.h", 3255 "fcntl.h", 3256 "grp.h", 3257 "sys/poll.h", 3258 "ifaddrs.h", 3259 "langinfo.h", 3260 "limits.h", 3261 "link.h", 3262 "locale.h", 3263 "sys/stat.h", 3264 "netdb.h", 3265 "pthread.h", 3266 "pwd.h", 3267 "sched.h", 3268 "semaphore.h", 3269 "signal.h", 3270 "stddef.h", 3271 "stdint.h", 3272 "stdio.h", 3273 "stdlib.h", 3274 "string.h", 3275 "sys/file.h", 3276 "sys/ioctl.h", 3277 "sys/socket.h", 3278 "sys/time.h", 3279 "sys/times.h", 3280 "sys/types.h", 3281 "sys/uio.h", 3282 "sys/un.h", 3283 "sys/utsname.h", 3284 "sys/wait.h", 3285 "netinet/tcp.h", 3286 "syslog.h", 3287 "termios.h", 3288 "time.h", 3289 "ucontext.h", 3290 "unistd.h", 3291 "utime.h", 3292 "wchar.h", 3293 "errno.h", 3294 "sys/mman.h", 3295 "pathLib.h", 3296 "mqueue.h", 3297 } 3298 // FIXME 3299 cfg.skip_const(move |name| match name { 3300 // sighandler_t weirdness 3301 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" 3302 // This is not defined in vxWorks 3303 | "RTLD_DEFAULT" => true, 3304 _ => false, 3305 }); 3306 // FIXME 3307 cfg.skip_type(move |ty| match ty { 3308 "stat64" | "sighandler_t" | "off64_t" => true, 3309 _ => false, 3310 }); 3311 3312 cfg.skip_field_type(move |struct_, field| match (struct_, field) { 3313 ("siginfo_t", "si_value") | ("stat", "st_size") | ("sigaction", "sa_u") => true, 3314 _ => false, 3315 }); 3316 3317 cfg.skip_roundtrip(move |s| match s { 3318 _ => false, 3319 }); 3320 3321 cfg.type_name(move |ty, is_struct, is_union| match ty { 3322 "DIR" | "FILE" | "Dl_info" | "RTP_DESC" => ty.to_string(), 3323 t if is_union => format!("union {}", t), 3324 t if t.ends_with("_t") => t.to_string(), 3325 t if is_struct => format!("struct {}", t), 3326 t => t.to_string(), 3327 }); 3328 3329 // FIXME 3330 cfg.skip_fn(move |name| match name { 3331 // sigval 3332 "sigqueue" | "_sigqueue" 3333 // sighandler_t 3334 | "signal" 3335 // not used in static linking by default 3336 | "dlerror" => true, 3337 _ => false, 3338 }); 3339 3340 cfg.generate("../src/lib.rs", "main.rs"); 3341 } 3342 3343 fn test_linux(target: &str) { 3344 assert!(target.contains("linux")); 3345 3346 // target_env 3347 let gnu = target.contains("gnu"); 3348 let musl = target.contains("musl") || target.contains("ohos"); 3349 let uclibc = target.contains("uclibc"); 3350 3351 match (gnu, musl, uclibc) { 3352 (true, false, false) => (), 3353 (false, true, false) => (), 3354 (false, false, true) => (), 3355 (_, _, _) => panic!( 3356 "linux target lib is gnu: {}, musl: {}, uclibc: {}", 3357 gnu, musl, uclibc 3358 ), 3359 } 3360 3361 let arm = target.contains("arm"); 3362 let aarch64 = target.contains("aarch64"); 3363 let i686 = target.contains("i686"); 3364 let ppc = target.contains("powerpc"); 3365 let ppc64 = target.contains("powerpc64"); 3366 let s390x = target.contains("s390x"); 3367 let sparc64 = target.contains("sparc64"); 3368 let x32 = target.contains("x32"); 3369 let x86_32 = target.contains("i686"); 3370 let x86_64 = target.contains("x86_64"); 3371 let aarch64_musl = aarch64 && musl; 3372 let gnueabihf = target.contains("gnueabihf"); 3373 let x86_64_gnux32 = target.contains("gnux32") && x86_64; 3374 let riscv64 = target.contains("riscv64"); 3375 let loongarch64 = target.contains("loongarch64"); 3376 let uclibc = target.contains("uclibc"); 3377 3378 let mut cfg = ctest_cfg(); 3379 cfg.define("_GNU_SOURCE", None); 3380 // This macro re-defines fscanf,scanf,sscanf to link to the symbols that are 3381 // deprecated since glibc >= 2.29. This allows Rust binaries to link against 3382 // glibc versions older than 2.29. 3383 cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None); 3384 3385 headers! { cfg: 3386 "ctype.h", 3387 "dirent.h", 3388 "dlfcn.h", 3389 "elf.h", 3390 "fcntl.h", 3391 "getopt.h", 3392 "glob.h", 3393 [gnu]: "gnu/libc-version.h", 3394 "grp.h", 3395 "iconv.h", 3396 "ifaddrs.h", 3397 "langinfo.h", 3398 "libgen.h", 3399 "limits.h", 3400 "link.h", 3401 "linux/sysctl.h", 3402 "locale.h", 3403 "malloc.h", 3404 "mntent.h", 3405 "mqueue.h", 3406 "net/ethernet.h", 3407 "net/if.h", 3408 "net/if_arp.h", 3409 "net/route.h", 3410 "netdb.h", 3411 "netinet/in.h", 3412 "netinet/ip.h", 3413 "netinet/tcp.h", 3414 "netinet/udp.h", 3415 "netpacket/packet.h", 3416 "poll.h", 3417 "pthread.h", 3418 "pty.h", 3419 "pwd.h", 3420 "regex.h", 3421 "resolv.h", 3422 "sched.h", 3423 "semaphore.h", 3424 "shadow.h", 3425 "signal.h", 3426 "spawn.h", 3427 "stddef.h", 3428 "stdint.h", 3429 "stdio.h", 3430 "stdlib.h", 3431 "string.h", 3432 "sys/epoll.h", 3433 "sys/eventfd.h", 3434 "sys/file.h", 3435 "sys/fsuid.h", 3436 "sys/inotify.h", 3437 "sys/ioctl.h", 3438 "sys/ipc.h", 3439 "sys/mman.h", 3440 "sys/mount.h", 3441 "sys/msg.h", 3442 "sys/personality.h", 3443 "sys/prctl.h", 3444 "sys/ptrace.h", 3445 "sys/quota.h", 3446 "sys/random.h", 3447 "sys/reboot.h", 3448 "sys/resource.h", 3449 "sys/sem.h", 3450 "sys/sendfile.h", 3451 "sys/shm.h", 3452 "sys/signalfd.h", 3453 "sys/socket.h", 3454 "sys/stat.h", 3455 "sys/statvfs.h", 3456 "sys/swap.h", 3457 "sys/syscall.h", 3458 "sys/time.h", 3459 "sys/timerfd.h", 3460 "sys/times.h", 3461 "sys/timex.h", 3462 "sys/types.h", 3463 "sys/uio.h", 3464 "sys/un.h", 3465 "sys/user.h", 3466 "sys/utsname.h", 3467 "sys/vfs.h", 3468 "sys/wait.h", 3469 "syslog.h", 3470 "termios.h", 3471 "time.h", 3472 "ucontext.h", 3473 "unistd.h", 3474 "utime.h", 3475 "utmp.h", 3476 "utmpx.h", 3477 "wchar.h", 3478 "errno.h", 3479 // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit 3480 // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162 3481 // Also unavailable on gnueabihf with glibc 2.30. 3482 // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6b33f373c7b9199e00ba5fbafd94ac9bfb4337b1 3483 [(x86_64 || x86_32 || arm) && !gnueabihf]: "sys/io.h", 3484 // `sys/reg.h` is only available on x86 and x86_64 3485 [x86_64 || x86_32]: "sys/reg.h", 3486 // sysctl system call is deprecated and not available on musl 3487 // It is also unsupported in x32, deprecated since glibc 2.30: 3488 [!(x32 || musl || gnu)]: "sys/sysctl.h", 3489 // <execinfo.h> is not supported by musl: 3490 // https://www.openwall.com/lists/musl/2015/04/09/3 3491 // <execinfo.h> is not present on uclibc. 3492 [!(musl || uclibc)]: "execinfo.h", 3493 } 3494 3495 // Include linux headers at the end: 3496 headers! { 3497 cfg: 3498 [loongarch64]: "asm/hwcap.h", 3499 [riscv64]: "asm/hwcap.h", 3500 "asm/mman.h", 3501 [gnu]: "linux/aio_abi.h", 3502 "linux/can.h", 3503 "linux/can/raw.h", 3504 // FIXME: requires kernel headers >= 5.4.1. 3505 [!musl]: "linux/can/j1939.h", 3506 "linux/dccp.h", 3507 "linux/errqueue.h", 3508 "linux/falloc.h", 3509 "linux/filter.h", 3510 "linux/fs.h", 3511 "linux/futex.h", 3512 "linux/genetlink.h", 3513 "linux/if.h", 3514 "linux/if_addr.h", 3515 "linux/if_alg.h", 3516 "linux/if_ether.h", 3517 "linux/if_tun.h", 3518 "linux/if_xdp.h", 3519 "linux/input.h", 3520 "linux/ipv6.h", 3521 "linux/kexec.h", 3522 "linux/keyctl.h", 3523 "linux/magic.h", 3524 "linux/memfd.h", 3525 "linux/membarrier.h", 3526 "linux/mempolicy.h", 3527 "linux/mman.h", 3528 "linux/module.h", 3529 // FIXME: requires kernel headers >= 5.1. 3530 [!musl]: "linux/mount.h", 3531 "linux/net_tstamp.h", 3532 "linux/netfilter/nfnetlink.h", 3533 "linux/netfilter/nfnetlink_log.h", 3534 "linux/netfilter/nfnetlink_queue.h", 3535 "linux/netfilter/nf_tables.h", 3536 "linux/netfilter_ipv4.h", 3537 "linux/netfilter_ipv6.h", 3538 "linux/netfilter_ipv6/ip6_tables.h", 3539 "linux/netlink.h", 3540 // FIXME: requires Linux >= 5.6: 3541 [!musl]: "linux/openat2.h", 3542 [!musl]: "linux/ptrace.h", 3543 "linux/quota.h", 3544 "linux/random.h", 3545 "linux/reboot.h", 3546 "linux/rtnetlink.h", 3547 "linux/sched.h", 3548 "linux/sctp.h", 3549 "linux/seccomp.h", 3550 "linux/sock_diag.h", 3551 "linux/sockios.h", 3552 "linux/tls.h", 3553 "linux/uinput.h", 3554 "linux/vm_sockets.h", 3555 "linux/wait.h", 3556 "linux/wireless.h", 3557 "sys/fanotify.h", 3558 // <sys/auxv.h> is not present on uclibc 3559 [!uclibc]: "sys/auxv.h", 3560 [gnu]: "linux/close_range.h", 3561 } 3562 3563 // note: aio.h must be included before sys/mount.h 3564 headers! { 3565 cfg: 3566 "sys/xattr.h", 3567 "sys/sysinfo.h", 3568 // AIO is not supported by uclibc: 3569 [!uclibc]: "aio.h", 3570 } 3571 3572 cfg.type_name(move |ty, is_struct, is_union| { 3573 match ty { 3574 // Just pass all these through, no need for a "struct" prefix 3575 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 3576 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 3577 | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(), 3578 3579 "Ioctl" if gnu => "unsigned long".to_string(), 3580 "Ioctl" => "int".to_string(), 3581 3582 // LFS64 types have been removed in musl 1.2.4+ 3583 "off64_t" if musl => "off_t".to_string(), 3584 3585 // typedefs don't need any keywords 3586 t if t.ends_with("_t") => t.to_string(), 3587 // put `struct` in front of all structs:. 3588 t if is_struct => format!("struct {}", t), 3589 // put `union` in front of all unions: 3590 t if is_union => format!("union {}", t), 3591 3592 t => t.to_string(), 3593 } 3594 }); 3595 3596 cfg.field_name(move |struct_, field| { 3597 match field { 3598 // Our stat *_nsec fields normally don't actually exist but are part 3599 // of a timeval struct 3600 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 3601 s.replace("e_nsec", ".tv_nsec") 3602 } 3603 // FIXME: epoll_event.data is actually a union in C, but in Rust 3604 // it is only a u64 because we only expose one field 3605 // http://man7.org/linux/man-pages/man2/epoll_wait.2.html 3606 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 3607 // The following structs have a field called `type` in C, 3608 // but `type` is a Rust keyword, so these fields are translated 3609 // to `type_` in Rust. 3610 "type_" 3611 if struct_ == "input_event" 3612 || struct_ == "input_mask" 3613 || struct_ == "ff_effect" => 3614 { 3615 "type".to_string() 3616 } 3617 3618 s => s.to_string(), 3619 } 3620 }); 3621 3622 cfg.skip_type(move |ty| { 3623 match ty { 3624 // FIXME: `sighandler_t` type is incorrect, see: 3625 // https://github.com/rust-lang/libc/issues/1359 3626 "sighandler_t" => true, 3627 3628 // These cannot be tested when "resolv.h" is included and are tested 3629 // in the `linux_elf.rs` file. 3630 "Elf64_Phdr" | "Elf32_Phdr" => true, 3631 3632 // This type is private on Linux. It is implemented as a C `enum` 3633 // (`c_uint`) and this clashes with the type of the `rlimit` APIs 3634 // which expect a `c_int` even though both are ABI compatible. 3635 "__rlimit_resource_t" => true, 3636 // on Linux, this is a volatile int 3637 "pthread_spinlock_t" => true, 3638 3639 // For internal use only, to define architecture specific ioctl constants with a libc 3640 // specific type. 3641 "Ioctl" => true, 3642 3643 // FIXME: requires >= 5.4.1 kernel headers 3644 "pgn_t" if musl => true, 3645 "priority_t" if musl => true, 3646 "name_t" if musl => true, 3647 3648 t => { 3649 if musl { 3650 // LFS64 types have been removed in musl 1.2.4+ 3651 t.ends_with("64") || t.ends_with("64_t") 3652 } else { 3653 false 3654 } 3655 } 3656 } 3657 }); 3658 3659 cfg.skip_struct(move |ty| { 3660 if ty.starts_with("__c_anonymous_") { 3661 return true; 3662 } 3663 // FIXME: musl CI has old headers 3664 if musl && ty.starts_with("uinput_") { 3665 return true; 3666 } 3667 if musl && ty == "seccomp_notif" { 3668 return true; 3669 } 3670 if musl && ty == "seccomp_notif_addfd" { 3671 return true; 3672 } 3673 if musl && ty == "seccomp_notif_resp" { 3674 return true; 3675 } 3676 if musl && ty == "seccomp_notif_sizes" { 3677 return true; 3678 } 3679 3680 // LFS64 types have been removed in musl 1.2.4+ 3681 if musl && (ty.ends_with("64") || ty.ends_with("64_t")) { 3682 return true; 3683 } 3684 // FIXME: sparc64 CI has old headers 3685 if sparc64 && (ty == "uinput_ff_erase" || ty == "uinput_abs_setup") { 3686 return true; 3687 } 3688 // FIXME(https://github.com/rust-lang/libc/issues/1558): passing by 3689 // value corrupts the value for reasons not understood. 3690 if (gnu && sparc64) && (ty == "ip_mreqn" || ty == "hwtstamp_config") { 3691 return true; 3692 } 3693 match ty { 3694 // These cannot be tested when "resolv.h" is included and are tested 3695 // in the `linux_elf.rs` file. 3696 "Elf64_Phdr" | "Elf32_Phdr" => true, 3697 3698 // On Linux, the type of `ut_tv` field of `struct utmpx` 3699 // can be an anonymous struct, so an extra struct, 3700 // which is absent in glibc, has to be defined. 3701 "__timeval" => true, 3702 3703 // FIXME: This is actually a union, not a struct 3704 "sigval" => true, 3705 3706 // This type is tested in the `linux_termios.rs` file since there 3707 // are header conflicts when including them with all the other 3708 // structs. 3709 "termios2" => true, 3710 3711 // FIXME: remove once we set minimum supported glibc version. 3712 // ucontext_t added a new field as of glibc 2.28; our struct definition is 3713 // conservative and omits the field, but that means the size doesn't match for newer 3714 // glibcs (see https://github.com/rust-lang/libc/issues/1410) 3715 "ucontext_t" if gnu => true, 3716 3717 // FIXME: Somehow we cannot include headers correctly in glibc 2.30. 3718 // So let's ignore for now and re-visit later. 3719 // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085 3720 "statx" => true, 3721 "statx_timestamp" => true, 3722 3723 // On Linux, the type of `ut_exit` field of struct `utmpx` 3724 // can be an anonymous struct, so an extra struct, 3725 // which is absent in musl, has to be defined. 3726 "__exit_status" if musl => true, 3727 3728 // clone_args might differ b/w libc versions 3729 "clone_args" => true, 3730 3731 // Might differ between kernel versions 3732 "open_how" => true, 3733 3734 // FIXME: requires >= 5.4.1 kernel headers 3735 "j1939_filter" if musl => true, 3736 3737 // FIXME: requires >= 5.4 kernel headers 3738 "sockaddr_can" if musl => true, 3739 3740 "sctp_initmsg" | "sctp_sndrcvinfo" | "sctp_sndinfo" | "sctp_rcvinfo" 3741 | "sctp_nxtinfo" | "sctp_prinfo" | "sctp_authinfo" => true, 3742 3743 // FIXME: requires >= 6.1 kernel headers 3744 "canxl_frame" => true, 3745 3746 // FIXME: The size of `iv` has been changed since Linux v6.0 3747 // https://github.com/torvalds/linux/commit/94dfc73e7cf4a31da66b8843f0b9283ddd6b8381 3748 "af_alg_iv" => true, 3749 3750 // FIXME: Requires >= 5.1 kernel headers. 3751 // Everything that uses install-musl.sh has 4.19 kernel headers. 3752 "tls12_crypto_info_aes_gcm_256" 3753 if (aarch64 || arm || i686 || s390x || x86_64) && musl => 3754 { 3755 true 3756 } 3757 3758 // FIXME: Requires >= 5.11 kernel headers. 3759 // Everything that uses install-musl.sh has 4.19 kernel headers. 3760 "tls12_crypto_info_chacha20_poly1305" 3761 if (aarch64 || arm || i686 || s390x || x86_64) && musl => 3762 { 3763 true 3764 } 3765 3766 // FIXME: Requires >= 5.3 kernel headers. 3767 // Everything that uses install-musl.sh has 4.19 kernel headers. 3768 "xdp_options" if musl => true, 3769 3770 // FIXME: Requires >= 5.4 kernel headers. 3771 // Everything that uses install-musl.sh has 4.19 kernel headers. 3772 "xdp_umem_reg" | "xdp_ring_offset" | "xdp_mmap_offsets" if musl => true, 3773 3774 // FIXME: Requires >= 5.9 kernel headers. 3775 // Everything that uses install-musl.sh has 4.19 kernel headers. 3776 "xdp_statistics" if musl => true, 3777 3778 // A new field was added in kernel 5.4, this is the old version for backwards compatibility. 3779 // https://github.com/torvalds/linux/commit/77cd0d7b3f257fd0e3096b4fdcff1a7d38e99e10 3780 "xdp_ring_offset_v1" | "xdp_mmap_offsets_v1" => true, 3781 3782 // Multiple new fields were added in kernel 5.9, this is the old version for backwards compatibility. 3783 // https://github.com/torvalds/linux/commit/77cd0d7b3f257fd0e3096b4fdcff1a7d38e99e10 3784 "xdp_statistics_v1" => true, 3785 3786 // A new field was added in kernel 5.4, this is the old version for backwards compatibility. 3787 // https://github.com/torvalds/linux/commit/c05cd3645814724bdeb32a2b4d953b12bdea5f8c 3788 "xdp_umem_reg_v1" => true, 3789 3790 // Is defined in `<linux/sched/types.h>` but if this file is included at the same time 3791 // as `<sched.h>`, the `struct sched_param` is defined twice, causing the compilation to 3792 // fail. The problem doesn't seem to be present in more recent versions of the linux 3793 // kernel so we can drop this and test the type once this new version is used in CI. 3794 "sched_attr" => true, 3795 3796 _ => false, 3797 } 3798 }); 3799 3800 cfg.skip_const(move |name| { 3801 if !gnu { 3802 // Skip definitions from the kernel on non-glibc Linux targets. 3803 // They're libc-independent, so we only need to check them on one 3804 // libc. We don't want to break CI if musl or another libc doesn't 3805 // have the definitions yet. (We do still want to check them on 3806 // every glibc target, though, as some of them can vary by 3807 // architecture.) 3808 // 3809 // This is not an exhaustive list of kernel constants, just a list 3810 // of prefixes of all those that have appeared here or that get 3811 // updated regularly and seem likely to cause breakage. 3812 if name.starts_with("AF_") 3813 || name.starts_with("ARPHRD_") 3814 || name.starts_with("EPOLL") 3815 || name.starts_with("F_") 3816 || name.starts_with("FALLOC_FL_") 3817 || name.starts_with("IFLA_") 3818 || name.starts_with("KEXEC_") 3819 || name.starts_with("MS_") 3820 || name.starts_with("MSG_") 3821 || name.starts_with("OPEN_TREE_") 3822 || name.starts_with("P_") 3823 || name.starts_with("PF_") 3824 || name.starts_with("RLIMIT_") 3825 || name.starts_with("RTEXT_FILTER_") 3826 || name.starts_with("SOL_") 3827 || name.starts_with("STATX_") 3828 || name.starts_with("SW_") 3829 || name.starts_with("SYS_") 3830 || name.starts_with("TCP_") 3831 || name.starts_with("UINPUT_") 3832 || name.starts_with("VMADDR_") 3833 { 3834 return true; 3835 } 3836 } 3837 if musl { 3838 // FIXME: Requires >= 5.0 kernel headers 3839 if name == "SECCOMP_GET_NOTIF_SIZES" 3840 || name == "SECCOMP_FILTER_FLAG_NEW_LISTENER" 3841 || name == "SECCOMP_FILTER_FLAG_TSYNC_ESRCH" 3842 || name == "SECCOMP_USER_NOTIF_FLAG_CONTINUE" // requires >= 5.5 3843 || name == "SECCOMP_ADDFD_FLAG_SETFD" // requires >= 5.9 3844 || name == "SECCOMP_ADDFD_FLAG_SEND" // requires >= 5.9 3845 || name == "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV" // requires >= 5.19 3846 { 3847 return true; 3848 } 3849 // FIXME: Requires >= 5.4.1 kernel headers 3850 if name.starts_with("J1939") 3851 || name.starts_with("RTEXT_FILTER_") 3852 || name.starts_with("SO_J1939") 3853 || name.starts_with("SCM_J1939") 3854 { 3855 return true; 3856 } 3857 // FIXME: Requires >= 5.10 kernel headers 3858 if name.starts_with("MEMBARRIER_CMD_REGISTER") 3859 || name.starts_with("MEMBARRIER_CMD_PRIVATE") 3860 { 3861 return true; 3862 } 3863 // LFS64 types have been removed in musl 1.2.4+ 3864 if name.starts_with("RLIM64") { 3865 return true; 3866 } 3867 // CI fails because musl targets use Linux v4 kernel 3868 if name.starts_with("NI_IDN") { 3869 return true; 3870 } 3871 // FIXME: Requires >= 6.3 kernel headers 3872 if name == "MFD_NOEXEC_SEAL" || name == "MFD_EXEC" { 3873 return true; 3874 } 3875 } 3876 match name { 3877 // These constants are not available if gnu headers have been included 3878 // and can therefore not be tested here 3879 // 3880 // The IPV6 constants are tested in the `linux_ipv6.rs` tests: 3881 | "IPV6_FLOWINFO" 3882 | "IPV6_FLOWLABEL_MGR" 3883 | "IPV6_FLOWINFO_SEND" 3884 | "IPV6_FLOWINFO_FLOWLABEL" 3885 | "IPV6_FLOWINFO_PRIORITY" 3886 // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: 3887 | "F_CANCELLK" 3888 | "F_ADD_SEALS" 3889 | "F_GET_SEALS" 3890 | "F_SEAL_SEAL" 3891 | "F_SEAL_SHRINK" 3892 | "F_SEAL_GROW" 3893 | "F_SEAL_WRITE" => true, 3894 // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests 3895 // because including `linux/if_arp.h` causes some conflicts: 3896 "ARPHRD_CAN" => true, 3897 3898 // FIXME: deprecated: not available in any header 3899 // See: https://github.com/rust-lang/libc/issues/1356 3900 "ENOATTR" => true, 3901 3902 // FIXME: SIGUNUSED was removed in glibc 2.26 3903 // Users should use SIGSYS instead. 3904 "SIGUNUSED" => true, 3905 3906 // FIXME: conflicts with glibc headers and is tested in 3907 // `linux_termios.rs` below: 3908 | "BOTHER" 3909 | "IBSHIFT" 3910 | "TCGETS2" 3911 | "TCSETS2" 3912 | "TCSETSW2" 3913 | "TCSETSF2" => true, 3914 3915 // FIXME: on musl the pthread types are defined a little differently 3916 // - these constants are used by the glibc implementation. 3917 n if musl && n.contains("__SIZEOF_PTHREAD") => true, 3918 3919 // FIXME: It was extended to 4096 since glibc 2.31 (Linux 5.4). 3920 // We should do so after a while. 3921 "SOMAXCONN" if gnu => true, 3922 3923 // deprecated: not available from Linux kernel 5.6: 3924 "VMADDR_CID_RESERVED" => true, 3925 3926 // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP: 3927 | "IPPROTO_MAX" 3928 | "IPPROTO_ETHERNET" 3929 | "IPPROTO_MPTCP" => true, 3930 3931 // FIXME: Not yet implemented on sparc64 3932 "SYS_clone3" if sparc64 => true, 3933 3934 // FIXME: Not defined on ARM, gnueabihf, musl, PowerPC, riscv64, s390x, and sparc64. 3935 "SYS_memfd_secret" if arm | gnueabihf | musl | ppc | riscv64 | s390x | sparc64 => true, 3936 3937 // FIXME: Added in Linux 5.16 3938 // https://github.com/torvalds/linux/commit/039c0ec9bb77446d7ada7f55f90af9299b28ca49 3939 "SYS_futex_waitv" => true, 3940 3941 // FIXME: Added in Linux 5.17 3942 // https://github.com/torvalds/linux/commit/c6018b4b254971863bd0ad36bb5e7d0fa0f0ddb0 3943 "SYS_set_mempolicy_home_node" => true, 3944 3945 // FIXME: Added in Linux 5.18 3946 // https://github.com/torvalds/linux/commit/8b5413647262dda8d8d0e07e14ea1de9ac7cf0b2 3947 "NFQA_PRIORITY" => true, 3948 3949 // FIXME: requires more recent kernel headers on CI 3950 | "UINPUT_VERSION" 3951 | "SW_MAX" 3952 | "SW_CNT" 3953 if ppc64 || riscv64 => true, 3954 3955 // FIXME: requires more recent kernel headers on CI 3956 | "MFD_EXEC" 3957 | "MFD_NOEXEC_SEAL" 3958 | "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV" 3959 if sparc64 => true, 3960 3961 // FIXME: Not currently available in headers on ARM and musl. 3962 "NETLINK_GET_STRICT_CHK" if arm || musl => true, 3963 3964 // kernel constants not available in uclibc 1.0.34 3965 | "EXTPROC" 3966 | "IPPROTO_BEETPH" 3967 | "IPPROTO_MPLS" 3968 | "IPV6_HDRINCL" 3969 | "IPV6_MULTICAST_ALL" 3970 | "IPV6_PMTUDISC_INTERFACE" 3971 | "IPV6_PMTUDISC_OMIT" 3972 | "IPV6_ROUTER_ALERT_ISOLATE" 3973 | "PACKET_MR_UNICAST" 3974 | "RUSAGE_THREAD" 3975 | "SHM_EXEC" 3976 | "UDP_GRO" 3977 | "UDP_SEGMENT" 3978 if uclibc => true, 3979 3980 // headers conflicts with linux/pidfd.h 3981 "PIDFD_NONBLOCK" => true, 3982 3983 // is a private value for kernel usage normally 3984 "FUSE_SUPER_MAGIC" => true, 3985 3986 // linux 5.17 min 3987 "PR_SET_VMA" | "PR_SET_VMA_ANON_NAME" => true, 3988 3989 // present in recent kernels only 3990 "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, 3991 3992 // present in recent kernels only >= 5.13 3993 "PR_PAC_SET_ENABLED_KEYS" | "PR_PAC_GET_ENABLED_KEYS" => true, 3994 // present in recent kernels only >= 5.19 3995 "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, 3996 3997 // Added in Linux 5.14 3998 "FUTEX_LOCK_PI2" => true, 3999 4000 // Added in linux 6.1 4001 "STATX_DIOALIGN" 4002 | "CAN_RAW_XL_FRAMES" 4003 | "CANXL_HDR_SIZE" 4004 | "CANXL_MAX_DLC" 4005 | "CANXL_MAX_DLC_MASK" 4006 | "CANXL_MAX_DLEN" 4007 | "CANXL_MAX_MTU" 4008 | "CANXL_MIN_DLC" 4009 | "CANXL_MIN_DLEN" 4010 | "CANXL_MIN_MTU" 4011 | "CANXL_MTU" 4012 | "CANXL_PRIO_BITS" 4013 | "CANXL_PRIO_MASK" 4014 | "CANXL_SEC" 4015 | "CANXL_XLF" 4016 => true, 4017 4018 // FIXME: Parts of netfilter/nfnetlink*.h require more recent kernel headers: 4019 | "RTNLGRP_MCTP_IFADDR" // linux v5.17+ 4020 | "RTNLGRP_TUNNEL" // linux v5.18+ 4021 | "RTNLGRP_STATS" // linux v5.18+ 4022 => true, 4023 4024 // FIXME: The below is no longer const in glibc 2.34: 4025 // https://github.com/bminor/glibc/commit/5d98a7dae955bafa6740c26eaba9c86060ae0344 4026 | "PTHREAD_STACK_MIN" 4027 | "SIGSTKSZ" 4028 | "MINSIGSTKSZ" 4029 if gnu => true, 4030 4031 // FIXME: Linux >= 5.16 changed its value: 4032 // https://github.com/torvalds/linux/commit/42df6e1d221dddc0f2acf2be37e68d553ad65f96 4033 "NF_NETDEV_NUMHOOKS" => true, 4034 4035 // FIXME: requires Linux >= 5.6: 4036 | "RESOLVE_BENEATH" 4037 | "RESOLVE_CACHED" 4038 | "RESOLVE_IN_ROOT" 4039 | "RESOLVE_NO_MAGICLINKS" 4040 | "RESOLVE_NO_SYMLINKS" 4041 | "RESOLVE_NO_XDEV" if musl => true, 4042 4043 // FIXME: requires Linux >= 5.4: 4044 | "CAN_J1939" 4045 | "CAN_NPROTO" if musl => true, 4046 4047 // FIXME: requires Linux >= 5.6 4048 "GRND_INSECURE" if musl => true, 4049 4050 // FIXME: requires Linux >= 5.7: 4051 "MREMAP_DONTUNMAP" if musl => true, 4052 4053 // FIXME: requires Linux >= v5.8 4054 "IF_LINK_MODE_TESTING" if musl || sparc64 => true, 4055 4056 // FIXME: Requires more recent kernel headers (5.9 / 5.11): 4057 | "CLOSE_RANGE_UNSHARE" 4058 | "CLOSE_RANGE_CLOEXEC" if musl => true, 4059 4060 // FIXME: requires Linux >= 5.12: 4061 "MPOL_F_NUMA_BALANCING" if musl => true, 4062 4063 // FIXME: Requires more recent kernel headers 4064 | "NFNL_SUBSYS_COUNT" // bumped in v5.14 4065 | "NFNL_SUBSYS_HOOK" // v5.14+ 4066 | "NFULA_VLAN" // v5.4+ 4067 | "NFULA_L2HDR" // v5.4+ 4068 | "NFULA_VLAN_PROTO" // v5.4+ 4069 | "NFULA_VLAN_TCI" // v5.4+ 4070 | "NFULA_VLAN_UNSPEC" // v5.4+ 4071 | "RTNLGRP_NEXTHOP" // linux v5.3+ 4072 | "RTNLGRP_BRVLAN" // linux v5.6+ 4073 if musl => true, 4074 4075 | "MADV_COLD" 4076 | "MADV_PAGEOUT" 4077 | "MADV_POPULATE_READ" 4078 | "MADV_POPULATE_WRITE" 4079 if musl => true, 4080 "CLONE_CLEAR_SIGHAND" | "CLONE_INTO_CGROUP" => true, 4081 4082 // kernel 6.1 minimum 4083 "MADV_COLLAPSE" => true, 4084 4085 // kernel 6.2 minimum 4086 "TUN_F_USO4" | "TUN_F_USO6" | "IFF_NO_CARRIER" => true, 4087 4088 // FIXME: Requires more recent kernel headers 4089 | "IFLA_PARENT_DEV_NAME" // linux v5.13+ 4090 | "IFLA_PARENT_DEV_BUS_NAME" // linux v5.13+ 4091 | "IFLA_GRO_MAX_SIZE" // linux v5.16+ 4092 | "IFLA_TSO_MAX_SIZE" // linux v5.18+ 4093 | "IFLA_TSO_MAX_SEGS" // linux v5.18+ 4094 | "IFLA_ALLMULTI" // linux v6.0+ 4095 | "MADV_DONTNEED_LOCKED" // linux v5.18+ 4096 => true, 4097 "SCTP_FUTURE_ASSOC" | "SCTP_CURRENT_ASSOC" | "SCTP_ALL_ASSOC" | "SCTP_PEER_ADDR_THLDS_V2" => true, // linux 5.5+ 4098 4099 // FIXME: Requires more recent kernel headers 4100 "HWTSTAMP_TX_ONESTEP_P2P" if musl => true, // linux v5.6+ 4101 4102 // kernel 6.5 minimum 4103 "MOVE_MOUNT_BENEATH" => true, 4104 // FIXME: Requires linux 6.1 4105 "ALG_SET_KEY_BY_KEY_SERIAL" | "ALG_SET_DRBG_ENTROPY" => true, 4106 4107 // FIXME: Requires more recent kernel headers 4108 | "FAN_FS_ERROR" // linux v5.16+ 4109 | "FAN_RENAME" // linux v5.17+ 4110 | "FAN_REPORT_TARGET_FID" // linux v5.17+ 4111 | "FAN_REPORT_DFID_NAME_TARGET" // linux v5.17+ 4112 | "FAN_MARK_EVICTABLE" // linux v5.19+ 4113 | "FAN_MARK_IGNORE" // linux v6.0+ 4114 | "FAN_MARK_IGNORE_SURV" // linux v6.0+ 4115 | "FAN_EVENT_INFO_TYPE_ERROR" // linux v5.16+ 4116 | "FAN_EVENT_INFO_TYPE_OLD_DFID_NAME" // linux v5.17+ 4117 | "FAN_EVENT_INFO_TYPE_NEW_DFID_NAME" // linux v5.17+ 4118 | "FAN_RESPONSE_INFO_NONE" // linux v5.16+ 4119 | "FAN_RESPONSE_INFO_AUDIT_RULE" // linux v5.16+ 4120 | "FAN_INFO" // linux v5.16+ 4121 => true, 4122 4123 // FIXME: Requires linux 5.15+ 4124 "FAN_REPORT_PIDFD" if musl => true, 4125 4126 // FIXME: Requires linux 5.9+ 4127 | "FAN_REPORT_DIR_FID" 4128 | "FAN_REPORT_NAME" 4129 | "FAN_REPORT_DFID_NAME" 4130 | "FAN_EVENT_INFO_TYPE_DFID_NAME" 4131 | "FAN_EVENT_INFO_TYPE_DFID" 4132 | "FAN_EVENT_INFO_TYPE_PIDFD" 4133 | "FAN_NOPIDFD" 4134 | "FAN_EPIDFD" 4135 if musl => true, 4136 4137 // FIXME: Requires linux 6.5 4138 "NFT_MSG_MAX" => true, 4139 4140 // FIXME: Requires >= 5.1 kernel headers. 4141 // Everything that uses install-musl.sh has 4.19 kernel headers. 4142 "TLS_1_3_VERSION" 4143 | "TLS_1_3_VERSION_MAJOR" 4144 | "TLS_1_3_VERSION_MINOR" 4145 | "TLS_CIPHER_AES_GCM_256" 4146 | "TLS_CIPHER_AES_GCM_256_IV_SIZE" 4147 | "TLS_CIPHER_AES_GCM_256_KEY_SIZE" 4148 | "TLS_CIPHER_AES_GCM_256_SALT_SIZE" 4149 | "TLS_CIPHER_AES_GCM_256_TAG_SIZE" 4150 | "TLS_CIPHER_AES_GCM_256_REC_SEQ_SIZE" 4151 if (aarch64 || arm || i686 || s390x || x86_64) && musl => 4152 { 4153 true 4154 } 4155 4156 // FIXME: Requires >= 5.11 kernel headers. 4157 // Everything that uses install-musl.sh has 4.19 kernel headers. 4158 "TLS_CIPHER_CHACHA20_POLY1305" 4159 | "TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE" 4160 | "TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE" 4161 | "TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE" 4162 | "TLS_CIPHER_CHACHA20_POLY1305_TAG_SIZE" 4163 | "TLS_CIPHER_CHACHA20_POLY1305_REC_SEQ_SIZE" 4164 if (aarch64 || arm || i686 || s390x || x86_64) && musl => 4165 { 4166 true 4167 } 4168 4169 // FIXME: Requires >= 5.3 kernel headers. 4170 // Everything that uses install-musl.sh has 4.19 kernel headers. 4171 "XDP_OPTIONS_ZEROCOPY" | "XDP_OPTIONS" 4172 if musl => 4173 { 4174 true 4175 } 4176 4177 // FIXME: Requires >= 5.4 kernel headers. 4178 // Everything that uses install-musl.sh has 4.19 kernel headers. 4179 "XSK_UNALIGNED_BUF_OFFSET_SHIFT" 4180 | "XSK_UNALIGNED_BUF_ADDR_MASK" 4181 | "XDP_UMEM_UNALIGNED_CHUNK_FLAG" 4182 | "XDP_RING_NEED_WAKEUP" 4183 | "XDP_USE_NEED_WAKEUP" 4184 if musl => 4185 { 4186 true 4187 } 4188 4189 // FIXME: Requires >= 6.6 kernel headers. 4190 "XDP_USE_SG" 4191 | "XDP_PKT_CONTD" 4192 => 4193 { 4194 true 4195 } 4196 4197 // FIXME: seems to not be available all the time (from <include/linux/sched.h>: 4198 "PF_VCPU" 4199 | "PF_IDLE" 4200 | "PF_EXITING" 4201 | "PF_POSTCOREDUMP" 4202 | "PF_IO_WORKER" 4203 | "PF_WQ_WORKER" 4204 | "PF_FORKNOEXEC" 4205 | "PF_MCE_PROCESS" 4206 | "PF_SUPERPRIV" 4207 | "PF_DUMPCORE" 4208 | "PF_SIGNALED" 4209 | "PF_MEMALLOC" 4210 | "PF_NPROC_EXCEEDED" 4211 | "PF_USED_MATH" 4212 | "PF_USER_WORKER" 4213 | "PF_NOFREEZE" 4214 | "PF_KSWAPD" 4215 | "PF_MEMALLOC_NOFS" 4216 | "PF_MEMALLOC_NOIO" 4217 | "PF_LOCAL_THROTTLE" 4218 | "PF_KTHREAD" 4219 | "PF_RANDOMIZE" 4220 | "PF_NO_SETAFFINITY" 4221 | "PF_MCE_EARLY" 4222 | "PF_MEMALLOC_PIN" => true, 4223 4224 "SCHED_FLAG_KEEP_POLICY" 4225 | "SCHED_FLAG_KEEP_PARAMS" 4226 | "SCHED_FLAG_UTIL_CLAMP_MIN" 4227 | "SCHED_FLAG_UTIL_CLAMP_MAX" 4228 | "SCHED_FLAG_KEEP_ALL" 4229 | "SCHED_FLAG_UTIL_CLAMP" 4230 | "SCHED_FLAG_ALL" if musl => true, // Needs more recent linux headers. 4231 4232 _ => false, 4233 } 4234 }); 4235 4236 cfg.skip_fn(move |name| { 4237 // skip those that are manually verified 4238 match name { 4239 // FIXME: https://github.com/rust-lang/libc/issues/1272 4240 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 4241 4242 // There are two versions of the sterror_r function, see 4243 // 4244 // https://linux.die.net/man/3/strerror_r 4245 // 4246 // An XSI-compliant version provided if: 4247 // 4248 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) 4249 // && ! _GNU_SOURCE 4250 // 4251 // and a GNU specific version provided if _GNU_SOURCE is defined. 4252 // 4253 // libc provides bindings for the XSI-compliant version, which is 4254 // preferred for portable applications. 4255 // 4256 // We skip the test here since here _GNU_SOURCE is defined, and 4257 // test the XSI version below. 4258 "strerror_r" => true, 4259 4260 // FIXME: Our API is unsound. The Rust API allows aliasing 4261 // pointers, but the C API requires pointers not to alias. 4262 // We should probably be at least using `&`/`&mut` here, see: 4263 // https://github.com/gnzlbg/ctest/issues/68 4264 "lio_listio" if musl => true, 4265 4266 // Needs glibc 2.34 or later. 4267 "posix_spawn_file_actions_addclosefrom_np" if gnu && sparc64 => true, 4268 // Needs glibc 2.35 or later. 4269 "posix_spawn_file_actions_addtcsetpgrp_np" if gnu && sparc64 => true, 4270 4271 // FIXME: Deprecated since glibc 2.30. Remove fn once upstream does. 4272 "sysctl" if gnu => true, 4273 4274 // FIXME: It now takes c_void instead of timezone since glibc 2.31. 4275 "gettimeofday" if gnu => true, 4276 4277 // These are all implemented as static inline functions in uclibc, so 4278 // they cannot be linked against. 4279 // If implementations are required, they might need to be implemented 4280 // in this crate. 4281 "posix_spawnattr_init" if uclibc => true, 4282 "posix_spawnattr_destroy" if uclibc => true, 4283 "posix_spawnattr_getsigdefault" if uclibc => true, 4284 "posix_spawnattr_setsigdefault" if uclibc => true, 4285 "posix_spawnattr_getsigmask" if uclibc => true, 4286 "posix_spawnattr_setsigmask" if uclibc => true, 4287 "posix_spawnattr_getflags" if uclibc => true, 4288 "posix_spawnattr_setflags" if uclibc => true, 4289 "posix_spawnattr_getpgroup" if uclibc => true, 4290 "posix_spawnattr_setpgroup" if uclibc => true, 4291 "posix_spawnattr_getschedpolicy" if uclibc => true, 4292 "posix_spawnattr_setschedpolicy" if uclibc => true, 4293 "posix_spawnattr_getschedparam" if uclibc => true, 4294 "posix_spawnattr_setschedparam" if uclibc => true, 4295 "posix_spawn_file_actions_init" if uclibc => true, 4296 "posix_spawn_file_actions_destroy" if uclibc => true, 4297 4298 // uclibc defines the flags type as a uint, but dependent crates 4299 // assume it's a int instead. 4300 "getnameinfo" if uclibc => true, 4301 4302 // FIXME: This needs musl 1.2.2 or later. 4303 "gettid" if musl => true, 4304 4305 // Needs glibc 2.33 or later. 4306 "mallinfo2" => true, 4307 4308 "reallocarray" if musl => true, 4309 4310 // Not defined in uclibc as of 1.0.34 4311 "gettid" if uclibc => true, 4312 4313 // Needs musl 1.2.3 or later. 4314 "pthread_getname_np" if musl => true, 4315 4316 // pthread_sigqueue uses sigval, which was initially declared 4317 // as a struct but should be defined as a union. However due 4318 // to the issues described here: https://github.com/rust-lang/libc/issues/2816 4319 // it can't be changed from struct. 4320 "pthread_sigqueue" => true, 4321 4322 // There are two versions of basename(3) on Linux with glibc, see 4323 // 4324 // https://man7.org/linux/man-pages/man3/basename.3.html 4325 // 4326 // If libgen.h is included, then the POSIX version will be available; 4327 // If _GNU_SOURCE is defined and string.h is included, then the GNU one 4328 // will be used. 4329 // 4330 // libc exposes both of them, providing a prefix to differentiate between 4331 // them. 4332 // 4333 // Because the name with prefix is not a valid symbol in C, we have to 4334 // skip the tests. 4335 "posix_basename" if gnu => true, 4336 "gnu_basename" if gnu => true, 4337 4338 // FIXME: function pointers changed since Ubuntu 23.10 4339 "strtol" | "strtoll" | "strtoul" | "strtoull" | "fscanf" | "scanf" | "sscanf" => true, 4340 4341 // Added in musl 1.2.5 4342 "preadv2" | "pwritev2" if musl => true, 4343 4344 _ => false, 4345 } 4346 }); 4347 4348 cfg.skip_field_type(move |struct_, field| { 4349 // This is a weird union, don't check the type. 4350 (struct_ == "ifaddrs" && field == "ifa_ifu") || 4351 // sighandler_t type is super weird 4352 (struct_ == "sigaction" && field == "sa_sigaction") || 4353 // __timeval type is a patch which doesn't exist in glibc 4354 (struct_ == "utmpx" && field == "ut_tv") || 4355 // sigval is actually a union, but we pretend it's a struct 4356 (struct_ == "sigevent" && field == "sigev_value") || 4357 // this one is an anonymous union 4358 (struct_ == "ff_effect" && field == "u") || 4359 // `__exit_status` type is a patch which is absent in musl 4360 (struct_ == "utmpx" && field == "ut_exit" && musl) || 4361 // `can_addr` is an anonymous union 4362 (struct_ == "sockaddr_can" && field == "can_addr") 4363 }); 4364 4365 cfg.volatile_item(|i| { 4366 use ctest::VolatileItemKind::*; 4367 match i { 4368 // aio_buf is a volatile void** but since we cannot express that in 4369 // Rust types, we have to explicitly tell the checker about it here: 4370 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 4371 _ => false, 4372 } 4373 }); 4374 4375 cfg.skip_field(move |struct_, field| { 4376 // this is actually a union on linux, so we can't represent it well and 4377 // just insert some padding. 4378 (struct_ == "siginfo_t" && field == "_pad") || 4379 // musl names this __dummy1 but it's still there 4380 (musl && struct_ == "glob_t" && field == "gl_flags") || 4381 // musl seems to define this as an *anonymous* bitfield 4382 (musl && struct_ == "statvfs" && field == "__f_unused") || 4383 // sigev_notify_thread_id is actually part of a sigev_un union 4384 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 4385 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release 4386 // has them yet. 4387 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 4388 field == "_pad2" || 4389 field == "ssi_syscall" || 4390 field == "ssi_call_addr" || 4391 field == "ssi_arch")) || 4392 // FIXME: After musl 1.1.24, it have only one field `sched_priority`, 4393 // while other fields become reserved. 4394 (struct_ == "sched_param" && [ 4395 "sched_ss_low_priority", 4396 "sched_ss_repl_period", 4397 "sched_ss_init_budget", 4398 "sched_ss_max_repl", 4399 ].contains(&field) && musl) || 4400 // FIXME: After musl 1.1.24, the type becomes `int` instead of `unsigned short`. 4401 (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) || 4402 // glibc uses unnamed fields here and Rust doesn't support that yet 4403 (struct_ == "timex" && field.starts_with("__unused")) || 4404 // FIXME: It now takes mode_t since glibc 2.31 on some targets. 4405 (struct_ == "ipc_perm" && field == "mode" 4406 && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32) 4407 ) || 4408 // the `u` field is in fact an anonymous union 4409 (gnu && struct_ == "ptrace_syscall_info" && (field == "u" || field == "pad")) || 4410 // the vregs field is a `__uint128_t` C's type. 4411 (struct_ == "user_fpsimd_struct" && field == "vregs") || 4412 // Linux >= 5.11 tweaked the `svm_zero` field of the `sockaddr_vm` struct. 4413 // https://github.com/torvalds/linux/commit/dc8eeef73b63ed8988224ba6b5ed19a615163a7f 4414 (struct_ == "sockaddr_vm" && field == "svm_zero") || 4415 // the `ifr_ifru` field is an anonymous union 4416 (struct_ == "ifreq" && field == "ifr_ifru") || 4417 // the `ifc_ifcu` field is an anonymous union 4418 (struct_ == "ifconf" && field == "ifc_ifcu") || 4419 // glibc uses a single array `uregs` instead of individual fields. 4420 (struct_ == "user_regs" && arm) 4421 }); 4422 4423 cfg.skip_roundtrip(move |s| match s { 4424 // FIXME: 4425 "mcontext_t" if s390x => true, 4426 // FIXME: This is actually a union. 4427 "fpreg_t" if s390x => true, 4428 4429 // The test doesn't work on some env: 4430 "ipv6_mreq" 4431 | "ip_mreq_source" 4432 | "sockaddr_in6" 4433 | "sockaddr_ll" 4434 | "in_pktinfo" 4435 | "arpreq" 4436 | "arpreq_old" 4437 | "sockaddr_un" 4438 | "ff_constant_effect" 4439 | "ff_ramp_effect" 4440 | "ff_condition_effect" 4441 | "Elf32_Ehdr" 4442 | "Elf32_Chdr" 4443 | "ucred" 4444 | "in6_pktinfo" 4445 | "sockaddr_nl" 4446 | "termios" 4447 | "nlmsgerr" 4448 if sparc64 && gnu => 4449 { 4450 true 4451 } 4452 4453 // The `inotify_event` and `cmsghdr` types contain Flexible Array Member fields (the 4454 // `name` and `data` fields respectively) which have unspecified calling convention. 4455 // The roundtripping tests deliberately pass the structs by value to check "by value" 4456 // layout consistency, but this would be UB for the these types. 4457 "inotify_event" => true, 4458 "cmsghdr" => true, 4459 4460 // FIXME: the call ABI of max_align_t is incorrect on these platforms: 4461 "max_align_t" if i686 || ppc64 => true, 4462 4463 _ => false, 4464 }); 4465 4466 cfg.generate("../src/lib.rs", "main.rs"); 4467 4468 test_linux_like_apis(target); 4469 } 4470 4471 // This function tests APIs that are incompatible to test when other APIs 4472 // are included (e.g. because including both sets of headers clashes) 4473 fn test_linux_like_apis(target: &str) { 4474 let gnu = target.contains("gnu"); 4475 let musl = target.contains("musl") || target.contains("ohos"); 4476 let linux = target.contains("linux"); 4477 let emscripten = target.contains("emscripten"); 4478 let android = target.contains("android"); 4479 assert!(linux || android || emscripten); 4480 4481 if linux || android || emscripten { 4482 // test strerror_r from the `string.h` header 4483 let mut cfg = ctest_cfg(); 4484 cfg.skip_type(|_| true).skip_static(|_| true); 4485 4486 headers! { cfg: "string.h" } 4487 cfg.skip_fn(|f| match f { 4488 "strerror_r" => false, 4489 _ => true, 4490 }) 4491 .skip_const(|_| true) 4492 .skip_struct(|_| true); 4493 cfg.generate("../src/lib.rs", "linux_strerror_r.rs"); 4494 } 4495 4496 if linux || android || emscripten { 4497 // test fcntl - see: 4498 // http://man7.org/linux/man-pages/man2/fcntl.2.html 4499 let mut cfg = ctest_cfg(); 4500 4501 if musl { 4502 cfg.header("fcntl.h"); 4503 } else { 4504 cfg.header("linux/fcntl.h"); 4505 } 4506 4507 cfg.skip_type(|_| true) 4508 .skip_static(|_| true) 4509 .skip_struct(|_| true) 4510 .skip_fn(|_| true) 4511 .skip_const(move |name| match name { 4512 // test fcntl constants: 4513 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" 4514 | "F_SEAL_GROW" | "F_SEAL_WRITE" => false, 4515 _ => true, 4516 }) 4517 .type_name(move |ty, is_struct, is_union| match ty { 4518 t if is_struct => format!("struct {}", t), 4519 t if is_union => format!("union {}", t), 4520 t => t.to_string(), 4521 }); 4522 4523 cfg.generate("../src/lib.rs", "linux_fcntl.rs"); 4524 } 4525 4526 if linux || android { 4527 // test termios 4528 let mut cfg = ctest_cfg(); 4529 cfg.header("asm/termbits.h"); 4530 cfg.header("linux/termios.h"); 4531 cfg.skip_type(|_| true) 4532 .skip_static(|_| true) 4533 .skip_fn(|_| true) 4534 .skip_const(|c| match c { 4535 "BOTHER" | "IBSHIFT" => false, 4536 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => false, 4537 _ => true, 4538 }) 4539 .skip_struct(|s| s != "termios2") 4540 .type_name(move |ty, is_struct, is_union| match ty { 4541 "Ioctl" if gnu => "unsigned long".to_string(), 4542 "Ioctl" => "int".to_string(), 4543 t if is_struct => format!("struct {}", t), 4544 t if is_union => format!("union {}", t), 4545 t => t.to_string(), 4546 }); 4547 cfg.generate("../src/lib.rs", "linux_termios.rs"); 4548 } 4549 4550 if linux || android { 4551 // test IPV6_ constants: 4552 let mut cfg = ctest_cfg(); 4553 headers! { 4554 cfg: 4555 "linux/in6.h" 4556 } 4557 cfg.skip_type(|_| true) 4558 .skip_static(|_| true) 4559 .skip_fn(|_| true) 4560 .skip_const(|_| true) 4561 .skip_struct(|_| true) 4562 .skip_const(move |name| match name { 4563 "IPV6_FLOWINFO" 4564 | "IPV6_FLOWLABEL_MGR" 4565 | "IPV6_FLOWINFO_SEND" 4566 | "IPV6_FLOWINFO_FLOWLABEL" 4567 | "IPV6_FLOWINFO_PRIORITY" => false, 4568 _ => true, 4569 }) 4570 .type_name(move |ty, is_struct, is_union| match ty { 4571 t if is_struct => format!("struct {}", t), 4572 t if is_union => format!("union {}", t), 4573 t => t.to_string(), 4574 }); 4575 cfg.generate("../src/lib.rs", "linux_ipv6.rs"); 4576 } 4577 4578 if linux || android { 4579 // Test Elf64_Phdr and Elf32_Phdr 4580 // These types have a field called `p_type`, but including 4581 // "resolve.h" defines a `p_type` macro that expands to `__p_type` 4582 // making the tests for these fails when both are included. 4583 let mut cfg = ctest_cfg(); 4584 cfg.header("elf.h"); 4585 cfg.skip_fn(|_| true) 4586 .skip_static(|_| true) 4587 .skip_const(|_| true) 4588 .type_name(move |ty, _is_struct, _is_union| ty.to_string()) 4589 .skip_struct(move |ty| match ty { 4590 "Elf64_Phdr" | "Elf32_Phdr" => false, 4591 _ => true, 4592 }) 4593 .skip_type(move |ty| match ty { 4594 "Elf64_Phdr" | "Elf32_Phdr" => false, 4595 _ => true, 4596 }); 4597 cfg.generate("../src/lib.rs", "linux_elf.rs"); 4598 } 4599 4600 if linux || android { 4601 // Test `ARPHRD_CAN`. 4602 let mut cfg = ctest_cfg(); 4603 cfg.header("linux/if_arp.h"); 4604 cfg.skip_fn(|_| true) 4605 .skip_static(|_| true) 4606 .skip_const(move |name| match name { 4607 "ARPHRD_CAN" => false, 4608 _ => true, 4609 }) 4610 .skip_struct(|_| true) 4611 .skip_type(|_| true); 4612 cfg.generate("../src/lib.rs", "linux_if_arp.rs"); 4613 } 4614 } 4615 4616 fn which_freebsd() -> Option<i32> { 4617 let output = std::process::Command::new("freebsd-version") 4618 .output() 4619 .ok()?; 4620 if !output.status.success() { 4621 return None; 4622 } 4623 4624 let stdout = String::from_utf8(output.stdout).ok()?; 4625 4626 match &stdout { 4627 s if s.starts_with("10") => Some(10), 4628 s if s.starts_with("11") => Some(11), 4629 s if s.starts_with("12") => Some(12), 4630 s if s.starts_with("13") => Some(13), 4631 s if s.starts_with("14") => Some(14), 4632 s if s.starts_with("15") => Some(15), 4633 _ => None, 4634 } 4635 } 4636 4637 fn test_haiku(target: &str) { 4638 assert!(target.contains("haiku")); 4639 4640 let mut cfg = ctest_cfg(); 4641 cfg.flag("-Wno-deprecated-declarations"); 4642 cfg.define("__USE_GNU", Some("1")); 4643 cfg.define("_GNU_SOURCE", None); 4644 cfg.language(ctest::Lang::CXX); 4645 4646 // POSIX API 4647 headers! { cfg: 4648 "alloca.h", 4649 "arpa/inet.h", 4650 "arpa/nameser.h", 4651 "arpa/nameser_compat.h", 4652 "assert.h", 4653 "complex.h", 4654 "ctype.h", 4655 "dirent.h", 4656 "div_t.h", 4657 "dlfcn.h", 4658 "endian.h", 4659 "errno.h", 4660 "fcntl.h", 4661 "fenv.h", 4662 "fnmatch.h", 4663 "fts.h", 4664 "ftw.h", 4665 "getopt.h", 4666 "glob.h", 4667 "grp.h", 4668 "inttypes.h", 4669 "iovec.h", 4670 "langinfo.h", 4671 "libgen.h", 4672 "libio.h", 4673 "limits.h", 4674 "locale.h", 4675 "malloc.h", 4676 "malloc_debug.h", 4677 "math.h", 4678 "memory.h", 4679 "monetary.h", 4680 "net/if.h", 4681 "net/if_dl.h", 4682 "net/if_media.h", 4683 "net/if_tun.h", 4684 "net/if_types.h", 4685 "net/route.h", 4686 "netdb.h", 4687 "netinet/in.h", 4688 "netinet/ip.h", 4689 "netinet/ip6.h", 4690 "netinet/ip_icmp.h", 4691 "netinet/ip_var.h", 4692 "netinet/tcp.h", 4693 "netinet/udp.h", 4694 "netinet6/in6.h", 4695 "nl_types.h", 4696 "null.h", 4697 "poll.h", 4698 "pthread.h", 4699 "pwd.h", 4700 "regex.h", 4701 "resolv.h", 4702 "sched.h", 4703 "search.h", 4704 "semaphore.h", 4705 "setjmp.h", 4706 "shadow.h", 4707 "signal.h", 4708 "size_t.h", 4709 "spawn.h", 4710 "stdint.h", 4711 "stdio.h", 4712 "stdlib.h", 4713 "string.h", 4714 "strings.h", 4715 "sys/cdefs.h", 4716 "sys/file.h", 4717 "sys/ioctl.h", 4718 "sys/ipc.h", 4719 "sys/mman.h", 4720 "sys/msg.h", 4721 "sys/param.h", 4722 "sys/poll.h", 4723 "sys/resource.h", 4724 "sys/select.h", 4725 "sys/sem.h", 4726 "sys/socket.h", 4727 "sys/sockio.h", 4728 "sys/stat.h", 4729 "sys/statvfs.h", 4730 "sys/time.h", 4731 "sys/timeb.h", 4732 "sys/times.h", 4733 "sys/types.h", 4734 "sys/uio.h", 4735 "sys/un.h", 4736 "sys/utsname.h", 4737 "sys/wait.h", 4738 "syslog.h", 4739 "tar.h", 4740 "termios.h", 4741 "time.h", 4742 "uchar.h", 4743 "unistd.h", 4744 "utime.h", 4745 "utmpx.h", 4746 "wchar.h", 4747 "wchar_t.h", 4748 "wctype.h" 4749 } 4750 4751 // BSD Extensions 4752 headers! { cfg: 4753 "ifaddrs.h", 4754 "libutil.h", 4755 "link.h", 4756 "pty.h", 4757 "stringlist.h", 4758 "sys/link_elf.h", 4759 } 4760 4761 // Native API 4762 headers! { cfg: 4763 "kernel/OS.h", 4764 "kernel/fs_attr.h", 4765 "kernel/fs_index.h", 4766 "kernel/fs_info.h", 4767 "kernel/fs_query.h", 4768 "kernel/fs_volume.h", 4769 "kernel/image.h", 4770 "kernel/scheduler.h", 4771 "storage/FindDirectory.h", 4772 "storage/StorageDefs.h", 4773 "support/Errors.h", 4774 "support/SupportDefs.h", 4775 "support/TypeConstants.h" 4776 } 4777 4778 cfg.skip_struct(move |ty| { 4779 if ty.starts_with("__c_anonymous_") { 4780 return true; 4781 } 4782 match ty { 4783 // FIXME: actually a union 4784 "sigval" => true, 4785 // FIXME: locale_t does not exist on Haiku 4786 "locale_t" => true, 4787 // FIXME: rusage has a different layout on Haiku 4788 "rusage" => true, 4789 // FIXME?: complains that rust aligns on 4 byte boundary, but 4790 // Haiku does not align it at all. 4791 "in6_addr" => true, 4792 // The d_name attribute is an array of 1 on Haiku, with the 4793 // intention that the developer allocates a larger or smaller 4794 // piece of memory depending on the expected/actual size of the name. 4795 // Other platforms have sensible defaults. In Rust, the d_name field 4796 // is sized as the _POSIX_MAX_PATH, so that path names will fit in 4797 // newly allocated dirent objects. This breaks the automated tests. 4798 "dirent" => true, 4799 // The following structs contain function pointers, which cannot be initialized 4800 // with mem::zeroed(), so skip the automated test 4801 "image_info" | "thread_info" => true, 4802 4803 "Elf64_Phdr" => true, 4804 4805 // is an union 4806 "cpuid_info" => true, 4807 4808 _ => false, 4809 } 4810 }); 4811 4812 cfg.skip_type(move |ty| { 4813 match ty { 4814 // FIXME: locale_t does not exist on Haiku 4815 "locale_t" => true, 4816 // These cause errors, to be reviewed in the future 4817 "sighandler_t" => true, 4818 "pthread_t" => true, 4819 "pthread_condattr_t" => true, 4820 "pthread_mutexattr_t" => true, 4821 "pthread_rwlockattr_t" => true, 4822 _ => false, 4823 } 4824 }); 4825 4826 cfg.skip_fn(move |name| { 4827 // skip those that are manually verified 4828 match name { 4829 // FIXME: https://github.com/rust-lang/libc/issues/1272 4830 "execv" | "execve" | "execvp" | "execvpe" => true, 4831 // FIXME: does not exist on haiku 4832 "open_wmemstream" => true, 4833 "mlockall" | "munlockall" => true, 4834 "tcgetsid" => true, 4835 "cfsetspeed" => true, 4836 // ignore for now, will be part of Haiku R1 beta 3 4837 "mlock" | "munlock" => true, 4838 // returns const char * on Haiku 4839 "strsignal" => true, 4840 // uses an enum as a parameter argument, which is incorrectly 4841 // translated into a struct argument 4842 "find_path" => true, 4843 4844 "get_cpuid" => true, 4845 4846 // uses varargs parameter 4847 "ioctl" => true, 4848 4849 _ => false, 4850 } 4851 }); 4852 4853 cfg.skip_const(move |name| { 4854 match name { 4855 // FIXME: these constants do not exist on Haiku 4856 "DT_UNKNOWN" | "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" 4857 | "DT_SOCK" => true, 4858 "USRQUOTA" | "GRPQUOTA" => true, 4859 "SIGIOT" => true, 4860 "ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM" | "ATF_PUBL" 4861 | "ATF_USETRAILERS" => true, 4862 // Haiku does not have MAP_FILE, but rustc requires it 4863 "MAP_FILE" => true, 4864 // The following does not exist on Haiku but is required by 4865 // several crates 4866 "FIOCLEX" => true, 4867 // just skip this one, it is not defined on Haiku beta 2 but 4868 // since it is meant as a mask and not a parameter it can exist 4869 // here 4870 "LOG_PRIMASK" => true, 4871 // not defined on Haiku, but [get|set]priority is, so they are 4872 // useful 4873 "PRIO_MIN" | "PRIO_MAX" => true, 4874 // 4875 _ => false, 4876 } 4877 }); 4878 4879 cfg.skip_field(move |struct_, field| { 4880 match (struct_, field) { 4881 // FIXME: the stat struct actually has timespec members, whereas 4882 // the current representation has these unpacked. 4883 ("stat", "st_atime") => true, 4884 ("stat", "st_atime_nsec") => true, 4885 ("stat", "st_mtime") => true, 4886 ("stat", "st_mtime_nsec") => true, 4887 ("stat", "st_ctime") => true, 4888 ("stat", "st_ctime_nsec") => true, 4889 ("stat", "st_crtime") => true, 4890 ("stat", "st_crtime_nsec") => true, 4891 4892 // these are actually unions, but we cannot represent it well 4893 ("siginfo_t", "sigval") => true, 4894 ("sem_t", "named_sem_id") => true, 4895 ("sigaction", "sa_sigaction") => true, 4896 ("sigevent", "sigev_value") => true, 4897 ("fpu_state", "_fpreg") => true, 4898 ("cpu_topology_node_info", "data") => true, 4899 // these fields have a simplified data definition in libc 4900 ("fpu_state", "_xmm") => true, 4901 ("savefpu", "_fp_ymm") => true, 4902 4903 // skip these enum-type fields 4904 ("thread_info", "state") => true, 4905 ("image_info", "image_type") => true, 4906 _ => false, 4907 } 4908 }); 4909 4910 cfg.skip_roundtrip(move |s| match s { 4911 // FIXME: for some reason the roundtrip check fails for cpu_info 4912 "cpu_info" => true, 4913 _ => false, 4914 }); 4915 4916 cfg.type_name(move |ty, is_struct, is_union| { 4917 match ty { 4918 // Just pass all these through, no need for a "struct" prefix 4919 "area_info" 4920 | "port_info" 4921 | "port_message_info" 4922 | "team_info" 4923 | "sem_info" 4924 | "team_usage_info" 4925 | "thread_info" 4926 | "cpu_info" 4927 | "system_info" 4928 | "object_wait_info" 4929 | "image_info" 4930 | "attr_info" 4931 | "index_info" 4932 | "fs_info" 4933 | "FILE" 4934 | "DIR" 4935 | "Dl_info" 4936 | "topology_level_type" 4937 | "cpu_topology_node_info" 4938 | "cpu_topology_root_info" 4939 | "cpu_topology_package_info" 4940 | "cpu_topology_core_info" => ty.to_string(), 4941 4942 // enums don't need a prefix 4943 "directory_which" | "path_base_directory" | "cpu_platform" | "cpu_vendor" => { 4944 ty.to_string() 4945 } 4946 4947 // is actually a union 4948 "sigval" => format!("union sigval"), 4949 t if is_union => format!("union {}", t), 4950 t if t.ends_with("_t") => t.to_string(), 4951 t if is_struct => format!("struct {}", t), 4952 t => t.to_string(), 4953 } 4954 }); 4955 4956 cfg.field_name(move |struct_, field| { 4957 match field { 4958 // Field is named `type` in C but that is a Rust keyword, 4959 // so these fields are translated to `type_` in the bindings. 4960 "type_" if struct_ == "object_wait_info" => "type".to_string(), 4961 "type_" if struct_ == "sem_t" => "type".to_string(), 4962 "type_" if struct_ == "attr_info" => "type".to_string(), 4963 "type_" if struct_ == "index_info" => "type".to_string(), 4964 "type_" if struct_ == "cpu_topology_node_info" => "type".to_string(), 4965 "image_type" if struct_ == "image_info" => "type".to_string(), 4966 s => s.to_string(), 4967 } 4968 }); 4969 cfg.generate("../src/lib.rs", "main.rs"); 4970 } 4971