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 _ => false, 1823 } 1824 }); 1825 1826 cfg.skip_field_type(move |struct_, field| { 1827 // This is a weird union, don't check the type. 1828 (struct_ == "ifaddrs" && field == "ifa_ifu") || 1829 // sigval is actually a union, but we pretend it's a struct 1830 (struct_ == "sigevent" && field == "sigev_value") || 1831 // this one is an anonymous union 1832 (struct_ == "ff_effect" && field == "u") || 1833 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 1834 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 1835 (struct_ == "sigaction" && field == "sa_sigaction") || 1836 // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet. 1837 (struct_ == "signalfd_siginfo" && field == "ssi_call_addr") 1838 }); 1839 1840 cfg.skip_field(move |struct_, field| { 1841 // this is actually a union on linux, so we can't represent it well and 1842 // just insert some padding. 1843 (struct_ == "siginfo_t" && field == "_pad") || 1844 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 1845 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 1846 (struct_ == "sigaction" && field == "sa_sigaction") || 1847 // sigev_notify_thread_id is actually part of a sigev_un union 1848 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 1849 // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet. 1850 (struct_ == "signalfd_siginfo" && (field == "ssi_syscall" || 1851 field == "ssi_call_addr" || 1852 field == "ssi_arch")) 1853 }); 1854 1855 cfg.skip_field(|struct_, field| { 1856 match (struct_, field) { 1857 // conflicting with `p_type` macro from <resolve.h>. 1858 ("Elf32_Phdr", "p_type") => true, 1859 ("Elf64_Phdr", "p_type") => true, 1860 1861 // this is actually a union on linux, so we can't represent it well and 1862 // just insert some padding. 1863 ("siginfo_t", "_pad") => true, 1864 1865 _ => false, 1866 } 1867 }); 1868 1869 cfg.generate("../src/lib.rs", "main.rs"); 1870 1871 test_linux_like_apis(target); 1872 } 1873 1874 fn test_freebsd(target: &str) { 1875 assert!(target.contains("freebsd")); 1876 let mut cfg = ctest_cfg(); 1877 1878 let freebsd_ver = which_freebsd(); 1879 1880 match freebsd_ver { 1881 Some(12) => cfg.cfg("freebsd12", None), 1882 Some(13) => cfg.cfg("freebsd13", None), 1883 Some(14) => cfg.cfg("freebsd14", None), 1884 _ => &mut cfg, 1885 }; 1886 1887 // For sched linux compat fn 1888 cfg.define("_WITH_CPU_SET_T", None); 1889 // Required for `getline`: 1890 cfg.define("_WITH_GETLINE", None); 1891 // Required for making freebsd11_stat available in the headers 1892 cfg.define("_WANT_FREEBSD11_STAT", None); 1893 1894 let freebsd13 = match freebsd_ver { 1895 Some(n) if n >= 13 => true, 1896 _ => false, 1897 }; 1898 1899 headers! { cfg: 1900 "aio.h", 1901 "arpa/inet.h", 1902 "bsm/audit.h", 1903 "ctype.h", 1904 "dirent.h", 1905 "dlfcn.h", 1906 "elf.h", 1907 "errno.h", 1908 "execinfo.h", 1909 "fcntl.h", 1910 "getopt.h", 1911 "glob.h", 1912 "grp.h", 1913 "iconv.h", 1914 "ifaddrs.h", 1915 "langinfo.h", 1916 "libgen.h", 1917 "libutil.h", 1918 "limits.h", 1919 "link.h", 1920 "locale.h", 1921 "machine/elf.h", 1922 "machine/reg.h", 1923 "malloc_np.h", 1924 "memstat.h", 1925 "mqueue.h", 1926 "net/bpf.h", 1927 "net/if.h", 1928 "net/if_arp.h", 1929 "net/if_dl.h", 1930 "net/if_mib.h", 1931 "net/route.h", 1932 "netdb.h", 1933 "netinet/ip.h", 1934 "netinet/in.h", 1935 "netinet/tcp.h", 1936 "netinet/udp.h", 1937 "poll.h", 1938 "pthread.h", 1939 "pthread_np.h", 1940 "pwd.h", 1941 "regex.h", 1942 "resolv.h", 1943 "sched.h", 1944 "semaphore.h", 1945 "signal.h", 1946 "spawn.h", 1947 "stddef.h", 1948 "stdint.h", 1949 "stdio.h", 1950 "stdlib.h", 1951 "string.h", 1952 "sys/capsicum.h", 1953 "sys/auxv.h", 1954 "sys/cpuset.h", 1955 "sys/domainset.h", 1956 "sys/eui64.h", 1957 "sys/event.h", 1958 [freebsd13]:"sys/eventfd.h", 1959 "sys/extattr.h", 1960 "sys/file.h", 1961 "sys/ioctl.h", 1962 "sys/ipc.h", 1963 "sys/jail.h", 1964 "sys/mman.h", 1965 "sys/mount.h", 1966 "sys/msg.h", 1967 "sys/procctl.h", 1968 "sys/procdesc.h", 1969 "sys/ptrace.h", 1970 "sys/queue.h", 1971 "sys/random.h", 1972 "sys/resource.h", 1973 "sys/rtprio.h", 1974 "sys/sem.h", 1975 "sys/shm.h", 1976 "sys/socket.h", 1977 "sys/stat.h", 1978 "sys/statvfs.h", 1979 "sys/sysctl.h", 1980 "sys/thr.h", 1981 "sys/time.h", 1982 "sys/times.h", 1983 "sys/timex.h", 1984 "sys/types.h", 1985 "sys/proc.h", 1986 "kvm.h", // must be after "sys/types.h" 1987 "sys/ucontext.h", 1988 "sys/uio.h", 1989 "sys/ktrace.h", 1990 "sys/umtx.h", 1991 "sys/un.h", 1992 "sys/user.h", 1993 "sys/utsname.h", 1994 "sys/uuid.h", 1995 "sys/vmmeter.h", 1996 "sys/wait.h", 1997 "libprocstat.h", 1998 "devstat.h", 1999 "syslog.h", 2000 "termios.h", 2001 "time.h", 2002 "ufs/ufs/quota.h", 2003 "unistd.h", 2004 "utime.h", 2005 "utmpx.h", 2006 "wchar.h", 2007 } 2008 2009 cfg.type_name(move |ty, is_struct, is_union| { 2010 match ty { 2011 // Just pass all these through, no need for a "struct" prefix 2012 "FILE" 2013 | "fd_set" 2014 | "Dl_info" 2015 | "DIR" 2016 | "Elf32_Phdr" 2017 | "Elf64_Phdr" 2018 | "Elf32_Auxinfo" 2019 | "Elf64_Auxinfo" 2020 | "devstat_select_mode" 2021 | "devstat_support_flags" 2022 | "devstat_type_flags" 2023 | "devstat_match_flags" 2024 | "devstat_priority" => ty.to_string(), 2025 2026 // FIXME: https://github.com/rust-lang/libc/issues/1273 2027 "sighandler_t" => "sig_t".to_string(), 2028 2029 t if is_union => format!("union {}", t), 2030 2031 t if t.ends_with("_t") => t.to_string(), 2032 2033 // sigval is a struct in Rust, but a union in C: 2034 "sigval" => format!("union sigval"), 2035 2036 // put `struct` in front of all structs:. 2037 t if is_struct => format!("struct {}", t), 2038 2039 t => t.to_string(), 2040 } 2041 }); 2042 2043 cfg.field_name(move |struct_, field| { 2044 match field { 2045 // Our stat *_nsec fields normally don't actually exist but are part 2046 // of a timeval struct 2047 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2048 s.replace("e_nsec", ".tv_nsec") 2049 } 2050 // Field is named `type` in C but that is a Rust keyword, 2051 // so these fields are translated to `type_` in the bindings. 2052 "type_" if struct_ == "rtprio" => "type".to_string(), 2053 "type_" if struct_ == "sockstat" => "type".to_string(), 2054 "type_" if struct_ == "devstat_match_table" => "type".to_string(), 2055 s => s.to_string(), 2056 } 2057 }); 2058 2059 cfg.skip_const(move |name| { 2060 match name { 2061 // These constants were introduced in FreeBSD 13: 2062 "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" 2063 | "F_SEAL_WRITE" 2064 if Some(13) > freebsd_ver => 2065 { 2066 true 2067 } 2068 2069 // These constants were introduced in FreeBSD 13: 2070 "EFD_CLOEXEC" | "EFD_NONBLOCK" | "EFD_SEMAPHORE" if Some(13) > freebsd_ver => true, 2071 2072 // FIXME: These are deprecated - remove in a couple of releases. 2073 // These constants were removed in FreeBSD 11 (svn r273250) but will 2074 // still be accepted and ignored at runtime. 2075 "MAP_RENAME" | "MAP_NORESERVE" => true, 2076 2077 // FIXME: These are deprecated - remove in a couple of releases. 2078 // These constants were removed in FreeBSD 11 (svn r262489), 2079 // and they've never had any legitimate use outside of the 2080 // base system anyway. 2081 "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "USER_MAXID" => true, 2082 2083 // FIXME: This is deprecated - remove in a couple of releases. 2084 // This was removed in FreeBSD 14 (git 1b4701fe1e8) and never 2085 // should've been used anywhere anyway. 2086 "TDF_UNUSED23" => true, 2087 2088 // FIXME: These are deprecated - remove in a couple of releases. 2089 // These symbols are not stable across OS-versions. They were 2090 // changed for FreeBSD 14 in git revisions b62848b0c3f and 2091 // 2cf7870864e. 2092 "PRI_MAX_ITHD" | "PRI_MIN_REALTIME" | "PRI_MAX_REALTIME" | "PRI_MIN_KERN" 2093 | "PRI_MAX_KERN" | "PSWP" | "PVM" | "PINOD" | "PRIBIO" | "PVFS" | "PZERO" | "PSOCK" 2094 | "PWAIT" | "PLOCK" | "PPAUSE" | "PRI_MIN_TIMESHARE" | "PUSER" | "PI_AV" | "PI_NET" 2095 | "PI_DISK" | "PI_TTY" | "PI_DULL" | "PI_SOFT" => true, 2096 2097 // This symbol changed in FreeBSD 14 (git 051e7d78b03), but the new 2098 // version should be safe to use on older releases. 2099 "IFCAP_CANTCHANGE" => true, 2100 2101 // These were removed in FreeBSD 14 (git c6d31b8306e) 2102 "TDF_ASTPENDING" | "TDF_NEEDSUSPCHK" | "TDF_NEEDRESCHED" | "TDF_NEEDSIGCHK" 2103 | "TDF_ALRMPEND" | "TDF_PROFPEND" | "TDF_MACPEND" => true, 2104 2105 // This constant was removed in FreeBSD 13 (svn r363622), and never 2106 // had any legitimate use outside of the base system anyway. 2107 "CTL_P1003_1B_MAXID" => true, 2108 2109 // This was renamed in FreeBSD 12.2 and 13 (r352486). 2110 "CTL_UNSPEC" | "CTL_SYSCTL" => true, 2111 2112 // This was renamed in FreeBSD 12.2 and 13 (r350749). 2113 "IPPROTO_SEP" | "IPPROTO_DCCP" => true, 2114 2115 // This was changed to 96(0x60) in FreeBSD 13: 2116 // https://github.com/freebsd/freebsd/ 2117 // commit/06b00ceaa914a3907e4e27bad924f44612bae1d7 2118 "MINCORE_SUPER" if Some(13) <= freebsd_ver => true, 2119 2120 // Added in FreeBSD 13.0 (r356667) 2121 "GRND_INSECURE" if Some(13) > freebsd_ver => true, 2122 2123 // Added in FreeBSD 13.0 (r349609) 2124 "PROC_PROTMAX_CTL" 2125 | "PROC_PROTMAX_STATUS" 2126 | "PROC_PROTMAX_FORCE_ENABLE" 2127 | "PROC_PROTMAX_FORCE_DISABLE" 2128 | "PROC_PROTMAX_NOFORCE" 2129 | "PROC_PROTMAX_ACTIVE" 2130 | "PROC_NO_NEW_PRIVS_CTL" 2131 | "PROC_NO_NEW_PRIVS_STATUS" 2132 | "PROC_NO_NEW_PRIVS_ENABLE" 2133 | "PROC_NO_NEW_PRIVS_DISABLE" 2134 | "PROC_WXMAP_CTL" 2135 | "PROC_WXMAP_STATUS" 2136 | "PROC_WX_MAPPINGS_PERMIT" 2137 | "PROC_WX_MAPPINGS_DISALLOW_EXEC" 2138 | "PROC_WXORX_ENFORCE" 2139 if Some(13) > freebsd_ver => 2140 { 2141 true 2142 } 2143 2144 // Added in in FreeBSD 13.0 (r367776 and r367287) 2145 "SCM_CREDS2" | "LOCAL_CREDS_PERSISTENT" if Some(13) > freebsd_ver => true, 2146 2147 // Added in FreeBSD 14 2148 "SPACECTL_DEALLOC" if Some(14) > freebsd_ver => true, 2149 2150 // Added in FreeBSD 13. 2151 "KERN_PROC_SIGFASTBLK" 2152 | "USER_LOCALBASE" 2153 | "TDP_SIGFASTBLOCK" 2154 | "TDP_UIOHELD" 2155 | "TDP_SIGFASTPENDING" 2156 | "TDP2_COMPAT32RB" 2157 | "P2_PROTMAX_ENABLE" 2158 | "P2_PROTMAX_DISABLE" 2159 | "CTLFLAG_NEEDGIANT" 2160 | "CTL_SYSCTL_NEXTNOSKIP" 2161 if Some(13) > freebsd_ver => 2162 { 2163 true 2164 } 2165 2166 // Added in freebsd 14. 2167 "IFCAP_MEXTPG" if Some(14) > freebsd_ver => true, 2168 // Added in freebsd 13. 2169 "IFF_KNOWSEPOCH" | "IFCAP_TXTLS4" | "IFCAP_TXTLS6" | "IFCAP_VXLAN_HWCSUM" 2170 | "IFCAP_VXLAN_HWTSO" | "IFCAP_TXTLS_RTLMT" | "IFCAP_TXTLS" 2171 if Some(13) > freebsd_ver => 2172 { 2173 true 2174 } 2175 // Added in FreeBSD 13. 2176 "PS_FST_TYPE_EVENTFD" if Some(13) > freebsd_ver => true, 2177 2178 // Added in FreeBSD 14. 2179 "MNT_RECURSE" | "MNT_DEFERRED" if Some(14) > freebsd_ver => true, 2180 2181 // Added in FreeBSD 13. 2182 "MNT_EXTLS" | "MNT_EXTLSCERT" | "MNT_EXTLSCERTUSER" | "MNT_NOCOVER" 2183 | "MNT_EMPTYDIR" 2184 if Some(13) > freebsd_ver => 2185 { 2186 true 2187 } 2188 2189 // Added in FreeBSD 14. 2190 "PT_COREDUMP" | "PC_ALL" | "PC_COMPRESS" | "PT_GETREGSET" | "PT_SETREGSET" 2191 | "PT_SC_REMOTE" 2192 if Some(14) > freebsd_ver => 2193 { 2194 true 2195 } 2196 2197 // Added in FreeBSD 14. 2198 "F_KINFO" => true, // FIXME: depends how frequent freebsd 14 is updated on CI, this addition went this week only. 2199 "SHM_RENAME_NOREPLACE" 2200 | "SHM_RENAME_EXCHANGE" 2201 | "SHM_LARGEPAGE_ALLOC_DEFAULT" 2202 | "SHM_LARGEPAGE_ALLOC_NOWAIT" 2203 | "SHM_LARGEPAGE_ALLOC_HARD" 2204 | "MFD_CLOEXEC" 2205 | "MFD_ALLOW_SEALING" 2206 | "MFD_HUGETLB" 2207 | "MFD_HUGE_MASK" 2208 | "MFD_HUGE_64KB" 2209 | "MFD_HUGE_512KB" 2210 | "MFD_HUGE_1MB" 2211 | "MFD_HUGE_2MB" 2212 | "MFD_HUGE_8MB" 2213 | "MFD_HUGE_16MB" 2214 | "MFD_HUGE_32MB" 2215 | "MFD_HUGE_256MB" 2216 | "MFD_HUGE_512MB" 2217 | "MFD_HUGE_1GB" 2218 | "MFD_HUGE_2GB" 2219 | "MFD_HUGE_16GB" 2220 if Some(13) > freebsd_ver => 2221 { 2222 true 2223 } 2224 2225 // Flags introduced in FreeBSD 14. 2226 "TCP_MAXUNACKTIME" 2227 | "TCP_MAXPEAKRATE" 2228 | "TCP_IDLE_REDUCE" 2229 | "TCP_REMOTE_UDP_ENCAPS_PORT" 2230 | "TCP_DELACK" 2231 | "TCP_FIN_IS_RST" 2232 | "TCP_LOG_LIMIT" 2233 | "TCP_SHARED_CWND_ALLOWED" 2234 | "TCP_PROC_ACCOUNTING" 2235 | "TCP_USE_CMP_ACKS" 2236 | "TCP_PERF_INFO" 2237 | "TCP_LRD" 2238 if Some(14) > freebsd_ver => 2239 { 2240 true 2241 } 2242 2243 // Added in FreeBSD 14 2244 "LIO_READV" | "LIO_WRITEV" | "LIO_VECTORED" if Some(14) > freebsd_ver => true, 2245 2246 // Added in FreeBSD 13 2247 "FIOSSHMLPGCNF" if Some(13) > freebsd_ver => true, 2248 2249 // Added in FreeBSD 14 2250 "IFCAP_NV" if Some(14) > freebsd_ver => true, 2251 2252 _ => false, 2253 } 2254 }); 2255 2256 cfg.skip_type(move |ty| { 2257 match ty { 2258 // the struct "__kvm" is quite tricky to bind so since we only use a pointer to it 2259 // for now, it doesn't matter too much... 2260 "kvm_t" => true, 2261 2262 _ => false, 2263 } 2264 }); 2265 2266 cfg.skip_struct(move |ty| { 2267 if ty.starts_with("__c_anonymous_") { 2268 return true; 2269 } 2270 match ty { 2271 // `procstat` is a private struct 2272 "procstat" => true, 2273 2274 // `spacectl_range` was introduced in FreeBSD 14 2275 "spacectl_range" if Some(14) > freebsd_ver => true, 2276 2277 // `ptrace_coredump` introduced in FreeBSD 14. 2278 "ptrace_coredump" if Some(14) > freebsd_ver => true, 2279 // `ptrace_sc_remote` introduced in FreeBSD 14. 2280 "ptrace_sc_remote" if Some(14) > freebsd_ver => true, 2281 2282 // `sockcred2` is not available in FreeBSD 12. 2283 "sockcred2" if Some(13) > freebsd_ver => true, 2284 // `shm_largepage_conf` was introduced in FreeBSD 13. 2285 "shm_largepage_conf" if Some(13) > freebsd_ver => true, 2286 2287 // Those are private types 2288 "memory_type" => true, 2289 "memory_type_list" => true, 2290 2291 _ => false, 2292 } 2293 }); 2294 2295 cfg.skip_fn(move |name| { 2296 // skip those that are manually verified 2297 match name { 2298 // FIXME: https://github.com/rust-lang/libc/issues/1272 2299 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 2300 2301 // `fspacectl` was introduced in FreeBSD 14 2302 "fspacectl" if Some(14) > freebsd_ver => true, 2303 2304 // The `uname` function in the `utsname.h` FreeBSD header is a C 2305 // inline function (has no symbol) that calls the `__xuname` symbol. 2306 // Therefore the function pointer comparison does not make sense for it. 2307 "uname" => true, 2308 2309 // FIXME: Our API is unsound. The Rust API allows aliasing 2310 // pointers, but the C API requires pointers not to alias. 2311 // We should probably be at least using `&`/`&mut` here, see: 2312 // https://github.com/gnzlbg/ctest/issues/68 2313 "lio_listio" => true, 2314 2315 // Those are introduced in FreeBSD 14. 2316 "sched_getaffinity" | "sched_setaffinity" | "sched_getcpu" 2317 if Some(14) > freebsd_ver => 2318 { 2319 true 2320 } 2321 2322 // This is not available in FreeBSD 12. 2323 "SOCKCRED2SIZE" if Some(13) > freebsd_ver => true, 2324 2325 // Those are not available in FreeBSD 12. 2326 "memfd_create" | "shm_create_largepage" | "shm_rename" if Some(13) > freebsd_ver => { 2327 true 2328 } 2329 2330 // Added in FreeBSD 13. 2331 "getlocalbase" if Some(13) > freebsd_ver => true, 2332 "aio_readv" if Some(13) > freebsd_ver => true, 2333 "aio_writev" if Some(13) > freebsd_ver => true, 2334 "copy_file_range" if Some(13) > freebsd_ver => true, 2335 2336 _ => false, 2337 } 2338 }); 2339 2340 cfg.volatile_item(|i| { 2341 use ctest::VolatileItemKind::*; 2342 match i { 2343 // aio_buf is a volatile void** but since we cannot express that in 2344 // Rust types, we have to explicitly tell the checker about it here: 2345 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 2346 _ => false, 2347 } 2348 }); 2349 2350 cfg.skip_field(move |struct_, field| { 2351 match (struct_, field) { 2352 // FIXME: `sa_sigaction` has type `sighandler_t` but that type is 2353 // incorrect, see: https://github.com/rust-lang/libc/issues/1359 2354 ("sigaction", "sa_sigaction") => true, 2355 2356 // conflicting with `p_type` macro from <resolve.h>. 2357 ("Elf32_Phdr", "p_type") => true, 2358 ("Elf64_Phdr", "p_type") => true, 2359 2360 // not available until FreeBSD 12, and is an anonymous union there. 2361 ("xucred", "cr_pid__c_anonymous_union") => true, 2362 2363 // m_owner field is a volatile __lwpid_t 2364 ("umutex", "m_owner") => true, 2365 // c_has_waiters field is a volatile int32_t 2366 ("ucond", "c_has_waiters") => true, 2367 // is PATH_MAX long but tests can't accept multi array as equivalent. 2368 ("kinfo_vmentry", "kve_path") => true, 2369 2370 // a_un field is a union 2371 ("Elf32_Auxinfo", "a_un") => true, 2372 ("Elf64_Auxinfo", "a_un") => true, 2373 2374 // union fields 2375 ("if_data", "__ifi_epoch") => true, 2376 ("if_data", "__ifi_lastchange") => true, 2377 ("ifreq", "ifr_ifru") => true, 2378 ("ifconf", "ifc_ifcu") => true, 2379 2380 // anonymous struct 2381 ("devstat", "dev_links") => true, 2382 2383 // FIXME: structs too complicated to bind for now... 2384 ("kinfo_proc", "ki_paddr") => true, 2385 ("kinfo_proc", "ki_addr") => true, 2386 ("kinfo_proc", "ki_tracep") => true, 2387 ("kinfo_proc", "ki_textvp") => true, 2388 ("kinfo_proc", "ki_fd") => true, 2389 ("kinfo_proc", "ki_vmspace") => true, 2390 ("kinfo_proc", "ki_pcb") => true, 2391 ("kinfo_proc", "ki_tdaddr") => true, 2392 ("kinfo_proc", "ki_pd") => true, 2393 2394 // Anonymous type. 2395 ("filestat", "next") => true, 2396 2397 // We ignore this field because we needed to use a hack in order to make rust 1.19 2398 // happy... 2399 ("kinfo_proc", "ki_sparestrings") => true, 2400 2401 // `__sem_base` is a private struct field 2402 ("semid_ds", "__sem_base") => true, 2403 2404 // `snap_time` is a `long double`, but it's a nightmare to bind correctly in rust 2405 // for the moment, so it's a best effort thing... 2406 ("statinfo", "snap_time") => true, 2407 2408 _ => false, 2409 } 2410 }); 2411 2412 cfg.generate("../src/lib.rs", "main.rs"); 2413 } 2414 2415 fn test_emscripten(target: &str) { 2416 assert!(target.contains("emscripten")); 2417 2418 let mut cfg = ctest_cfg(); 2419 cfg.define("_GNU_SOURCE", None); // FIXME: ?? 2420 2421 headers! { cfg: 2422 "aio.h", 2423 "ctype.h", 2424 "dirent.h", 2425 "dlfcn.h", 2426 "errno.h", 2427 "fcntl.h", 2428 "glob.h", 2429 "grp.h", 2430 "ifaddrs.h", 2431 "langinfo.h", 2432 "limits.h", 2433 "locale.h", 2434 "malloc.h", 2435 "mntent.h", 2436 "mqueue.h", 2437 "net/ethernet.h", 2438 "net/if.h", 2439 "net/if_arp.h", 2440 "net/route.h", 2441 "netdb.h", 2442 "netinet/in.h", 2443 "netinet/ip.h", 2444 "netinet/tcp.h", 2445 "netinet/udp.h", 2446 "netpacket/packet.h", 2447 "poll.h", 2448 "pthread.h", 2449 "pty.h", 2450 "pwd.h", 2451 "resolv.h", 2452 "sched.h", 2453 "sched.h", 2454 "semaphore.h", 2455 "shadow.h", 2456 "signal.h", 2457 "stddef.h", 2458 "stdint.h", 2459 "stdio.h", 2460 "stdlib.h", 2461 "string.h", 2462 "sys/epoll.h", 2463 "sys/eventfd.h", 2464 "sys/file.h", 2465 "sys/ioctl.h", 2466 "sys/ipc.h", 2467 "sys/mman.h", 2468 "sys/mount.h", 2469 "sys/msg.h", 2470 "sys/personality.h", 2471 "sys/prctl.h", 2472 "sys/ptrace.h", 2473 "sys/quota.h", 2474 "sys/reboot.h", 2475 "sys/resource.h", 2476 "sys/sem.h", 2477 "sys/shm.h", 2478 "sys/signalfd.h", 2479 "sys/socket.h", 2480 "sys/stat.h", 2481 "sys/statvfs.h", 2482 "sys/swap.h", 2483 "sys/syscall.h", 2484 "sys/sysctl.h", 2485 "sys/sysinfo.h", 2486 "sys/time.h", 2487 "sys/timerfd.h", 2488 "sys/times.h", 2489 "sys/types.h", 2490 "sys/uio.h", 2491 "sys/un.h", 2492 "sys/user.h", 2493 "sys/utsname.h", 2494 "sys/vfs.h", 2495 "sys/wait.h", 2496 "sys/xattr.h", 2497 "syslog.h", 2498 "termios.h", 2499 "time.h", 2500 "ucontext.h", 2501 "unistd.h", 2502 "utime.h", 2503 "utmp.h", 2504 "utmpx.h", 2505 "wchar.h", 2506 } 2507 2508 cfg.type_name(move |ty, is_struct, is_union| { 2509 match ty { 2510 // Just pass all these through, no need for a "struct" prefix 2511 "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(), 2512 2513 "os_unfair_lock" => "struct os_unfair_lock_s".to_string(), 2514 2515 t if is_union => format!("union {}", t), 2516 2517 t if t.ends_with("_t") => t.to_string(), 2518 2519 // put `struct` in front of all structs:. 2520 t if is_struct => format!("struct {}", t), 2521 2522 t => t.to_string(), 2523 } 2524 }); 2525 2526 cfg.field_name(move |struct_, field| { 2527 match field { 2528 // Our stat *_nsec fields normally don't actually exist but are part 2529 // of a timeval struct 2530 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 2531 s.replace("e_nsec", ".tv_nsec") 2532 } 2533 // FIXME: appears that `epoll_event.data` is an union 2534 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 2535 s => s.to_string(), 2536 } 2537 }); 2538 2539 cfg.skip_type(move |ty| { 2540 match ty { 2541 // sighandler_t is crazy across platforms 2542 // FIXME: is this necessary? 2543 "sighandler_t" => true, 2544 2545 // FIXME: The size has been changed due to musl's time64 2546 "time_t" => true, 2547 2548 _ => false, 2549 } 2550 }); 2551 2552 cfg.skip_struct(move |ty| { 2553 match ty { 2554 // This is actually a union, not a struct 2555 // FIXME: is this necessary? 2556 "sigval" => true, 2557 2558 // FIXME: It was removed in 2559 // emscripten-core/emscripten@953e414 2560 "pthread_mutexattr_t" => true, 2561 2562 // FIXME: Investigate why the test fails. 2563 // Skip for now to unblock CI. 2564 "pthread_condattr_t" => true, 2565 2566 // FIXME: The size has been changed when upgraded to musl 1.2.2 2567 "pthread_mutex_t" => true, 2568 2569 // FIXME: Lowered from 16 to 8 bytes in 2570 // llvm/llvm-project@d1a96e9 2571 "max_align_t" => true, 2572 2573 // FIXME: The size has been changed due to time64 2574 "utimbuf" | "timeval" | "timespec" | "rusage" | "itimerval" | "sched_param" 2575 | "stat" | "stat64" | "shmid_ds" | "msqid_ds" => true, 2576 2577 _ => false, 2578 } 2579 }); 2580 2581 cfg.skip_fn(move |name| { 2582 match name { 2583 // Emscripten does not support fork/exec/wait or any kind of multi-process support 2584 // https://github.com/emscripten-core/emscripten/blob/3.1.30/tools/system_libs.py#L973 2585 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" | "wait4" => true, 2586 2587 // FIXME: Remove after emscripten-core/emscripten#18492 is released (> 3.1.30). 2588 "clearenv" => true, 2589 2590 _ => false, 2591 } 2592 }); 2593 2594 cfg.skip_const(move |name| { 2595 match name { 2596 // FIXME: deprecated - SIGNUNUSED was removed in glibc 2.26 2597 // users should use SIGSYS instead 2598 "SIGUNUSED" => true, 2599 2600 // FIXME: emscripten uses different constants to constructs these 2601 n if n.contains("__SIZEOF_PTHREAD") => true, 2602 2603 // FIXME: `SYS_gettid` was removed in 2604 // emscripten-core/emscripten@6d6474e 2605 "SYS_gettid" => true, 2606 2607 // FIXME: These values have been changed 2608 | "POSIX_MADV_DONTNEED" // to 4 2609 | "RLIMIT_NLIMITS" // to 16 2610 | "RLIM_NLIMITS" // to 16 2611 | "IPPROTO_MAX" // to 263 2612 | "F_GETLK" // to 5 2613 | "F_SETLK" // to 6 2614 | "F_SETLKW" // to 7 2615 | "O_TMPFILE" // to 65 2616 | "SIG_IGN" // -1 2617 => true, 2618 2619 _ => false, 2620 } 2621 }); 2622 2623 cfg.skip_field_type(move |struct_, field| { 2624 // This is a weird union, don't check the type. 2625 // FIXME: is this necessary? 2626 (struct_ == "ifaddrs" && field == "ifa_ifu") || 2627 // sighandler_t type is super weird 2628 // FIXME: is this necessary? 2629 (struct_ == "sigaction" && field == "sa_sigaction") || 2630 // sigval is actually a union, but we pretend it's a struct 2631 // FIXME: is this necessary? 2632 (struct_ == "sigevent" && field == "sigev_value") || 2633 // aio_buf is "volatile void*" and Rust doesn't understand volatile 2634 // FIXME: is this necessary? 2635 (struct_ == "aiocb" && field == "aio_buf") 2636 }); 2637 2638 cfg.skip_field(move |struct_, field| { 2639 // this is actually a union on linux, so we can't represent it well and 2640 // just insert some padding. 2641 // FIXME: is this necessary? 2642 (struct_ == "siginfo_t" && field == "_pad") || 2643 // musl names this __dummy1 but it's still there 2644 // FIXME: is this necessary? 2645 (struct_ == "glob_t" && field == "gl_flags") || 2646 // musl seems to define this as an *anonymous* bitfield 2647 // FIXME: is this necessary? 2648 (struct_ == "statvfs" && field == "__f_unused") || 2649 // sigev_notify_thread_id is actually part of a sigev_un union 2650 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 2651 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet. 2652 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 2653 field == "_pad2" || 2654 field == "ssi_syscall" || 2655 field == "ssi_call_addr" || 2656 field == "ssi_arch")) || 2657 // FIXME: After musl 1.1.24, it have only one field `sched_priority`, 2658 // while other fields become reserved. 2659 (struct_ == "sched_param" && [ 2660 "sched_ss_low_priority", 2661 "sched_ss_repl_period", 2662 "sched_ss_init_budget", 2663 "sched_ss_max_repl", 2664 ].contains(&field)) 2665 }); 2666 2667 // FIXME: test linux like 2668 cfg.generate("../src/lib.rs", "main.rs"); 2669 } 2670 2671 fn test_neutrino(target: &str) { 2672 assert!(target.contains("nto-qnx")); 2673 2674 let mut cfg = ctest_cfg(); 2675 2676 headers! { cfg: 2677 "ctype.h", 2678 "dirent.h", 2679 "dlfcn.h", 2680 "sys/elf.h", 2681 "fcntl.h", 2682 "glob.h", 2683 "grp.h", 2684 "iconv.h", 2685 "ifaddrs.h", 2686 "limits.h", 2687 "sys/link.h", 2688 "locale.h", 2689 "sys/malloc.h", 2690 "rcheck/malloc.h", 2691 "malloc.h", 2692 "mqueue.h", 2693 "net/if.h", 2694 "net/if_arp.h", 2695 "net/route.h", 2696 "netdb.h", 2697 "netinet/in.h", 2698 "netinet/ip.h", 2699 "netinet/tcp.h", 2700 "netinet/udp.h", 2701 "netinet/ip_var.h", 2702 "sys/poll.h", 2703 "pthread.h", 2704 "pwd.h", 2705 "regex.h", 2706 "resolv.h", 2707 "sys/sched.h", 2708 "sched.h", 2709 "semaphore.h", 2710 "shadow.h", 2711 "signal.h", 2712 "spawn.h", 2713 "stddef.h", 2714 "stdint.h", 2715 "stdio.h", 2716 "stdlib.h", 2717 "string.h", 2718 "sys/sysctl.h", 2719 "sys/file.h", 2720 "sys/inotify.h", 2721 "sys/ioctl.h", 2722 "sys/ipc.h", 2723 "sys/mman.h", 2724 "sys/mount.h", 2725 "sys/msg.h", 2726 "sys/resource.h", 2727 "sys/sem.h", 2728 "sys/socket.h", 2729 "sys/stat.h", 2730 "sys/statvfs.h", 2731 "sys/swap.h", 2732 "sys/termio.h", 2733 "sys/time.h", 2734 "sys/times.h", 2735 "sys/types.h", 2736 "sys/uio.h", 2737 "sys/un.h", 2738 "sys/utsname.h", 2739 "sys/wait.h", 2740 "syslog.h", 2741 "termios.h", 2742 "time.h", 2743 "sys/time.h", 2744 "ucontext.h", 2745 "unistd.h", 2746 "utime.h", 2747 "utmp.h", 2748 "wchar.h", 2749 "aio.h", 2750 "nl_types.h", 2751 "langinfo.h", 2752 "unix.h", 2753 "nbutil.h", 2754 "aio.h", 2755 "net/bpf.h", 2756 "net/if_dl.h", 2757 "sys/syspage.h", 2758 2759 // TODO: The following header file doesn't appear as part of the default headers 2760 // found in a standard installation of Neutrino 7.1 SDP. The structures/ 2761 // functions dependent on it are currently commented out. 2762 //"sys/asyncmsg.h", 2763 } 2764 2765 // Create and include a header file containing 2766 // items which are not included in any official 2767 // header file. 2768 let internal_header = "internal.h"; 2769 let out_dir = env::var("OUT_DIR").unwrap(); 2770 cfg.header(internal_header); 2771 cfg.include(&out_dir); 2772 std::fs::write( 2773 out_dir.to_owned() + "/" + internal_header, 2774 "#ifndef __internal_h__ 2775 #define __internal_h__ 2776 void __my_thread_exit(const void **); 2777 #endif", 2778 ) 2779 .unwrap(); 2780 2781 cfg.type_name(move |ty, is_struct, is_union| { 2782 match ty { 2783 // Just pass all these through, no need for a "struct" prefix 2784 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 2785 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 2786 | "Elf32_Chdr" | "Elf64_Chdr" | "aarch64_qreg_t" | "syspage_entry_info" 2787 | "syspage_array_info" => ty.to_string(), 2788 2789 "Ioctl" => "int".to_string(), 2790 2791 t if is_union => format!("union {}", t), 2792 2793 t if t.ends_with("_t") => t.to_string(), 2794 2795 // put `struct` in front of all structs:. 2796 t if is_struct => format!("struct {}", t), 2797 2798 t => t.to_string(), 2799 } 2800 }); 2801 2802 cfg.field_name(move |_struct_, field| match field { 2803 "type_" => "type".to_string(), 2804 2805 s => s.to_string(), 2806 }); 2807 2808 cfg.volatile_item(|i| { 2809 use ctest::VolatileItemKind::*; 2810 match i { 2811 // The following fields are volatie but since we cannot express that in 2812 // Rust types, we have to explicitly tell the checker about it here: 2813 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 2814 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec_tod_adjust" => true, 2815 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec" => true, 2816 StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec_stable" => true, 2817 StructField(ref n, ref f) if n == "intrspin" && f == "value" => true, 2818 _ => false, 2819 } 2820 }); 2821 2822 cfg.skip_type(move |ty| { 2823 match ty { 2824 // FIXME: `sighandler_t` type is incorrect, see: 2825 // https://github.com/rust-lang/libc/issues/1359 2826 "sighandler_t" => true, 2827 2828 // Does not exist in Neutrino 2829 "locale_t" => true, 2830 2831 _ => false, 2832 } 2833 }); 2834 2835 cfg.skip_struct(move |ty| { 2836 if ty.starts_with("__c_anonymous_") { 2837 return true; 2838 } 2839 match ty { 2840 "Elf64_Phdr" | "Elf32_Phdr" => true, 2841 2842 // FIXME: This is actually a union, not a struct 2843 "sigval" => true, 2844 2845 // union 2846 "_channel_connect_attr" => true, 2847 2848 _ => false, 2849 } 2850 }); 2851 2852 cfg.skip_const(move |name| { 2853 match name { 2854 // These signal "functions" are actually integer values that are casted to a fn ptr 2855 // This causes the compiler to err because of "illegal cast of int to ptr". 2856 "SIG_DFL" => true, 2857 "SIG_IGN" => true, 2858 "SIG_ERR" => true, 2859 2860 _ => false, 2861 } 2862 }); 2863 2864 cfg.skip_fn(move |name| { 2865 // skip those that are manually verified 2866 match name { 2867 // FIXME: https://github.com/rust-lang/libc/issues/1272 2868 "execv" | "execve" | "execvp" | "execvpe" => true, 2869 2870 // wrong signature 2871 "signal" => true, 2872 2873 // wrong signature of callback ptr 2874 "__cxa_atexit" => true, 2875 2876 // FIXME: Our API is unsound. The Rust API allows aliasing 2877 // pointers, but the C API requires pointers not to alias. 2878 // We should probably be at least using `&`/`&mut` here, see: 2879 // https://github.com/gnzlbg/ctest/issues/68 2880 "lio_listio" => true, 2881 2882 // 2 fields are actually unions which we're simply representing 2883 // as structures. 2884 "ChannelConnectAttr" => true, 2885 2886 // fields contains unions 2887 "SignalKillSigval" => true, 2888 "SignalKillSigval_r" => true, 2889 2890 // Not defined in any headers. Defined to work around a 2891 // stack unwinding bug. 2892 "__my_thread_exit" => true, 2893 2894 _ => false, 2895 } 2896 }); 2897 2898 cfg.skip_field_type(move |struct_, field| { 2899 // sigval is actually a union, but we pretend it's a struct 2900 struct_ == "sigevent" && field == "sigev_value" || 2901 // Anonymous structures 2902 struct_ == "_idle_hook" && field == "time" 2903 }); 2904 2905 cfg.skip_field(move |struct_, field| { 2906 (struct_ == "__sched_param" && field == "reserved") || 2907 (struct_ == "sched_param" && field == "reserved") || 2908 (struct_ == "sigevent" && field == "__sigev_un1") || // union 2909 (struct_ == "sigevent" && field == "__sigev_un2") || // union 2910 // sighandler_t type is super weird 2911 (struct_ == "sigaction" && field == "sa_sigaction") || 2912 // does not exist 2913 (struct_ == "syspage_entry" && field == "__reserved") || 2914 false // keep me for smaller diffs when something is added above 2915 }); 2916 2917 cfg.skip_static(move |name| (name == "__dso_handle")); 2918 2919 cfg.generate("../src/lib.rs", "main.rs"); 2920 } 2921 2922 fn test_vxworks(target: &str) { 2923 assert!(target.contains("vxworks")); 2924 2925 let mut cfg = ctest::TestGenerator::new(); 2926 headers! { cfg: 2927 "vxWorks.h", 2928 "yvals.h", 2929 "nfs/nfsCommon.h", 2930 "rtpLibCommon.h", 2931 "randomNumGen.h", 2932 "taskLib.h", 2933 "sysLib.h", 2934 "ioLib.h", 2935 "inetLib.h", 2936 "socket.h", 2937 "errnoLib.h", 2938 "ctype.h", 2939 "dirent.h", 2940 "dlfcn.h", 2941 "elf.h", 2942 "fcntl.h", 2943 "grp.h", 2944 "sys/poll.h", 2945 "ifaddrs.h", 2946 "langinfo.h", 2947 "limits.h", 2948 "link.h", 2949 "locale.h", 2950 "sys/stat.h", 2951 "netdb.h", 2952 "pthread.h", 2953 "pwd.h", 2954 "sched.h", 2955 "semaphore.h", 2956 "signal.h", 2957 "stddef.h", 2958 "stdint.h", 2959 "stdio.h", 2960 "stdlib.h", 2961 "string.h", 2962 "sys/file.h", 2963 "sys/ioctl.h", 2964 "sys/socket.h", 2965 "sys/time.h", 2966 "sys/times.h", 2967 "sys/types.h", 2968 "sys/uio.h", 2969 "sys/un.h", 2970 "sys/utsname.h", 2971 "sys/wait.h", 2972 "netinet/tcp.h", 2973 "syslog.h", 2974 "termios.h", 2975 "time.h", 2976 "ucontext.h", 2977 "unistd.h", 2978 "utime.h", 2979 "wchar.h", 2980 "errno.h", 2981 "sys/mman.h", 2982 "pathLib.h", 2983 "mqueue.h", 2984 } 2985 // FIXME 2986 cfg.skip_const(move |name| match name { 2987 // sighandler_t weirdness 2988 "SIG_DFL" | "SIG_ERR" | "SIG_IGN" 2989 // This is not defined in vxWorks 2990 | "RTLD_DEFAULT" => true, 2991 _ => false, 2992 }); 2993 // FIXME 2994 cfg.skip_type(move |ty| match ty { 2995 "stat64" | "sighandler_t" | "off64_t" => true, 2996 _ => false, 2997 }); 2998 2999 cfg.skip_field_type(move |struct_, field| match (struct_, field) { 3000 ("siginfo_t", "si_value") | ("stat", "st_size") | ("sigaction", "sa_u") => true, 3001 _ => false, 3002 }); 3003 3004 cfg.skip_roundtrip(move |s| match s { 3005 _ => false, 3006 }); 3007 3008 cfg.type_name(move |ty, is_struct, is_union| match ty { 3009 "DIR" | "FILE" | "Dl_info" | "RTP_DESC" => ty.to_string(), 3010 t if is_union => format!("union {}", t), 3011 t if t.ends_with("_t") => t.to_string(), 3012 t if is_struct => format!("struct {}", t), 3013 t => t.to_string(), 3014 }); 3015 3016 // FIXME 3017 cfg.skip_fn(move |name| match name { 3018 // sigval 3019 "sigqueue" | "_sigqueue" 3020 // sighandler_t 3021 | "signal" 3022 // not used in static linking by default 3023 | "dlerror" => true, 3024 _ => false, 3025 }); 3026 3027 cfg.generate("../src/lib.rs", "main.rs"); 3028 } 3029 3030 fn test_linux(target: &str) { 3031 assert!(target.contains("linux")); 3032 3033 // target_env 3034 let gnu = target.contains("gnu"); 3035 let musl = target.contains("musl"); 3036 let uclibc = target.contains("uclibc"); 3037 3038 match (gnu, musl, uclibc) { 3039 (true, false, false) => (), 3040 (false, true, false) => (), 3041 (false, false, true) => (), 3042 (_, _, _) => panic!( 3043 "linux target lib is gnu: {}, musl: {}, uclibc: {}", 3044 gnu, musl, uclibc 3045 ), 3046 } 3047 3048 let arm = target.contains("arm"); 3049 let i686 = target.contains("i686"); 3050 let mips = target.contains("mips"); 3051 let mips32 = mips && !target.contains("64"); 3052 let mips64 = mips && target.contains("64"); 3053 let ppc = target.contains("powerpc"); 3054 let ppc64 = target.contains("powerpc64"); 3055 let s390x = target.contains("s390x"); 3056 let sparc64 = target.contains("sparc64"); 3057 let x32 = target.contains("x32"); 3058 let x86_32 = target.contains("i686"); 3059 let x86_64 = target.contains("x86_64"); 3060 let aarch64_musl = target.contains("aarch64") && musl; 3061 let gnueabihf = target.contains("gnueabihf"); 3062 let x86_64_gnux32 = target.contains("gnux32") && x86_64; 3063 let riscv64 = target.contains("riscv64"); 3064 let uclibc = target.contains("uclibc"); 3065 3066 let mut cfg = ctest_cfg(); 3067 cfg.define("_GNU_SOURCE", None); 3068 // This macro re-deifnes fscanf,scanf,sscanf to link to the symbols that are 3069 // deprecated since glibc >= 2.29. This allows Rust binaries to link against 3070 // glibc versions older than 2.29. 3071 cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None); 3072 3073 headers! { cfg: 3074 "ctype.h", 3075 "dirent.h", 3076 "dlfcn.h", 3077 "elf.h", 3078 "fcntl.h", 3079 "getopt.h", 3080 "glob.h", 3081 [gnu]: "gnu/libc-version.h", 3082 "grp.h", 3083 "iconv.h", 3084 "ifaddrs.h", 3085 "langinfo.h", 3086 "libgen.h", 3087 "limits.h", 3088 "link.h", 3089 "locale.h", 3090 "malloc.h", 3091 "mntent.h", 3092 "mqueue.h", 3093 "net/ethernet.h", 3094 "net/if.h", 3095 "net/if_arp.h", 3096 "net/route.h", 3097 "netdb.h", 3098 "netinet/in.h", 3099 "netinet/ip.h", 3100 "netinet/tcp.h", 3101 "netinet/udp.h", 3102 "netpacket/packet.h", 3103 "poll.h", 3104 "pthread.h", 3105 "pty.h", 3106 "pwd.h", 3107 "regex.h", 3108 "resolv.h", 3109 "sched.h", 3110 "semaphore.h", 3111 "shadow.h", 3112 "signal.h", 3113 "spawn.h", 3114 "stddef.h", 3115 "stdint.h", 3116 "stdio.h", 3117 "stdlib.h", 3118 "string.h", 3119 "sys/epoll.h", 3120 "sys/eventfd.h", 3121 "sys/file.h", 3122 "sys/fsuid.h", 3123 "sys/inotify.h", 3124 "sys/ioctl.h", 3125 "sys/ipc.h", 3126 "sys/mman.h", 3127 "sys/mount.h", 3128 "sys/msg.h", 3129 "sys/personality.h", 3130 "sys/prctl.h", 3131 "sys/ptrace.h", 3132 "sys/quota.h", 3133 "sys/random.h", 3134 "sys/reboot.h", 3135 "sys/resource.h", 3136 "sys/sem.h", 3137 "sys/sendfile.h", 3138 "sys/shm.h", 3139 "sys/signalfd.h", 3140 "sys/socket.h", 3141 "sys/stat.h", 3142 "sys/statvfs.h", 3143 "sys/swap.h", 3144 "sys/syscall.h", 3145 "sys/time.h", 3146 "sys/timerfd.h", 3147 "sys/times.h", 3148 "sys/timex.h", 3149 "sys/types.h", 3150 "sys/uio.h", 3151 "sys/un.h", 3152 "sys/user.h", 3153 "sys/utsname.h", 3154 "sys/vfs.h", 3155 "sys/wait.h", 3156 "syslog.h", 3157 "termios.h", 3158 "time.h", 3159 "ucontext.h", 3160 "unistd.h", 3161 "utime.h", 3162 "utmp.h", 3163 "utmpx.h", 3164 "wchar.h", 3165 "errno.h", 3166 // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit 3167 // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162 3168 // Also unavailable on gnueabihf with glibc 2.30. 3169 // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6b33f373c7b9199e00ba5fbafd94ac9bfb4337b1 3170 [(x86_64 || x86_32 || arm) && !gnueabihf]: "sys/io.h", 3171 // `sys/reg.h` is only available on x86 and x86_64 3172 [x86_64 || x86_32]: "sys/reg.h", 3173 // sysctl system call is deprecated and not available on musl 3174 // It is also unsupported in x32, deprecated since glibc 2.30: 3175 [!(x32 || musl || gnu)]: "sys/sysctl.h", 3176 // <execinfo.h> is not supported by musl: 3177 // https://www.openwall.com/lists/musl/2015/04/09/3 3178 // <execinfo.h> is not present on uclibc. 3179 [!(musl || uclibc)]: "execinfo.h", 3180 } 3181 3182 // Include linux headers at the end: 3183 headers! { 3184 cfg: 3185 "asm/mman.h", 3186 "linux/can.h", 3187 "linux/can/raw.h", 3188 // FIXME: requires kernel headers >= 5.4.1. 3189 [!musl]: "linux/can/j1939.h", 3190 "linux/dccp.h", 3191 "linux/errqueue.h", 3192 "linux/falloc.h", 3193 "linux/filter.h", 3194 "linux/fs.h", 3195 "linux/futex.h", 3196 "linux/genetlink.h", 3197 "linux/if.h", 3198 "linux/if_addr.h", 3199 "linux/if_alg.h", 3200 "linux/if_ether.h", 3201 "linux/if_tun.h", 3202 "linux/input.h", 3203 "linux/ipv6.h", 3204 "linux/keyctl.h", 3205 "linux/magic.h", 3206 "linux/memfd.h", 3207 "linux/mempolicy.h", 3208 "linux/mman.h", 3209 "linux/module.h", 3210 // FIXME: requires kernel headers >= 5.1. 3211 [!musl]: "linux/mount.h", 3212 "linux/net_tstamp.h", 3213 "linux/netfilter/nfnetlink.h", 3214 "linux/netfilter/nfnetlink_log.h", 3215 "linux/netfilter/nfnetlink_queue.h", 3216 "linux/netfilter/nf_tables.h", 3217 "linux/netfilter_ipv4.h", 3218 "linux/netfilter_ipv6.h", 3219 "linux/netfilter_ipv6/ip6_tables.h", 3220 "linux/netlink.h", 3221 // FIXME: requires Linux >= 5.6: 3222 [!musl && !sparc64]: "linux/openat2.h", 3223 [!musl]: "linux/ptrace.h", 3224 "linux/quota.h", 3225 "linux/random.h", 3226 "linux/reboot.h", 3227 "linux/rtnetlink.h", 3228 "linux/sched.h", 3229 "linux/seccomp.h", 3230 "linux/sched.h", 3231 "linux/sock_diag.h", 3232 "linux/sockios.h", 3233 "linux/uinput.h", 3234 "linux/vm_sockets.h", 3235 "linux/wait.h", 3236 "sys/fanotify.h", 3237 // <sys/auxv.h> is not present on uclibc 3238 [!uclibc]: "sys/auxv.h", 3239 } 3240 3241 // note: aio.h must be included before sys/mount.h 3242 headers! { 3243 cfg: 3244 "sys/xattr.h", 3245 "sys/sysinfo.h", 3246 // AIO is not supported by uclibc: 3247 [!uclibc]: "aio.h", 3248 } 3249 3250 cfg.type_name(move |ty, is_struct, is_union| { 3251 match ty { 3252 // Just pass all these through, no need for a "struct" prefix 3253 "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr" 3254 | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" 3255 | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(), 3256 3257 "Ioctl" if gnu => "unsigned long".to_string(), 3258 "Ioctl" => "int".to_string(), 3259 3260 t if is_union => format!("union {}", t), 3261 3262 t if t.ends_with("_t") => t.to_string(), 3263 3264 // In MUSL `flock64` is a typedef to `flock`. 3265 "flock64" if musl => format!("struct {}", ty), 3266 3267 // put `struct` in front of all structs:. 3268 t if is_struct => format!("struct {}", t), 3269 3270 t => t.to_string(), 3271 } 3272 }); 3273 3274 cfg.field_name(move |struct_, field| { 3275 match field { 3276 // Our stat *_nsec fields normally don't actually exist but are part 3277 // of a timeval struct 3278 s if s.ends_with("_nsec") && struct_.starts_with("stat") => { 3279 s.replace("e_nsec", ".tv_nsec") 3280 } 3281 // FIXME: epoll_event.data is actually a union in C, but in Rust 3282 // it is only a u64 because we only expose one field 3283 // http://man7.org/linux/man-pages/man2/epoll_wait.2.html 3284 "u64" if struct_ == "epoll_event" => "data.u64".to_string(), 3285 // The following structs have a field called `type` in C, 3286 // but `type` is a Rust keyword, so these fields are translated 3287 // to `type_` in Rust. 3288 "type_" 3289 if struct_ == "input_event" 3290 || struct_ == "input_mask" 3291 || struct_ == "ff_effect" => 3292 { 3293 "type".to_string() 3294 } 3295 3296 s => s.to_string(), 3297 } 3298 }); 3299 3300 cfg.skip_type(move |ty| { 3301 match ty { 3302 // FIXME: `sighandler_t` type is incorrect, see: 3303 // https://github.com/rust-lang/libc/issues/1359 3304 "sighandler_t" => true, 3305 3306 // These cannot be tested when "resolv.h" is included and are tested 3307 // in the `linux_elf.rs` file. 3308 "Elf64_Phdr" | "Elf32_Phdr" => true, 3309 3310 // This type is private on Linux. It is implemented as a C `enum` 3311 // (`c_uint`) and this clashes with the type of the `rlimit` APIs 3312 // which expect a `c_int` even though both are ABI compatible. 3313 "__rlimit_resource_t" => true, 3314 // on Linux, this is a volatile int 3315 "pthread_spinlock_t" => true, 3316 3317 // For internal use only, to define architecture specific ioctl constants with a libc specific type. 3318 "Ioctl" => true, 3319 3320 // FIXME: requires >= 5.4.1 kernel headers 3321 "pgn_t" if musl => true, 3322 "priority_t" if musl => true, 3323 "name_t" if musl => true, 3324 3325 _ => false, 3326 } 3327 }); 3328 3329 cfg.skip_struct(move |ty| { 3330 if ty.starts_with("__c_anonymous_") { 3331 return true; 3332 } 3333 // FIXME: musl CI has old headers 3334 if (musl || sparc64) && ty.starts_with("uinput_") { 3335 return true; 3336 } 3337 // FIXME(https://github.com/rust-lang/libc/issues/1558): passing by 3338 // value corrupts the value for reasons not understood. 3339 if (gnu && sparc64) && ty == "ip_mreqn" { 3340 return true; 3341 } 3342 match ty { 3343 // These cannot be tested when "resolv.h" is included and are tested 3344 // in the `linux_elf.rs` file. 3345 "Elf64_Phdr" | "Elf32_Phdr" => true, 3346 3347 // On Linux, the type of `ut_tv` field of `struct utmpx` 3348 // can be an anonymous struct, so an extra struct, 3349 // which is absent in glibc, has to be defined. 3350 "__timeval" => true, 3351 3352 // FIXME: This is actually a union, not a struct 3353 "sigval" => true, 3354 3355 // This type is tested in the `linux_termios.rs` file since there 3356 // are header conflicts when including them with all the other 3357 // structs. 3358 "termios2" => true, 3359 3360 // FIXME: remove once we set minimum supported glibc version. 3361 // ucontext_t added a new field as of glibc 2.28; our struct definition is 3362 // conservative and omits the field, but that means the size doesn't match for newer 3363 // glibcs (see https://github.com/rust-lang/libc/issues/1410) 3364 "ucontext_t" if gnu => true, 3365 3366 // FIXME: Somehow we cannot include headers correctly in glibc 2.30. 3367 // So let's ignore for now and re-visit later. 3368 // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085 3369 "statx" => true, 3370 "statx_timestamp" => true, 3371 3372 // On Linux, the type of `ut_exit` field of struct `utmpx` 3373 // can be an anonymous struct, so an extra struct, 3374 // which is absent in musl, has to be defined. 3375 "__exit_status" if musl => true, 3376 3377 // clone_args might differ b/w libc versions 3378 "clone_args" => true, 3379 3380 // Might differ between kernel versions 3381 "open_how" => true, 3382 3383 // FIXME: requires >= 5.4.1 kernel headers 3384 "j1939_filter" if musl => true, 3385 3386 // FIXME: requires >= 5.4 kernel headers 3387 "sockaddr_can" if musl => true, 3388 3389 // FIXME: Unignore once we update Ubuntu to 22.04 3390 "mallinfo2" if sparc64 => true, 3391 "ptrace_rseq_configuration" if sparc64 => true, 3392 3393 _ => false, 3394 } 3395 }); 3396 3397 cfg.skip_const(move |name| { 3398 if !gnu { 3399 // Skip definitions from the kernel on non-glibc Linux targets. 3400 // They're libc-independent, so we only need to check them on one 3401 // libc. We don't want to break CI if musl or another libc doesn't 3402 // have the definitions yet. (We do still want to check them on 3403 // every glibc target, though, as some of them can vary by 3404 // architecture.) 3405 // 3406 // This is not an exhaustive list of kernel constants, just a list 3407 // of prefixes of all those that have appeared here or that get 3408 // updated regularly and seem likely to cause breakage. 3409 if name.starts_with("AF_") 3410 || name.starts_with("ARPHRD_") 3411 || name.starts_with("EPOLL") 3412 || name.starts_with("F_") 3413 || name.starts_with("FALLOC_FL_") 3414 || name.starts_with("IFLA_") 3415 || name.starts_with("MS_") 3416 || name.starts_with("MSG_") 3417 || name.starts_with("OPEN_TREE_") 3418 || name.starts_with("P_") 3419 || name.starts_with("PF_") 3420 || name.starts_with("RLIMIT_") 3421 || name.starts_with("SOL_") 3422 || name.starts_with("STATX_") 3423 || name.starts_with("SW_") 3424 || name.starts_with("SYS_") 3425 || name.starts_with("TCP_") 3426 || name.starts_with("UINPUT_") 3427 || name.starts_with("VMADDR_") 3428 { 3429 return true; 3430 } 3431 } 3432 if musl || sparc64 { 3433 // FIXME: Requires >= 5.4.1 kernel headers 3434 if name.starts_with("J1939") 3435 || name.starts_with("SO_J1939") 3436 || name.starts_with("SCM_J1939") 3437 { 3438 return true; 3439 } 3440 } 3441 match name { 3442 // These constants are not available if gnu headers have been included 3443 // and can therefore not be tested here 3444 // 3445 // The IPV6 constants are tested in the `linux_ipv6.rs` tests: 3446 | "IPV6_FLOWINFO" 3447 | "IPV6_FLOWLABEL_MGR" 3448 | "IPV6_FLOWINFO_SEND" 3449 | "IPV6_FLOWINFO_FLOWLABEL" 3450 | "IPV6_FLOWINFO_PRIORITY" 3451 // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests: 3452 | "F_CANCELLK" 3453 | "F_ADD_SEALS" 3454 | "F_GET_SEALS" 3455 | "F_SEAL_SEAL" 3456 | "F_SEAL_SHRINK" 3457 | "F_SEAL_GROW" 3458 | "F_SEAL_WRITE" => true, 3459 // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests 3460 // because including `linux/if_arp.h` causes some conflicts: 3461 "ARPHRD_CAN" => true, 3462 3463 // FIXME: deprecated: not available in any header 3464 // See: https://github.com/rust-lang/libc/issues/1356 3465 "ENOATTR" => true, 3466 3467 // FIXME: SIGUNUSED was removed in glibc 2.26 3468 // Users should use SIGSYS instead. 3469 "SIGUNUSED" => true, 3470 3471 // FIXME: conflicts with glibc headers and is tested in 3472 // `linux_termios.rs` below: 3473 | "BOTHER" 3474 | "IBSHIFT" 3475 | "TCGETS2" 3476 | "TCSETS2" 3477 | "TCSETSW2" 3478 | "TCSETSF2" => true, 3479 3480 // FIXME: on musl the pthread types are defined a little differently 3481 // - these constants are used by the glibc implementation. 3482 n if musl && n.contains("__SIZEOF_PTHREAD") => true, 3483 3484 // FIXME: It was extended to 4096 since glibc 2.31 (Linux 5.4). 3485 // We should do so after a while. 3486 "SOMAXCONN" if gnu => true, 3487 3488 // deprecated: not available from Linux kernel 5.6: 3489 "VMADDR_CID_RESERVED" => true, 3490 3491 // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP: 3492 | "IPPROTO_MAX" 3493 | "IPPROTO_MPTCP" => true, 3494 3495 // FIXME: Not currently available in headers 3496 "P_PIDFD" if mips => true, 3497 "SYS_pidfd_open" if mips => true, 3498 3499 // FIXME: Not currently available in headers on MIPS 3500 // Not yet implemented on sparc64 3501 "SYS_clone3" if mips | sparc64 => true, 3502 3503 // FIXME: Not defined on ARM, gnueabihf, MIPS, musl, PowerPC, riscv64, s390x, and sparc64. 3504 "SYS_memfd_secret" if arm | gnueabihf | mips | musl | ppc | riscv64 | s390x | sparc64 => true, 3505 3506 // FIXME: Added in Linux 5.16 3507 // https://github.com/torvalds/linux/commit/039c0ec9bb77446d7ada7f55f90af9299b28ca49 3508 "SYS_futex_waitv" => true, 3509 3510 // FIXME: Added in Linux 5.17 3511 // https://github.com/torvalds/linux/commit/c6018b4b254971863bd0ad36bb5e7d0fa0f0ddb0 3512 "SYS_set_mempolicy_home_node" => true, 3513 3514 // FIXME: Added in Linux 5.18 3515 // https://github.com/torvalds/linux/commit/8b5413647262dda8d8d0e07e14ea1de9ac7cf0b2 3516 "NFQA_PRIORITY" => true, 3517 3518 // FIXME: requires more recent kernel headers on CI 3519 | "UINPUT_VERSION" 3520 | "SW_MAX" 3521 | "SW_CNT" 3522 if mips || ppc64 || riscv64 || sparc64 => true, 3523 3524 // FIXME: Not currently available in headers on ARM, MIPS and musl. 3525 "NETLINK_GET_STRICT_CHK" if arm || mips || musl => true, 3526 3527 // kernel constants not available in uclibc 1.0.34 3528 | "EXTPROC" 3529 | "FAN_MARK_FILESYSTEM" 3530 | "FAN_MARK_INODE" 3531 | "IPPROTO_BEETPH" 3532 | "IPPROTO_MPLS" 3533 | "IPV6_HDRINCL" 3534 | "IPV6_MULTICAST_ALL" 3535 | "IPV6_PMTUDISC_INTERFACE" 3536 | "IPV6_PMTUDISC_OMIT" 3537 | "IPV6_ROUTER_ALERT_ISOLATE" 3538 | "PACKET_MR_UNICAST" 3539 | "RUSAGE_THREAD" 3540 | "SHM_EXEC" 3541 | "UDP_GRO" 3542 | "UDP_SEGMENT" 3543 if uclibc => true, 3544 3545 // headers conflicts with linux/pidfd.h 3546 "PIDFD_NONBLOCK" => true, 3547 3548 // is a private value for kernel usage normally 3549 "FUSE_SUPER_MAGIC" => true, 3550 3551 // linux 5.17 min 3552 "PR_SET_VMA" | "PR_SET_VMA_ANON_NAME" => true, 3553 3554 // present in recent kernels only 3555 "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, 3556 3557 // present in recent kernels only 3558 "PR_PAC_SET_ENABLED_KEYS" | "PR_PAC_GET_ENABLED_KEYS" => true, 3559 3560 // Added in Linux 5.14 3561 "FUTEX_LOCK_PI2" => true, 3562 3563 // FIXME: Parts of netfilter/nfnetlink*.h require more recent kernel headers: 3564 | "RTNLGRP_MCTP_IFADDR" // linux v5.17+ 3565 | "RTNLGRP_TUNNEL" // linux v5.18+ 3566 | "RTNLGRP_STATS" // linux v5.18+ 3567 => true, 3568 3569 // FIXME: The below is no longer const in glibc 2.34: 3570 // https://github.com/bminor/glibc/commit/5d98a7dae955bafa6740c26eaba9c86060ae0344 3571 | "PTHREAD_STACK_MIN" 3572 | "SIGSTKSZ" 3573 | "MINSIGSTKSZ" 3574 if gnu => true, 3575 3576 // FIXME: Linux >= 5.16 changed its value: 3577 // https://github.com/torvalds/linux/commit/42df6e1d221dddc0f2acf2be37e68d553ad65f96 3578 "NF_NETDEV_NUMHOOKS" => true, 3579 3580 // FIXME: requires Linux >= 5.6: 3581 | "RESOLVE_BENEATH" 3582 | "RESOLVE_CACHED" 3583 | "RESOLVE_IN_ROOT" 3584 | "RESOLVE_NO_MAGICLINKS" 3585 | "RESOLVE_NO_SYMLINKS" 3586 | "RESOLVE_NO_XDEV" if musl || sparc64 => true, 3587 3588 // FIXME: requires Linux >= 5.4: 3589 | "CAN_J1939" 3590 | "CAN_NPROTO" if musl || sparc64 => true, 3591 3592 // FIXME: requires Linux >= 5.6 3593 "GRND_INSECURE" if musl || sparc64 => true, 3594 3595 // FIXME: requires Linux >= 5.7: 3596 "MREMAP_DONTUNMAP" if musl || sparc64 => true, 3597 3598 // FIXME: Requires more recent kernel headers (5.9 / 5.11): 3599 | "CLOSE_RANGE_UNSHARE" 3600 | "CLOSE_RANGE_CLOEXEC" if musl || sparc64 => true, 3601 3602 // FIXME: requires Linux >= 5.12: 3603 "MPOL_F_NUMA_BALANCING" if musl || sparc64 => true, 3604 3605 // FIXME: Requires more recent kernel headers 3606 | "NFNL_SUBSYS_COUNT" // bumped in v5.14 3607 | "NFNL_SUBSYS_HOOK" // v5.14+ 3608 | "NFULA_VLAN" // v5.4+ 3609 | "NFULA_L2HDR" // v5.4+ 3610 | "NFULA_VLAN_PROTO" // v5.4+ 3611 | "NFULA_VLAN_TCI" // v5.4+ 3612 | "NFULA_VLAN_UNSPEC" // v5.4+ 3613 | "RTNLGRP_NEXTHOP" // linux v5.3+ 3614 | "RTNLGRP_BRVLAN" // linux v5.6+ 3615 if musl || sparc64 => true, 3616 3617 // FIXME: Unignore once we update Ubuntu to 22.04 3618 | "VMADDR_CID_LOCAL" 3619 | "STATX_MNT_ID" 3620 | "SYS_close_range" 3621 | "SYS_openat2" 3622 | "SYS_pidfd_getfd" 3623 | "SYS_faccessat2" 3624 | "SYS_process_madvise" 3625 | "SYS_epoll_pwait2" 3626 | "SYS_mount_setattr" 3627 | "SYS_quotactl_fd" 3628 | "SYS_landlock_create_ruleset" 3629 | "SYS_landlock_add_rule" 3630 | "SYS_landlock_restrict_self" 3631 | "SYS_process_mrelease" 3632 | "IFLA_PROP_LIST" 3633 | "IFLA_ALT_IFNAME" 3634 | "IFLA_PERM_ADDRESS" 3635 | "IFLA_PROTO_DOWN_REASON" 3636 | "STATX_ATTR_MOUNT_ROOT" 3637 | "STATX_ATTR_VERITY" 3638 | "STATX_ATTR_DAX" 3639 if sparc64 => true, 3640 // Added in Linux 5.13 3641 "PTRACE_GET_RSEQ_CONFIGURATION" if sparc64 => true, 3642 3643 // FIXME: Requires more recent kernel headers 3644 | "IFLA_PARENT_DEV_NAME" // linux v5.13+ 3645 | "IFLA_PARENT_DEV_BUS_NAME" // linux v5.13+ 3646 | "IFLA_GRO_MAX_SIZE" // linux v5.16+ 3647 | "IFLA_TSO_MAX_SIZE" // linux v5.18+ 3648 | "IFLA_TSO_MAX_SEGS" // linux v5.18+ 3649 | "IFLA_ALLMULTI" // linux v6.0+ 3650 => true, 3651 3652 _ => false, 3653 } 3654 }); 3655 3656 cfg.skip_fn(move |name| { 3657 // skip those that are manually verified 3658 match name { 3659 // FIXME: https://github.com/rust-lang/libc/issues/1272 3660 "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true, 3661 3662 // There are two versions of the sterror_r function, see 3663 // 3664 // https://linux.die.net/man/3/strerror_r 3665 // 3666 // An XSI-compliant version provided if: 3667 // 3668 // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) 3669 // && ! _GNU_SOURCE 3670 // 3671 // and a GNU specific version provided if _GNU_SOURCE is defined. 3672 // 3673 // libc provides bindings for the XSI-compliant version, which is 3674 // preferred for portable applications. 3675 // 3676 // We skip the test here since here _GNU_SOURCE is defined, and 3677 // test the XSI version below. 3678 "strerror_r" => true, 3679 3680 // FIXME: Our API is unsound. The Rust API allows aliasing 3681 // pointers, but the C API requires pointers not to alias. 3682 // We should probably be at least using `&`/`&mut` here, see: 3683 // https://github.com/gnzlbg/ctest/issues/68 3684 "lio_listio" if musl => true, 3685 3686 // FIXME: the glibc version used by the Sparc64 build jobs 3687 // which use Debian 10.0 is too old. 3688 "statx" if sparc64 => true, 3689 3690 // FIXME: Deprecated since glibc 2.30. Remove fn once upstream does. 3691 "sysctl" if gnu => true, 3692 3693 // FIXME: It now takes c_void instead of timezone since glibc 2.31. 3694 "gettimeofday" if gnu => true, 3695 3696 // These are all implemented as static inline functions in uclibc, so 3697 // they cannot be linked against. 3698 // If implementations are required, they might need to be implemented 3699 // in this crate. 3700 "posix_spawnattr_init" if uclibc => true, 3701 "posix_spawnattr_destroy" if uclibc => true, 3702 "posix_spawnattr_getsigdefault" if uclibc => true, 3703 "posix_spawnattr_setsigdefault" if uclibc => true, 3704 "posix_spawnattr_getsigmask" if uclibc => true, 3705 "posix_spawnattr_setsigmask" if uclibc => true, 3706 "posix_spawnattr_getflags" if uclibc => true, 3707 "posix_spawnattr_setflags" if uclibc => true, 3708 "posix_spawnattr_getpgroup" if uclibc => true, 3709 "posix_spawnattr_setpgroup" if uclibc => true, 3710 "posix_spawnattr_getschedpolicy" if uclibc => true, 3711 "posix_spawnattr_setschedpolicy" if uclibc => true, 3712 "posix_spawnattr_getschedparam" if uclibc => true, 3713 "posix_spawnattr_setschedparam" if uclibc => true, 3714 "posix_spawn_file_actions_init" if uclibc => true, 3715 "posix_spawn_file_actions_destroy" if uclibc => true, 3716 3717 // uclibc defines the flags type as a uint, but dependent crates 3718 // assume it's a int instead. 3719 "getnameinfo" if uclibc => true, 3720 3721 // FIXME: This needs musl 1.2.2 or later. 3722 "gettid" if musl => true, 3723 3724 // Needs glibc 2.33 or later. 3725 "mallinfo2" => true, 3726 3727 "reallocarray" if musl => true, 3728 3729 // Not defined in uclibc as of 1.0.34 3730 "gettid" if uclibc => true, 3731 3732 // Needs musl 1.2.3 or later. 3733 "pthread_getname_np" if musl => true, 3734 3735 // pthread_sigqueue uses sigval, which was initially declared 3736 // as a struct but should be defined as a union. However due 3737 // to the issues described here: https://github.com/rust-lang/libc/issues/2816 3738 // it can't be changed from struct. 3739 "pthread_sigqueue" => true, 3740 3741 // There are two versions of basename(3) on Linux with glibc, see 3742 // 3743 // https://man7.org/linux/man-pages/man3/basename.3.html 3744 // 3745 // If libgen.h is included, then the POSIX version will be available; 3746 // If _GNU_SOURCE is defined and string.h is included, then the GNU one 3747 // will be used. 3748 // 3749 // libc exposes both of them, providing a prefix to differentiate between 3750 // them. 3751 // 3752 // Because the name with prefix is not a valid symbol in C, we have to 3753 // skip the tests. 3754 "posix_basename" if gnu => true, 3755 "gnu_basename" if gnu => true, 3756 3757 _ => false, 3758 } 3759 }); 3760 3761 cfg.skip_field_type(move |struct_, field| { 3762 // This is a weird union, don't check the type. 3763 (struct_ == "ifaddrs" && field == "ifa_ifu") || 3764 // sighandler_t type is super weird 3765 (struct_ == "sigaction" && field == "sa_sigaction") || 3766 // __timeval type is a patch which doesn't exist in glibc 3767 (struct_ == "utmpx" && field == "ut_tv") || 3768 // sigval is actually a union, but we pretend it's a struct 3769 (struct_ == "sigevent" && field == "sigev_value") || 3770 // this one is an anonymous union 3771 (struct_ == "ff_effect" && field == "u") || 3772 // `__exit_status` type is a patch which is absent in musl 3773 (struct_ == "utmpx" && field == "ut_exit" && musl) || 3774 // `can_addr` is an anonymous union 3775 (struct_ == "sockaddr_can" && field == "can_addr") 3776 }); 3777 3778 cfg.volatile_item(|i| { 3779 use ctest::VolatileItemKind::*; 3780 match i { 3781 // aio_buf is a volatile void** but since we cannot express that in 3782 // Rust types, we have to explicitly tell the checker about it here: 3783 StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true, 3784 _ => false, 3785 } 3786 }); 3787 3788 cfg.skip_field(move |struct_, field| { 3789 // this is actually a union on linux, so we can't represent it well and 3790 // just insert some padding. 3791 (struct_ == "siginfo_t" && field == "_pad") || 3792 // musl names this __dummy1 but it's still there 3793 (musl && struct_ == "glob_t" && field == "gl_flags") || 3794 // musl seems to define this as an *anonymous* bitfield 3795 (musl && struct_ == "statvfs" && field == "__f_unused") || 3796 // sigev_notify_thread_id is actually part of a sigev_un union 3797 (struct_ == "sigevent" && field == "sigev_notify_thread_id") || 3798 // signalfd had SIGSYS fields added in Linux 4.18, but no libc release 3799 // has them yet. 3800 (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || 3801 field == "_pad2" || 3802 field == "ssi_syscall" || 3803 field == "ssi_call_addr" || 3804 field == "ssi_arch")) || 3805 // FIXME: After musl 1.1.24, it have only one field `sched_priority`, 3806 // while other fields become reserved. 3807 (struct_ == "sched_param" && [ 3808 "sched_ss_low_priority", 3809 "sched_ss_repl_period", 3810 "sched_ss_init_budget", 3811 "sched_ss_max_repl", 3812 ].contains(&field) && musl) || 3813 // FIXME: After musl 1.1.24, the type becomes `int` instead of `unsigned short`. 3814 (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) || 3815 // glibc uses unnamed fields here and Rust doesn't support that yet 3816 (struct_ == "timex" && field.starts_with("__unused")) || 3817 // FIXME: It now takes mode_t since glibc 2.31 on some targets. 3818 (struct_ == "ipc_perm" && field == "mode" 3819 && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32) 3820 ) || 3821 // the `u` field is in fact an anonymous union 3822 (gnu && struct_ == "ptrace_syscall_info" && (field == "u" || field == "pad")) || 3823 // the vregs field is a `__uint128_t` C's type. 3824 (struct_ == "user_fpsimd_struct" && field == "vregs") || 3825 // Linux >= 5.11 tweaked the `svm_zero` field of the `sockaddr_vm` struct. 3826 // https://github.com/torvalds/linux/commit/dc8eeef73b63ed8988224ba6b5ed19a615163a7f 3827 (struct_ == "sockaddr_vm" && field == "svm_zero") || 3828 // the `ifr_ifru` field is an anonymous union 3829 (struct_ == "ifreq" && field == "ifr_ifru") 3830 }); 3831 3832 cfg.skip_roundtrip(move |s| match s { 3833 // FIXME: 3834 "utsname" if mips32 || mips64 => true, 3835 // FIXME: 3836 "mcontext_t" if s390x => true, 3837 // FIXME: This is actually a union. 3838 "fpreg_t" if s390x => true, 3839 3840 "sockaddr_un" | "sembuf" | "ff_constant_effect" if mips32 && (gnu || musl) => true, 3841 "ipv6_mreq" 3842 | "ip_mreq_source" 3843 | "sockaddr_in6" 3844 | "sockaddr_ll" 3845 | "in_pktinfo" 3846 | "arpreq" 3847 | "arpreq_old" 3848 | "sockaddr_un" 3849 | "ff_constant_effect" 3850 | "ff_ramp_effect" 3851 | "ff_condition_effect" 3852 | "Elf32_Ehdr" 3853 | "Elf32_Chdr" 3854 | "ucred" 3855 | "in6_pktinfo" 3856 | "sockaddr_nl" 3857 | "termios" 3858 | "nlmsgerr" 3859 if (mips64 || sparc64) && gnu => 3860 { 3861 true 3862 } 3863 3864 // FIXME: the call ABI of max_align_t is incorrect on these platforms: 3865 "max_align_t" if i686 || mips64 || ppc64 => true, 3866 3867 _ => false, 3868 }); 3869 3870 cfg.generate("../src/lib.rs", "main.rs"); 3871 3872 test_linux_like_apis(target); 3873 } 3874 3875 // This function tests APIs that are incompatible to test when other APIs 3876 // are included (e.g. because including both sets of headers clashes) 3877 fn test_linux_like_apis(target: &str) { 3878 let gnu = target.contains("gnu"); 3879 let musl = target.contains("musl"); 3880 let linux = target.contains("linux"); 3881 let emscripten = target.contains("emscripten"); 3882 let android = target.contains("android"); 3883 assert!(linux || android || emscripten); 3884 3885 if linux || android || emscripten { 3886 // test strerror_r from the `string.h` header 3887 let mut cfg = ctest_cfg(); 3888 cfg.skip_type(|_| true).skip_static(|_| true); 3889 3890 headers! { cfg: "string.h" } 3891 cfg.skip_fn(|f| match f { 3892 "strerror_r" => false, 3893 _ => true, 3894 }) 3895 .skip_const(|_| true) 3896 .skip_struct(|_| true); 3897 cfg.generate("../src/lib.rs", "linux_strerror_r.rs"); 3898 } 3899 3900 if linux || android || emscripten { 3901 // test fcntl - see: 3902 // http://man7.org/linux/man-pages/man2/fcntl.2.html 3903 let mut cfg = ctest_cfg(); 3904 3905 if musl { 3906 cfg.header("fcntl.h"); 3907 } else { 3908 cfg.header("linux/fcntl.h"); 3909 } 3910 3911 cfg.skip_type(|_| true) 3912 .skip_static(|_| true) 3913 .skip_struct(|_| true) 3914 .skip_fn(|_| true) 3915 .skip_const(move |name| match name { 3916 // test fcntl constants: 3917 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" 3918 | "F_SEAL_GROW" | "F_SEAL_WRITE" => false, 3919 _ => true, 3920 }) 3921 .type_name(move |ty, is_struct, is_union| match ty { 3922 t if is_struct => format!("struct {}", t), 3923 t if is_union => format!("union {}", t), 3924 t => t.to_string(), 3925 }); 3926 3927 cfg.generate("../src/lib.rs", "linux_fcntl.rs"); 3928 } 3929 3930 if linux || android { 3931 // test termios 3932 let mut cfg = ctest_cfg(); 3933 cfg.header("asm/termbits.h"); 3934 cfg.header("linux/termios.h"); 3935 cfg.skip_type(|_| true) 3936 .skip_static(|_| true) 3937 .skip_fn(|_| true) 3938 .skip_const(|c| match c { 3939 "BOTHER" | "IBSHIFT" => false, 3940 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => false, 3941 _ => true, 3942 }) 3943 .skip_struct(|s| s != "termios2") 3944 .type_name(move |ty, is_struct, is_union| match ty { 3945 "Ioctl" if gnu => "unsigned long".to_string(), 3946 "Ioctl" => "int".to_string(), 3947 t if is_struct => format!("struct {}", t), 3948 t if is_union => format!("union {}", t), 3949 t => t.to_string(), 3950 }); 3951 cfg.generate("../src/lib.rs", "linux_termios.rs"); 3952 } 3953 3954 if linux || android { 3955 // test IPV6_ constants: 3956 let mut cfg = ctest_cfg(); 3957 headers! { 3958 cfg: 3959 "linux/in6.h" 3960 } 3961 cfg.skip_type(|_| true) 3962 .skip_static(|_| true) 3963 .skip_fn(|_| true) 3964 .skip_const(|_| true) 3965 .skip_struct(|_| true) 3966 .skip_const(move |name| match name { 3967 "IPV6_FLOWINFO" 3968 | "IPV6_FLOWLABEL_MGR" 3969 | "IPV6_FLOWINFO_SEND" 3970 | "IPV6_FLOWINFO_FLOWLABEL" 3971 | "IPV6_FLOWINFO_PRIORITY" => false, 3972 _ => true, 3973 }) 3974 .type_name(move |ty, is_struct, is_union| match ty { 3975 t if is_struct => format!("struct {}", t), 3976 t if is_union => format!("union {}", t), 3977 t => t.to_string(), 3978 }); 3979 cfg.generate("../src/lib.rs", "linux_ipv6.rs"); 3980 } 3981 3982 if linux || android { 3983 // Test Elf64_Phdr and Elf32_Phdr 3984 // These types have a field called `p_type`, but including 3985 // "resolve.h" defines a `p_type` macro that expands to `__p_type` 3986 // making the tests for these fails when both are included. 3987 let mut cfg = ctest_cfg(); 3988 cfg.header("elf.h"); 3989 cfg.skip_fn(|_| true) 3990 .skip_static(|_| true) 3991 .skip_const(|_| true) 3992 .type_name(move |ty, _is_struct, _is_union| ty.to_string()) 3993 .skip_struct(move |ty| match ty { 3994 "Elf64_Phdr" | "Elf32_Phdr" => false, 3995 _ => true, 3996 }) 3997 .skip_type(move |ty| match ty { 3998 "Elf64_Phdr" | "Elf32_Phdr" => false, 3999 _ => true, 4000 }); 4001 cfg.generate("../src/lib.rs", "linux_elf.rs"); 4002 } 4003 4004 if linux || android { 4005 // Test `ARPHRD_CAN`. 4006 let mut cfg = ctest_cfg(); 4007 cfg.header("linux/if_arp.h"); 4008 cfg.skip_fn(|_| true) 4009 .skip_static(|_| true) 4010 .skip_const(move |name| match name { 4011 "ARPHRD_CAN" => false, 4012 _ => true, 4013 }) 4014 .skip_struct(|_| true) 4015 .skip_type(|_| true); 4016 cfg.generate("../src/lib.rs", "linux_if_arp.rs"); 4017 } 4018 } 4019 4020 fn which_freebsd() -> Option<i32> { 4021 let output = std::process::Command::new("freebsd-version") 4022 .output() 4023 .ok()?; 4024 if !output.status.success() { 4025 return None; 4026 } 4027 4028 let stdout = String::from_utf8(output.stdout).ok()?; 4029 4030 match &stdout { 4031 s if s.starts_with("10") => Some(10), 4032 s if s.starts_with("11") => Some(11), 4033 s if s.starts_with("12") => Some(12), 4034 s if s.starts_with("13") => Some(13), 4035 s if s.starts_with("14") => Some(14), 4036 _ => None, 4037 } 4038 } 4039 4040 fn test_haiku(target: &str) { 4041 assert!(target.contains("haiku")); 4042 4043 let mut cfg = ctest_cfg(); 4044 cfg.flag("-Wno-deprecated-declarations"); 4045 cfg.define("__USE_GNU", Some("1")); 4046 cfg.define("_GNU_SOURCE", None); 4047 cfg.language(ctest::Lang::CXX); 4048 4049 // POSIX API 4050 headers! { cfg: 4051 "alloca.h", 4052 "arpa/inet.h", 4053 "arpa/nameser.h", 4054 "arpa/nameser_compat.h", 4055 "assert.h", 4056 "bsd_mem.h", 4057 "complex.h", 4058 "ctype.h", 4059 "dirent.h", 4060 "div_t.h", 4061 "dlfcn.h", 4062 "endian.h", 4063 "errno.h", 4064 "fcntl.h", 4065 "fenv.h", 4066 "fnmatch.h", 4067 "fts.h", 4068 "ftw.h", 4069 "getopt.h", 4070 "glob.h", 4071 "grp.h", 4072 "inttypes.h", 4073 "iovec.h", 4074 "langinfo.h", 4075 "libgen.h", 4076 "libio.h", 4077 "limits.h", 4078 "locale.h", 4079 "malloc.h", 4080 "malloc_debug.h", 4081 "math.h", 4082 "memory.h", 4083 "monetary.h", 4084 "net/if.h", 4085 "net/if_dl.h", 4086 "net/if_media.h", 4087 "net/if_tun.h", 4088 "net/if_types.h", 4089 "net/route.h", 4090 "netdb.h", 4091 "netinet/in.h", 4092 "netinet/ip.h", 4093 "netinet/ip6.h", 4094 "netinet/ip_icmp.h", 4095 "netinet/ip_var.h", 4096 "netinet/tcp.h", 4097 "netinet/udp.h", 4098 "netinet6/in6.h", 4099 "nl_types.h", 4100 "null.h", 4101 "poll.h", 4102 "pthread.h", 4103 "pwd.h", 4104 "regex.h", 4105 "resolv.h", 4106 "sched.h", 4107 "search.h", 4108 "semaphore.h", 4109 "setjmp.h", 4110 "shadow.h", 4111 "signal.h", 4112 "size_t.h", 4113 "spawn.h", 4114 "stdint.h", 4115 "stdio.h", 4116 "stdlib.h", 4117 "string.h", 4118 "strings.h", 4119 "sys/cdefs.h", 4120 "sys/file.h", 4121 "sys/ioctl.h", 4122 "sys/ipc.h", 4123 "sys/mman.h", 4124 "sys/msg.h", 4125 "sys/param.h", 4126 "sys/poll.h", 4127 "sys/resource.h", 4128 "sys/select.h", 4129 "sys/sem.h", 4130 "sys/socket.h", 4131 "sys/sockio.h", 4132 "sys/stat.h", 4133 "sys/statvfs.h", 4134 "sys/time.h", 4135 "sys/timeb.h", 4136 "sys/times.h", 4137 "sys/types.h", 4138 "sys/uio.h", 4139 "sys/un.h", 4140 "sys/utsname.h", 4141 "sys/wait.h", 4142 "syslog.h", 4143 "tar.h", 4144 "termios.h", 4145 "time.h", 4146 "uchar.h", 4147 "unistd.h", 4148 "utime.h", 4149 "utmpx.h", 4150 "wchar.h", 4151 "wchar_t.h", 4152 "wctype.h" 4153 } 4154 4155 // BSD Extensions 4156 headers! { cfg: 4157 "ifaddrs.h", 4158 "libutil.h", 4159 "link.h", 4160 "pty.h", 4161 } 4162 4163 // Native API 4164 headers! { cfg: 4165 "kernel/OS.h", 4166 "kernel/fs_attr.h", 4167 "kernel/fs_index.h", 4168 "kernel/fs_info.h", 4169 "kernel/fs_query.h", 4170 "kernel/fs_volume.h", 4171 "kernel/image.h", 4172 "kernel/scheduler.h", 4173 "storage/FindDirectory.h", 4174 "storage/StorageDefs.h", 4175 "support/Errors.h", 4176 "support/SupportDefs.h", 4177 "support/TypeConstants.h" 4178 } 4179 4180 cfg.skip_struct(move |ty| { 4181 if ty.starts_with("__c_anonymous_") { 4182 return true; 4183 } 4184 match ty { 4185 // FIXME: actually a union 4186 "sigval" => true, 4187 // FIXME: locale_t does not exist on Haiku 4188 "locale_t" => true, 4189 // FIXME: rusage has a different layout on Haiku 4190 "rusage" => true, 4191 // FIXME?: complains that rust aligns on 4 byte boundary, but 4192 // Haiku does not align it at all. 4193 "in6_addr" => true, 4194 // The d_name attribute is an array of 1 on Haiku, with the 4195 // intention that the developer allocates a larger or smaller 4196 // piece of memory depending on the expected/actual size of the name. 4197 // Other platforms have sensible defaults. In Rust, the d_name field 4198 // is sized as the _POSIX_MAX_PATH, so that path names will fit in 4199 // newly allocated dirent objects. This breaks the automated tests. 4200 "dirent" => true, 4201 // The following structs contain function pointers, which cannot be initialized 4202 // with mem::zeroed(), so skip the automated test 4203 "image_info" | "thread_info" => true, 4204 4205 "Elf64_Phdr" => true, 4206 4207 // is an union 4208 "cpuid_info" => true, 4209 4210 _ => false, 4211 } 4212 }); 4213 4214 cfg.skip_type(move |ty| { 4215 match ty { 4216 // FIXME: locale_t does not exist on Haiku 4217 "locale_t" => true, 4218 // These cause errors, to be reviewed in the future 4219 "sighandler_t" => true, 4220 "pthread_t" => true, 4221 "pthread_condattr_t" => true, 4222 "pthread_mutexattr_t" => true, 4223 "pthread_rwlockattr_t" => true, 4224 _ => false, 4225 } 4226 }); 4227 4228 cfg.skip_fn(move |name| { 4229 // skip those that are manually verified 4230 match name { 4231 // FIXME: https://github.com/rust-lang/libc/issues/1272 4232 "execv" | "execve" | "execvp" | "execvpe" => true, 4233 // FIXME: does not exist on haiku 4234 "open_wmemstream" => true, 4235 "mlockall" | "munlockall" => true, 4236 "tcgetsid" => true, 4237 "cfsetspeed" => true, 4238 // ignore for now, will be part of Haiku R1 beta 3 4239 "mlock" | "munlock" => true, 4240 // returns const char * on Haiku 4241 "strsignal" => true, 4242 // uses an enum as a parameter argument, which is incorrectly 4243 // translated into a struct argument 4244 "find_path" => true, 4245 4246 "get_cpuid" => true, 4247 4248 // uses varargs parameter 4249 "ioctl" => true, 4250 4251 _ => false, 4252 } 4253 }); 4254 4255 cfg.skip_const(move |name| { 4256 match name { 4257 // FIXME: these constants do not exist on Haiku 4258 "DT_UNKNOWN" | "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" 4259 | "DT_SOCK" => true, 4260 "USRQUOTA" | "GRPQUOTA" => true, 4261 "SIGIOT" => true, 4262 "ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM" | "ATF_PUBL" 4263 | "ATF_USETRAILERS" => true, 4264 // Haiku does not have MAP_FILE, but rustc requires it 4265 "MAP_FILE" => true, 4266 // The following does not exist on Haiku but is required by 4267 // several crates 4268 "FIOCLEX" => true, 4269 // just skip this one, it is not defined on Haiku beta 2 but 4270 // since it is meant as a mask and not a parameter it can exist 4271 // here 4272 "LOG_PRIMASK" => true, 4273 // not defined on Haiku, but [get|set]priority is, so they are 4274 // useful 4275 "PRIO_MIN" | "PRIO_MAX" => true, 4276 // 4277 _ => false, 4278 } 4279 }); 4280 4281 cfg.skip_field(move |struct_, field| { 4282 match (struct_, field) { 4283 // FIXME: the stat struct actually has timespec members, whereas 4284 // the current representation has these unpacked. 4285 ("stat", "st_atime") => true, 4286 ("stat", "st_atime_nsec") => true, 4287 ("stat", "st_mtime") => true, 4288 ("stat", "st_mtime_nsec") => true, 4289 ("stat", "st_ctime") => true, 4290 ("stat", "st_ctime_nsec") => true, 4291 ("stat", "st_crtime") => true, 4292 ("stat", "st_crtime_nsec") => true, 4293 4294 // these are actually unions, but we cannot represent it well 4295 ("siginfo_t", "sigval") => true, 4296 ("sem_t", "named_sem_id") => true, 4297 ("sigaction", "sa_sigaction") => true, 4298 ("sigevent", "sigev_value") => true, 4299 ("fpu_state", "_fpreg") => true, 4300 // these fields have a simplified data definition in libc 4301 ("fpu_state", "_xmm") => true, 4302 ("savefpu", "_fp_ymm") => true, 4303 4304 // skip these enum-type fields 4305 ("thread_info", "state") => true, 4306 ("image_info", "image_type") => true, 4307 _ => false, 4308 } 4309 }); 4310 4311 cfg.skip_roundtrip(move |s| match s { 4312 // FIXME: for some reason the roundtrip check fails for cpu_info 4313 "cpu_info" => true, 4314 _ => false, 4315 }); 4316 4317 cfg.type_name(move |ty, is_struct, is_union| { 4318 match ty { 4319 // Just pass all these through, no need for a "struct" prefix 4320 "area_info" | "port_info" | "port_message_info" | "team_info" | "sem_info" 4321 | "team_usage_info" | "thread_info" | "cpu_info" | "system_info" 4322 | "object_wait_info" | "image_info" | "attr_info" | "index_info" | "fs_info" 4323 | "FILE" | "DIR" | "Dl_info" => ty.to_string(), 4324 4325 // enums don't need a prefix 4326 "directory_which" | "path_base_directory" => ty.to_string(), 4327 4328 // is actually a union 4329 "sigval" => format!("union sigval"), 4330 t if is_union => format!("union {}", t), 4331 t if t.ends_with("_t") => t.to_string(), 4332 t if is_struct => format!("struct {}", t), 4333 t => t.to_string(), 4334 } 4335 }); 4336 4337 cfg.field_name(move |struct_, field| { 4338 match field { 4339 // Field is named `type` in C but that is a Rust keyword, 4340 // so these fields are translated to `type_` in the bindings. 4341 "type_" if struct_ == "object_wait_info" => "type".to_string(), 4342 "type_" if struct_ == "sem_t" => "type".to_string(), 4343 "type_" if struct_ == "attr_info" => "type".to_string(), 4344 "type_" if struct_ == "index_info" => "type".to_string(), 4345 "image_type" if struct_ == "image_info" => "type".to_string(), 4346 s => s.to_string(), 4347 } 4348 }); 4349 cfg.generate("../src/lib.rs", "main.rs"); 4350 } 4351