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