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