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