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