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