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