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