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