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