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