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