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