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