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