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