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