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