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