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