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