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