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