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