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