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