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