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