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