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