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