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