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