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