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