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