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