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