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