xref: /rust-libc-0.2.174/libc-test/build.rs (revision 8592ff94)
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_MCE_PROCESS"
2066             | "PF_SUPERPRIV"
2067             | "PF_DUMPCORE"
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_BLOCK_TS"
2084             | "PF_SUSPEND_TASK" => true,
2085 
2086             _ => false,
2087         }
2088     });
2089 
2090     cfg.skip_fn(move |name| {
2091         // skip those that are manually verified
2092         match name {
2093             // FIXME: https://github.com/rust-lang/libc/issues/1272
2094             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
2095 
2096             // There are two versions of the sterror_r function, see
2097             //
2098             // https://linux.die.net/man/3/strerror_r
2099             //
2100             // An XSI-compliant version provided if:
2101             //
2102             // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
2103             //
2104             // and a GNU specific version provided if _GNU_SOURCE is defined.
2105             //
2106             // libc provides bindings for the XSI-compliant version, which is
2107             // preferred for portable applications.
2108             //
2109             // We skip the test here since here _GNU_SOURCE is defined, and
2110             // test the XSI version below.
2111             "strerror_r" => true,
2112             "reallocarray" => true,
2113             "__system_property_wait" => true,
2114 
2115             // Added in API level 30, but tests use level 28.
2116             "memfd_create" | "mlock2" | "renameat2" | "statx" | "statx_timestamp" => true,
2117 
2118             // Added in glibc 2.25.
2119             "getentropy" => true,
2120 
2121             // Added in API level 28, but some tests use level 24.
2122             "getrandom" => true,
2123 
2124             // Added in API level 28, but some tests use level 24.
2125             "syncfs" => true,
2126 
2127             // Added in API level 28, but some tests use level 24.
2128             "pthread_attr_getinheritsched" | "pthread_attr_setinheritsched" => true,
2129             // Added in API level 28, but some tests use level 24.
2130             "fread_unlocked" | "fwrite_unlocked" | "fgets_unlocked" | "fflush_unlocked" => true,
2131 
2132             // Added in API level 28, but some tests use level 24.
2133             "aligned_alloc" => true,
2134 
2135             // Added in API level 26, but some tests use level 24.
2136             "getgrent" => true,
2137 
2138             // Added in API level 26, but some tests use level 24.
2139             "setgrent" => true,
2140 
2141             // Added in API level 26, but some tests use level 24.
2142             "endgrent" => true,
2143 
2144             // FIXME: bad function pointers:
2145             "isalnum" | "isalpha" | "iscntrl" | "isdigit" | "isgraph" | "islower" | "isprint"
2146             | "ispunct" | "isspace" | "isupper" | "isxdigit" | "isblank" | "tolower"
2147             | "toupper" => true,
2148 
2149             _ => false,
2150         }
2151     });
2152 
2153     cfg.skip_field_type(move |struct_, field| {
2154         // This is a weird union, don't check the type.
2155         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
2156         // sigval is actually a union, but we pretend it's a struct
2157         (struct_ == "sigevent" && field == "sigev_value") ||
2158         // this one is an anonymous union
2159         (struct_ == "ff_effect" && field == "u") ||
2160         // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
2161         // incorrect, see: https://github.com/rust-lang/libc/issues/1359
2162         (struct_ == "sigaction" && field == "sa_sigaction") ||
2163         // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet.
2164         (struct_ == "signalfd_siginfo" && field == "ssi_call_addr") ||
2165         // FIXME: Seems the type has been changed on NDK r26b
2166         (struct_ == "flock64" && (field == "l_start" || field == "l_len"))
2167     });
2168 
2169     cfg.skip_field(|struct_, field| {
2170         match (struct_, field) {
2171             // conflicting with `p_type` macro from <resolve.h>.
2172             ("Elf32_Phdr", "p_type") => true,
2173             ("Elf64_Phdr", "p_type") => true,
2174 
2175             // this is actually a union on linux, so we can't represent it well and
2176             // just insert some padding.
2177             ("siginfo_t", "_pad") => true,
2178             ("ifreq", "ifr_ifru") => true,
2179             ("ifconf", "ifc_ifcu") => true,
2180 
2181             _ => false,
2182         }
2183     });
2184 
2185     cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs");
2186 
2187     test_linux_like_apis(target);
2188 }
2189 
2190 fn test_freebsd(target: &str) {
2191     assert!(target.contains("freebsd"));
2192     let mut cfg = ctest_cfg();
2193 
2194     let freebsd_ver = which_freebsd();
2195 
2196     match freebsd_ver {
2197         Some(12) => cfg.cfg("freebsd12", None),
2198         Some(13) => cfg.cfg("freebsd13", None),
2199         Some(14) => cfg.cfg("freebsd14", None),
2200         Some(15) => cfg.cfg("freebsd15", None),
2201         _ => &mut cfg,
2202     };
2203 
2204     // For sched linux compat fn
2205     cfg.define("_WITH_CPU_SET_T", None);
2206     // Required for `getline`:
2207     cfg.define("_WITH_GETLINE", None);
2208     // Required for making freebsd11_stat available in the headers
2209     cfg.define("_WANT_FREEBSD11_STAT", None);
2210 
2211     let freebsd13 = match freebsd_ver {
2212         Some(n) if n >= 13 => true,
2213         _ => false,
2214     };
2215     let freebsd14 = match freebsd_ver {
2216         Some(n) if n >= 14 => true,
2217         _ => false,
2218     };
2219     let freebsd15 = match freebsd_ver {
2220         Some(n) if n >= 15 => true,
2221         _ => false,
2222     };
2223 
2224     headers! { cfg:
2225                 "aio.h",
2226                 "arpa/inet.h",
2227                 "bsm/audit.h",
2228                 "ctype.h",
2229                 "dirent.h",
2230                 "dlfcn.h",
2231                 "elf.h",
2232                 "errno.h",
2233                 "execinfo.h",
2234                 "fcntl.h",
2235                 "fnmatch.h",
2236                 "getopt.h",
2237                 "glob.h",
2238                 "grp.h",
2239                 "iconv.h",
2240                 "ifaddrs.h",
2241                 "kenv.h",
2242                 "langinfo.h",
2243                 "libgen.h",
2244                 "libutil.h",
2245                 "limits.h",
2246                 "link.h",
2247                 "locale.h",
2248                 "machine/elf.h",
2249                 "machine/reg.h",
2250                 "malloc_np.h",
2251                 "memstat.h",
2252                 "mqueue.h",
2253                 "net/bpf.h",
2254                 "net/if.h",
2255                 "net/if_arp.h",
2256                 "net/if_dl.h",
2257                 "net/if_mib.h",
2258                 "net/route.h",
2259                 "netdb.h",
2260                 "netinet/ip.h",
2261                 "netinet/in.h",
2262                 "netinet/sctp.h",
2263                 "netinet/tcp.h",
2264                 "netinet/udp.h",
2265                 "poll.h",
2266                 "pthread.h",
2267                 "pthread_np.h",
2268                 "pwd.h",
2269                 "regex.h",
2270                 "resolv.h",
2271                 "sched.h",
2272                 "semaphore.h",
2273                 "signal.h",
2274                 "spawn.h",
2275                 "stddef.h",
2276                 "stdint.h",
2277                 "stdio.h",
2278                 "stdlib.h",
2279                 "string.h",
2280                 "sys/capsicum.h",
2281                 "sys/auxv.h",
2282                 "sys/cpuset.h",
2283                 "sys/domainset.h",
2284                 "sys/eui64.h",
2285                 "sys/event.h",
2286                 [freebsd13]:"sys/eventfd.h",
2287                 "sys/extattr.h",
2288                 "sys/file.h",
2289                 "sys/ioctl.h",
2290                 "sys/ipc.h",
2291                 "sys/jail.h",
2292                 "sys/mman.h",
2293                 "sys/mount.h",
2294                 "sys/msg.h",
2295                 "sys/procctl.h",
2296                 "sys/procdesc.h",
2297                 "sys/ptrace.h",
2298                 "sys/queue.h",
2299                 "sys/random.h",
2300                 "sys/reboot.h",
2301                 "sys/resource.h",
2302                 "sys/rtprio.h",
2303                 "sys/sem.h",
2304                 "sys/shm.h",
2305                 "sys/socket.h",
2306                 "sys/stat.h",
2307                 "sys/statvfs.h",
2308                 "sys/sysctl.h",
2309                 "sys/thr.h",
2310                 "sys/time.h",
2311                 [freebsd14 || freebsd15]:"sys/timerfd.h",
2312                 "sys/times.h",
2313                 "sys/timex.h",
2314                 "sys/types.h",
2315                 "sys/proc.h",
2316                 "kvm.h", // must be after "sys/types.h"
2317                 "sys/ucontext.h",
2318                 "sys/uio.h",
2319                 "sys/ktrace.h",
2320                 "sys/umtx.h",
2321                 "sys/un.h",
2322                 "sys/user.h",
2323                 "sys/utsname.h",
2324                 "sys/uuid.h",
2325                 "sys/vmmeter.h",
2326                 "sys/wait.h",
2327                 "libprocstat.h",
2328                 "devstat.h",
2329                 "syslog.h",
2330                 "termios.h",
2331                 "time.h",
2332                 "ufs/ufs/quota.h",
2333                 "unistd.h",
2334                 "utime.h",
2335                 "utmpx.h",
2336                 "wchar.h",
2337     }
2338 
2339     cfg.type_name(move |ty, is_struct, is_union| {
2340         match ty {
2341             // Just pass all these through, no need for a "struct" prefix
2342             "FILE"
2343             | "fd_set"
2344             | "Dl_info"
2345             | "DIR"
2346             | "Elf32_Phdr"
2347             | "Elf64_Phdr"
2348             | "Elf32_Auxinfo"
2349             | "Elf64_Auxinfo"
2350             | "devstat_select_mode"
2351             | "devstat_support_flags"
2352             | "devstat_type_flags"
2353             | "devstat_match_flags"
2354             | "devstat_priority" => ty.to_string(),
2355 
2356             // FIXME: https://github.com/rust-lang/libc/issues/1273
2357             "sighandler_t" => "sig_t".to_string(),
2358 
2359             t if is_union => format!("union {}", t),
2360 
2361             t if t.ends_with("_t") => t.to_string(),
2362 
2363             // sigval is a struct in Rust, but a union in C:
2364             "sigval" => format!("union sigval"),
2365 
2366             // put `struct` in front of all structs:.
2367             t if is_struct => format!("struct {}", t),
2368 
2369             t => t.to_string(),
2370         }
2371     });
2372 
2373     cfg.field_name(move |struct_, field| {
2374         match field {
2375             // Our stat *_nsec fields normally don't actually exist but are part
2376             // of a timeval struct
2377             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
2378                 s.replace("e_nsec", ".tv_nsec")
2379             }
2380             // Field is named `type` in C but that is a Rust keyword,
2381             // so these fields are translated to `type_` in the bindings.
2382             "type_" if struct_ == "rtprio" => "type".to_string(),
2383             "type_" if struct_ == "sockstat" => "type".to_string(),
2384             "type_" if struct_ == "devstat_match_table" => "type".to_string(),
2385             s => s.to_string(),
2386         }
2387     });
2388 
2389     cfg.skip_const(move |name| {
2390         match name {
2391             // These constants were introduced in FreeBSD 13:
2392             "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW"
2393             | "F_SEAL_WRITE"
2394                 if Some(13) > freebsd_ver =>
2395             {
2396                 true
2397             }
2398 
2399             // These constants were introduced in FreeBSD 13:
2400             "EFD_CLOEXEC" | "EFD_NONBLOCK" | "EFD_SEMAPHORE" if Some(13) > freebsd_ver => true,
2401 
2402             // These constants were introduced in FreeBSD 12:
2403             "AT_RESOLVE_BENEATH" | "O_RESOLVE_BENEATH" if Some(12) > freebsd_ver => true,
2404 
2405             // These constants were introduced in FreeBSD 13:
2406             "O_DSYNC" | "O_PATH" | "O_EMPTY_PATH" | "AT_EMPTY_PATH" if Some(13) > freebsd_ver => {
2407                 true
2408             }
2409 
2410             // These aliases were introduced in FreeBSD 13:
2411             // (note however that the constants themselves work on any version)
2412             "CLOCK_BOOTTIME" | "CLOCK_REALTIME_COARSE" | "CLOCK_MONOTONIC_COARSE"
2413                 if Some(13) > freebsd_ver =>
2414             {
2415                 true
2416             }
2417 
2418             // FIXME: These are deprecated - remove in a couple of releases.
2419             // These constants were removed in FreeBSD 11 (svn r273250) but will
2420             // still be accepted and ignored at runtime.
2421             "MAP_RENAME" | "MAP_NORESERVE" => true,
2422 
2423             // FIXME: These are deprecated - remove in a couple of releases.
2424             // These constants were removed in FreeBSD 11 (svn r262489),
2425             // and they've never had any legitimate use outside of the
2426             // base system anyway.
2427             "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "USER_MAXID" => true,
2428 
2429             // Deprecated and removed in FreeBSD 15.  It was never actually implemented.
2430             "TCP_MAXPEAKRATE" => true,
2431 
2432             // FIXME: This is deprecated - remove in a couple of releases.
2433             // This was removed in FreeBSD 14 (git 1b4701fe1e8) and never
2434             // should've been used anywhere anyway.
2435             "TDF_UNUSED23" => true,
2436 
2437             // Removed in FreeBSD 15
2438             "TDF_CANSWAP" | "TDF_SWAPINREQ" => true,
2439 
2440             // Unaccessible in FreeBSD 15
2441             "TDI_SWAPPED" | "P_SWAPPINGOUT" | "P_SWAPPINGIN" => true,
2442 
2443             // Removed in FreeBSD 14 (git a6b55ee6be1)
2444             "IFF_KNOWSEPOCH" => true,
2445 
2446             // Removed in FreeBSD 14 (git 7ff9ae90f0b)
2447             "IFF_NOGROUP" => true,
2448 
2449             // FIXME: These are deprecated - remove in a couple of releases.
2450             // These symbols are not stable across OS-versions.  They were
2451             // changed for FreeBSD 14 in git revisions b62848b0c3f and
2452             // 2cf7870864e.
2453             "PRI_MAX_ITHD" | "PRI_MIN_REALTIME" | "PRI_MAX_REALTIME" | "PRI_MIN_KERN"
2454             | "PRI_MAX_KERN" | "PSWP" | "PVM" | "PINOD" | "PRIBIO" | "PVFS" | "PZERO" | "PSOCK"
2455             | "PWAIT" | "PLOCK" | "PPAUSE" | "PRI_MIN_TIMESHARE" | "PUSER" | "PI_AV" | "PI_NET"
2456             | "PI_DISK" | "PI_TTY" | "PI_DULL" | "PI_SOFT" => true,
2457 
2458             // This constant changed in FreeBSD 15 (git 3458bbd397783).  It was never intended to
2459             // be stable, and probably shouldn't be bound by libc at all.
2460             "RLIM_NLIMITS" => true,
2461 
2462             // This symbol changed in FreeBSD 14 (git 051e7d78b03), but the new
2463             // version should be safe to use on older releases.
2464             "IFCAP_CANTCHANGE" => true,
2465 
2466             // These were removed in FreeBSD 14 (git c6d31b8306e)
2467             "TDF_ASTPENDING" | "TDF_NEEDSUSPCHK" | "TDF_NEEDRESCHED" | "TDF_NEEDSIGCHK"
2468             | "TDF_ALRMPEND" | "TDF_PROFPEND" | "TDF_MACPEND" => true,
2469 
2470             // This constant was removed in FreeBSD 13 (svn r363622), and never
2471             // had any legitimate use outside of the base system anyway.
2472             "CTL_P1003_1B_MAXID" => true,
2473 
2474             // This was renamed in FreeBSD 12.2 and 13 (r352486).
2475             "CTL_UNSPEC" | "CTL_SYSCTL" => true,
2476 
2477             // This was renamed in FreeBSD 12.2 and 13 (r350749).
2478             "IPPROTO_SEP" | "IPPROTO_DCCP" => true,
2479 
2480             // This was changed to 96(0x60) in FreeBSD 13:
2481             // https://github.com/freebsd/freebsd/
2482             // commit/06b00ceaa914a3907e4e27bad924f44612bae1d7
2483             "MINCORE_SUPER" if Some(13) <= freebsd_ver => true,
2484 
2485             // Added in FreeBSD 13.0 (r356667)
2486             "GRND_INSECURE" if Some(13) > freebsd_ver => true,
2487 
2488             // Added in FreeBSD 13.0 (r349609)
2489             "PROC_PROTMAX_CTL"
2490             | "PROC_PROTMAX_STATUS"
2491             | "PROC_PROTMAX_FORCE_ENABLE"
2492             | "PROC_PROTMAX_FORCE_DISABLE"
2493             | "PROC_PROTMAX_NOFORCE"
2494             | "PROC_PROTMAX_ACTIVE"
2495             | "PROC_NO_NEW_PRIVS_CTL"
2496             | "PROC_NO_NEW_PRIVS_STATUS"
2497             | "PROC_NO_NEW_PRIVS_ENABLE"
2498             | "PROC_NO_NEW_PRIVS_DISABLE"
2499             | "PROC_WXMAP_CTL"
2500             | "PROC_WXMAP_STATUS"
2501             | "PROC_WX_MAPPINGS_PERMIT"
2502             | "PROC_WX_MAPPINGS_DISALLOW_EXEC"
2503             | "PROC_WXORX_ENFORCE"
2504                 if Some(13) > freebsd_ver =>
2505             {
2506                 true
2507             }
2508 
2509             // Added in FreeBSD 13.0 (r367776 and r367287)
2510             "SCM_CREDS2" | "LOCAL_CREDS_PERSISTENT" if Some(13) > freebsd_ver => true,
2511 
2512             // Added in FreeBSD 14
2513             "SPACECTL_DEALLOC" if Some(14) > freebsd_ver => true,
2514 
2515             // Added in FreeBSD 13.
2516             "KERN_PROC_SIGFASTBLK"
2517             | "USER_LOCALBASE"
2518             | "TDP_SIGFASTBLOCK"
2519             | "TDP_UIOHELD"
2520             | "TDP_SIGFASTPENDING"
2521             | "TDP2_COMPAT32RB"
2522             | "P2_PROTMAX_ENABLE"
2523             | "P2_PROTMAX_DISABLE"
2524             | "CTLFLAG_NEEDGIANT"
2525             | "CTL_SYSCTL_NEXTNOSKIP"
2526                 if Some(13) > freebsd_ver =>
2527             {
2528                 true
2529             }
2530 
2531             // Added in freebsd 14.
2532             "IFCAP_MEXTPG" if Some(14) > freebsd_ver => true,
2533             // Added in freebsd 13.
2534             "IFCAP_TXTLS4" | "IFCAP_TXTLS6" | "IFCAP_VXLAN_HWCSUM" | "IFCAP_VXLAN_HWTSO"
2535             | "IFCAP_TXTLS_RTLMT" | "IFCAP_TXTLS"
2536                 if Some(13) > freebsd_ver =>
2537             {
2538                 true
2539             }
2540             // Added in FreeBSD 13.
2541             "PS_FST_TYPE_EVENTFD" if Some(13) > freebsd_ver => true,
2542 
2543             // Added in FreeBSD 14.
2544             "MNT_RECURSE" | "MNT_DEFERRED" if Some(14) > freebsd_ver => true,
2545 
2546             // Added in FreeBSD 13.
2547             "MNT_EXTLS" | "MNT_EXTLSCERT" | "MNT_EXTLSCERTUSER" | "MNT_NOCOVER"
2548             | "MNT_EMPTYDIR"
2549                 if Some(13) > freebsd_ver =>
2550             {
2551                 true
2552             }
2553 
2554             // Added in FreeBSD 14.
2555             "PT_COREDUMP" | "PC_ALL" | "PC_COMPRESS" | "PT_GETREGSET" | "PT_SETREGSET"
2556             | "PT_SC_REMOTE"
2557                 if Some(14) > freebsd_ver =>
2558             {
2559                 true
2560             }
2561 
2562             // Added in FreeBSD 14.
2563             "F_KINFO" => true, // FIXME: depends how frequent freebsd 14 is updated on CI, this addition went this week only.
2564             "SHM_RENAME_NOREPLACE"
2565             | "SHM_RENAME_EXCHANGE"
2566             | "SHM_LARGEPAGE_ALLOC_DEFAULT"
2567             | "SHM_LARGEPAGE_ALLOC_NOWAIT"
2568             | "SHM_LARGEPAGE_ALLOC_HARD"
2569             | "MFD_CLOEXEC"
2570             | "MFD_ALLOW_SEALING"
2571             | "MFD_HUGETLB"
2572             | "MFD_HUGE_MASK"
2573             | "MFD_HUGE_64KB"
2574             | "MFD_HUGE_512KB"
2575             | "MFD_HUGE_1MB"
2576             | "MFD_HUGE_2MB"
2577             | "MFD_HUGE_8MB"
2578             | "MFD_HUGE_16MB"
2579             | "MFD_HUGE_32MB"
2580             | "MFD_HUGE_256MB"
2581             | "MFD_HUGE_512MB"
2582             | "MFD_HUGE_1GB"
2583             | "MFD_HUGE_2GB"
2584             | "MFD_HUGE_16GB"
2585                 if Some(13) > freebsd_ver =>
2586             {
2587                 true
2588             }
2589 
2590             // Flags introduced in FreeBSD 14.
2591             "TCP_MAXUNACKTIME"
2592             | "TCP_IDLE_REDUCE"
2593             | "TCP_REMOTE_UDP_ENCAPS_PORT"
2594             | "TCP_DELACK"
2595             | "TCP_FIN_IS_RST"
2596             | "TCP_LOG_LIMIT"
2597             | "TCP_SHARED_CWND_ALLOWED"
2598             | "TCP_PROC_ACCOUNTING"
2599             | "TCP_USE_CMP_ACKS"
2600             | "TCP_PERF_INFO"
2601             | "TCP_LRD"
2602                 if Some(14) > freebsd_ver =>
2603             {
2604                 true
2605             }
2606 
2607             // Introduced in FreeBSD 14 then removed ?
2608             "TCP_LRD" if freebsd_ver >= Some(15) => true,
2609 
2610             // Added in FreeBSD 14
2611             "LIO_READV" | "LIO_WRITEV" | "LIO_VECTORED" if Some(14) > freebsd_ver => true,
2612 
2613             // Added in FreeBSD 13
2614             "FIOSSHMLPGCNF" if Some(13) > freebsd_ver => true,
2615 
2616             // Added in FreeBSD 14
2617             "IFCAP_NV" if Some(14) > freebsd_ver => true,
2618 
2619             // FIXME: Removed in https://reviews.freebsd.org/D38574 and https://reviews.freebsd.org/D38822
2620             // We maybe should deprecate them once a stable release ships them.
2621             "IP_BINDMULTI" | "IP_RSS_LISTEN_BUCKET" => true,
2622 
2623             // FIXME: Removed in https://reviews.freebsd.org/D39127.
2624             "KERN_VNODE" => true,
2625 
2626             // Added in FreeBSD 14
2627             "EV_KEEPUDATA" if Some(14) > freebsd_ver => true,
2628 
2629             // Added in FreeBSD 13.2
2630             "AT_USRSTACKBASE" | "AT_USRSTACKLIM" if Some(13) > freebsd_ver => true,
2631 
2632             // Added in FreeBSD 14
2633             "TFD_CLOEXEC" | "TFD_NONBLOCK" | "TFD_TIMER_ABSTIME" | "TFD_TIMER_CANCEL_ON_SET"
2634                 if Some(14) > freebsd_ver =>
2635             {
2636                 true
2637             }
2638 
2639             // Added in FreeBSD 14.1
2640             "KCMP_FILE" | "KCMP_FILEOBJ" | "KCMP_FILES" | "KCMP_SIGHAND" | "KCMP_VM"
2641                 if Some(14) > freebsd_ver =>
2642             {
2643                 true
2644             }
2645 
2646             // FIXME: Removed in FreeBSD 15:
2647             "LOCAL_CONNWAIT" if freebsd_ver >= Some(15) => true,
2648 
2649             // FIXME: The values has been changed in FreeBSD 15:
2650             "CLOCK_BOOTTIME" if Some(15) <= freebsd_ver => true,
2651 
2652             // Added in FreeBSD 14.0
2653             "TCP_FUNCTION_ALIAS" if Some(14) > freebsd_ver => true,
2654 
2655             // These constants may change or disappear in future OS releases, and they probably
2656             // have no legitimate use in applications anyway.
2657             "CAP_UNUSED0_44" | "CAP_UNUSED0_57" | "CAP_UNUSED1_22" | "CAP_UNUSED1_57" |
2658                 "CAP_ALL0" | "CAP_ALL1" => true,
2659 
2660             _ => false,
2661         }
2662     });
2663 
2664     cfg.skip_type(move |ty| {
2665         match ty {
2666             // the struct "__kvm" is quite tricky to bind so since we only use a pointer to it
2667             // for now, it doesn't matter too much...
2668             "kvm_t" => true,
2669             // `eventfd(2)` and things come with it are added in FreeBSD 13
2670             "eventfd_t" if Some(13) > freebsd_ver => true,
2671 
2672             _ => false,
2673         }
2674     });
2675 
2676     cfg.skip_struct(move |ty| {
2677         if ty.starts_with("__c_anonymous_") {
2678             return true;
2679         }
2680         match ty {
2681             // `procstat` is a private struct
2682             "procstat" => true,
2683 
2684             // `spacectl_range` was introduced in FreeBSD 14
2685             "spacectl_range" if Some(14) > freebsd_ver => true,
2686 
2687             // `ptrace_coredump` introduced in FreeBSD 14.
2688             "ptrace_coredump" if Some(14) > freebsd_ver => true,
2689             // `ptrace_sc_remote` introduced in FreeBSD 14.
2690             "ptrace_sc_remote" if Some(14) > freebsd_ver => true,
2691 
2692             // `sockcred2` is not available in FreeBSD 12.
2693             "sockcred2" if Some(13) > freebsd_ver => true,
2694             // `shm_largepage_conf` was introduced in FreeBSD 13.
2695             "shm_largepage_conf" if Some(13) > freebsd_ver => true,
2696 
2697             // Those are private types
2698             "memory_type" => true,
2699             "memory_type_list" => true,
2700             "pidfh" => true,
2701             "sctp_gen_error_cause"
2702             | "sctp_error_missing_param"
2703             | "sctp_remote_error"
2704             | "sctp_assoc_change"
2705             | "sctp_send_failed_event"
2706             | "sctp_stream_reset_event" => true,
2707 
2708             // FIXME: Changed in FreeBSD 15
2709             "tcp_info" | "sockstat" if Some(15) >= freebsd_ver => true,
2710 
2711             _ => false,
2712         }
2713     });
2714 
2715     cfg.skip_fn(move |name| {
2716         // skip those that are manually verified
2717         match name {
2718             // FIXME: https://github.com/rust-lang/libc/issues/1272
2719             // Also, `execvpe` is introduced in FreeBSD 14.1
2720             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
2721 
2722             // The `uname` function in the `utsname.h` FreeBSD header is a C
2723             // inline function (has no symbol) that calls the `__xuname` symbol.
2724             // Therefore the function pointer comparison does not make sense for it.
2725             "uname" => true,
2726 
2727             // FIXME: Our API is unsound. The Rust API allows aliasing
2728             // pointers, but the C API requires pointers not to alias.
2729             // We should probably be at least using `&`/`&mut` here, see:
2730             // https://github.com/gnzlbg/ctest/issues/68
2731             "lio_listio" => true,
2732 
2733             // Those are introduced in FreeBSD 12.
2734             "clock_nanosleep" | "getrandom" | "elf_aux_info" | "setproctitle_fast"
2735             | "timingsafe_bcmp" | "timingsafe_memcmp"
2736                 if Some(12) > freebsd_ver =>
2737             {
2738                 true
2739             }
2740 
2741             // Those are introduced in FreeBSD 13.
2742             "memfd_create"
2743             | "shm_create_largepage"
2744             | "shm_rename"
2745             | "getentropy"
2746             | "eventfd"
2747             | "SOCKCRED2SIZE"
2748             | "getlocalbase"
2749             | "aio_readv"
2750             | "aio_writev"
2751             | "copy_file_range"
2752             | "eventfd_read"
2753             | "eventfd_write"
2754                 if Some(13) > freebsd_ver =>
2755             {
2756                 true
2757             }
2758 
2759             // Those are introduced in FreeBSD 14.
2760             "sched_getaffinity" | "sched_setaffinity" | "sched_getcpu" | "fspacectl"
2761                 if Some(14) > freebsd_ver =>
2762             {
2763                 true
2764             }
2765 
2766             // Those are introduced in FreeBSD 14.
2767             "timerfd_create" | "timerfd_gettime" | "timerfd_settime" if Some(14) > freebsd_ver => {
2768                 true
2769             }
2770 
2771             // Those are introduced in FreeBSD 14.1.
2772             "kcmp" => true,
2773 
2774             _ => false,
2775         }
2776     });
2777 
2778     cfg.volatile_item(|i| {
2779         use ctest::VolatileItemKind::*;
2780         match i {
2781             // aio_buf is a volatile void** but since we cannot express that in
2782             // Rust types, we have to explicitly tell the checker about it here:
2783             StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
2784             _ => false,
2785         }
2786     });
2787 
2788     cfg.skip_field(move |struct_, field| {
2789         match (struct_, field) {
2790             // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
2791             // incorrect, see: https://github.com/rust-lang/libc/issues/1359
2792             ("sigaction", "sa_sigaction") => true,
2793 
2794             // conflicting with `p_type` macro from <resolve.h>.
2795             ("Elf32_Phdr", "p_type") => true,
2796             ("Elf64_Phdr", "p_type") => true,
2797 
2798             // not available until FreeBSD 12, and is an anonymous union there.
2799             ("xucred", "cr_pid__c_anonymous_union") => true,
2800 
2801             // m_owner field is a volatile __lwpid_t
2802             ("umutex", "m_owner") => true,
2803             // c_has_waiters field is a volatile int32_t
2804             ("ucond", "c_has_waiters") => true,
2805             // is PATH_MAX long but tests can't accept multi array as equivalent.
2806             ("kinfo_vmentry", "kve_path") => true,
2807 
2808             // a_un field is a union
2809             ("Elf32_Auxinfo", "a_un") => true,
2810             ("Elf64_Auxinfo", "a_un") => true,
2811 
2812             // union fields
2813             ("if_data", "__ifi_epoch") => true,
2814             ("if_data", "__ifi_lastchange") => true,
2815             ("ifreq", "ifr_ifru") => true,
2816             ("ifconf", "ifc_ifcu") => true,
2817 
2818             // anonymous struct
2819             ("devstat", "dev_links") => true,
2820 
2821             // FIXME: structs too complicated to bind for now...
2822             ("kinfo_proc", "ki_paddr") => true,
2823             ("kinfo_proc", "ki_addr") => true,
2824             ("kinfo_proc", "ki_tracep") => true,
2825             ("kinfo_proc", "ki_textvp") => true,
2826             ("kinfo_proc", "ki_fd") => true,
2827             ("kinfo_proc", "ki_vmspace") => true,
2828             ("kinfo_proc", "ki_pcb") => true,
2829             ("kinfo_proc", "ki_tdaddr") => true,
2830             ("kinfo_proc", "ki_pd") => true,
2831 
2832             // Anonymous type.
2833             ("filestat", "next") => true,
2834 
2835             // We ignore this field because we needed to use a hack in order to make rust 1.19
2836             // happy...
2837             ("kinfo_proc", "ki_sparestrings") => true,
2838 
2839             // `__sem_base` is a private struct field
2840             ("semid_ds", "__sem_base") => true,
2841 
2842             // `snap_time` is a `long double`, but it's a nightmare to bind correctly in rust
2843             // for the moment, so it's a best effort thing...
2844             ("statinfo", "snap_time") => true,
2845             ("sctp_sndrcvinfo", "__reserve_pad") => true,
2846             ("sctp_extrcvinfo", "__reserve_pad") => true,
2847             // `tcp_snd_wscale` and `tcp_rcv_wscale` are bitfields
2848             ("tcp_info", "tcp_snd_wscale") => true,
2849             ("tcp_info", "tcp_rcv_wscale") => true,
2850 
2851             _ => false,
2852         }
2853     });
2854     if target.contains("arm") {
2855         cfg.skip_roundtrip(move |s| match s {
2856             // Can't return an array from a C function.
2857             "__gregset_t" => true,
2858             _ => false,
2859         });
2860     }
2861 
2862     cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs");
2863 }
2864 
2865 fn test_emscripten(target: &str) {
2866     assert!(target.contains("emscripten"));
2867 
2868     let mut cfg = ctest_cfg();
2869     cfg.define("_GNU_SOURCE", None); // FIXME: ??
2870 
2871     headers! { cfg:
2872                "ctype.h",
2873                "dirent.h",
2874                "dlfcn.h",
2875                "errno.h",
2876                "fcntl.h",
2877                "fnmatch.h",
2878                "glob.h",
2879                "grp.h",
2880                "ifaddrs.h",
2881                "langinfo.h",
2882                "limits.h",
2883                "locale.h",
2884                "malloc.h",
2885                "mntent.h",
2886                "mqueue.h",
2887                "net/ethernet.h",
2888                "net/if.h",
2889                "net/if_arp.h",
2890                "net/route.h",
2891                "netdb.h",
2892                "netinet/in.h",
2893                "netinet/ip.h",
2894                "netinet/tcp.h",
2895                "netinet/udp.h",
2896                "netpacket/packet.h",
2897                "poll.h",
2898                "pthread.h",
2899                "pty.h",
2900                "pwd.h",
2901                "resolv.h",
2902                "sched.h",
2903                "sched.h",
2904                "semaphore.h",
2905                "shadow.h",
2906                "signal.h",
2907                "stddef.h",
2908                "stdint.h",
2909                "stdio.h",
2910                "stdlib.h",
2911                "string.h",
2912                "sys/file.h",
2913                "sys/ioctl.h",
2914                "sys/ipc.h",
2915                "sys/mman.h",
2916                "sys/mount.h",
2917                "sys/msg.h",
2918                "sys/resource.h",
2919                "sys/sem.h",
2920                "sys/shm.h",
2921                "sys/socket.h",
2922                "sys/stat.h",
2923                "sys/statvfs.h",
2924                "sys/syscall.h",
2925                "sys/sysinfo.h",
2926                "sys/time.h",
2927                "sys/times.h",
2928                "sys/types.h",
2929                "sys/uio.h",
2930                "sys/un.h",
2931                "sys/user.h",
2932                "sys/utsname.h",
2933                "sys/vfs.h",
2934                "sys/wait.h",
2935                "sys/xattr.h",
2936                "syslog.h",
2937                "termios.h",
2938                "time.h",
2939                "ucontext.h",
2940                "unistd.h",
2941                "utime.h",
2942                "utmp.h",
2943                "utmpx.h",
2944                "wchar.h",
2945     }
2946 
2947     cfg.type_name(move |ty, is_struct, is_union| {
2948         match ty {
2949             // Just pass all these through, no need for a "struct" prefix
2950             "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(),
2951 
2952             // LFS64 types have been removed in Emscripten 3.1.44
2953             // https://github.com/emscripten-core/emscripten/pull/19812
2954             "off64_t" => "off_t".to_string(),
2955 
2956             // typedefs don't need any keywords
2957             t if t.ends_with("_t") => t.to_string(),
2958 
2959             // put `struct` in front of all structs:.
2960             t if is_struct => format!("struct {}", t),
2961 
2962             // put `union` in front of all unions:
2963             t if is_union => format!("union {}", t),
2964 
2965             t => t.to_string(),
2966         }
2967     });
2968 
2969     cfg.field_name(move |struct_, field| {
2970         match field {
2971             // Our stat *_nsec fields normally don't actually exist but are part
2972             // of a timeval struct
2973             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
2974                 s.replace("e_nsec", ".tv_nsec")
2975             }
2976             // Rust struct uses raw u64, rather than union
2977             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
2978             s => s.to_string(),
2979         }
2980     });
2981 
2982     cfg.skip_type(move |ty| {
2983         match ty {
2984             // sighandler_t is crazy across platforms
2985             // FIXME: is this necessary?
2986             "sighandler_t" => true,
2987 
2988             // No epoll support
2989             // https://github.com/emscripten-core/emscripten/issues/5033
2990             ty if ty.starts_with("epoll") => true,
2991 
2992             // LFS64 types have been removed in Emscripten 3.1.44
2993             // https://github.com/emscripten-core/emscripten/pull/19812
2994             t => t.ends_with("64") || t.ends_with("64_t"),
2995         }
2996     });
2997 
2998     cfg.skip_struct(move |ty| {
2999         match ty {
3000             // This is actually a union, not a struct
3001             "sigval" => true,
3002 
3003             // FIXME: Investigate why the test fails.
3004             // Skip for now to unblock CI.
3005             "pthread_condattr_t" => true,
3006             "pthread_mutexattr_t" => true,
3007 
3008             // No epoll support
3009             // https://github.com/emscripten-core/emscripten/issues/5033
3010             ty if ty.starts_with("epoll") => true,
3011             ty if ty.starts_with("signalfd") => true,
3012 
3013             // LFS64 types have been removed in Emscripten 3.1.44
3014             // https://github.com/emscripten-core/emscripten/pull/19812
3015             ty => ty.ends_with("64") || ty.ends_with("64_t"),
3016         }
3017     });
3018 
3019     cfg.skip_fn(move |name| {
3020         match name {
3021             // Emscripten does not support fork/exec/wait or any kind of multi-process support
3022             // https://github.com/emscripten-core/emscripten/blob/3.1.68/tools/system_libs.py#L1100
3023             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" | "wait4" => true,
3024 
3025             _ => false,
3026         }
3027     });
3028 
3029     cfg.skip_const(move |name| {
3030         match name {
3031             // FIXME: deprecated - SIGNUNUSED was removed in glibc 2.26
3032             // users should use SIGSYS instead
3033             "SIGUNUSED" => true,
3034 
3035             // FIXME: emscripten uses different constants to constructs these
3036             n if n.contains("__SIZEOF_PTHREAD") => true,
3037 
3038             // No epoll support
3039             // https://github.com/emscripten-core/emscripten/issues/5033
3040             n if n.starts_with("EPOLL") => true,
3041 
3042             // No ptrace.h
3043             // https://github.com/emscripten-core/emscripten/pull/17704
3044             n if n.starts_with("PTRACE_") => true,
3045 
3046             // No quota.h
3047             // https://github.com/emscripten-core/emscripten/pull/17704
3048             n if n.starts_with("QIF_") => true,
3049             "USRQUOTA" | "GRPQUOTA" | "Q_GETFMT" | "Q_GETINFO" | "Q_SETINFO" | "Q_SYNC"
3050             | "Q_QUOTAON" | "Q_QUOTAOFF" | "Q_GETQUOTA" | "Q_SETQUOTA" => true,
3051 
3052             // `SYS_gettid` was removed in Emscripten v1.39.9
3053             // https://github.com/emscripten-core/emscripten/pull/10439
3054             "SYS_gettid" => true,
3055 
3056             // No personality.h
3057             // https://github.com/emscripten-core/emscripten/pull/17704
3058             "ADDR_NO_RANDOMIZE" | "MMAP_PAGE_ZERO" | "ADDR_COMPAT_LAYOUT" | "READ_IMPLIES_EXEC"
3059             | "ADDR_LIMIT_32BIT" | "SHORT_INODE" | "WHOLE_SECONDS" | "STICKY_TIMEOUTS"
3060             | "ADDR_LIMIT_3GB" => true,
3061 
3062             // `SIG_IGN` has been changed to -2 since 1 is a valid function address
3063             // https://github.com/emscripten-core/emscripten/pull/14883
3064             "SIG_IGN" => true,
3065 
3066             // LFS64 types have been removed in Emscripten 3.1.44
3067             // https://github.com/emscripten-core/emscripten/pull/19812
3068             n if n.starts_with("RLIM64") => true,
3069 
3070             _ => false,
3071         }
3072     });
3073 
3074     cfg.skip_field_type(move |struct_, field| {
3075         // This is a weird union, don't check the type.
3076         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
3077         // sighandler_t type is super weird
3078         (struct_ == "sigaction" && field == "sa_sigaction") ||
3079         // sigval is actually a union, but we pretend it's a struct
3080         (struct_ == "sigevent" && field == "sigev_value")
3081     });
3082 
3083     cfg.skip_field(move |struct_, field| {
3084         // this is actually a union on linux, so we can't represent it well and
3085         // just insert some padding.
3086         (struct_ == "siginfo_t" && field == "_pad") ||
3087         // musl names this __dummy1 but it's still there
3088         (struct_ == "glob_t" && field == "gl_flags") ||
3089         // FIXME: After musl 1.1.24, it have only one field `sched_priority`,
3090         // while other fields become reserved.
3091         (struct_ == "sched_param" && [
3092             "sched_ss_low_priority",
3093             "sched_ss_repl_period",
3094             "sched_ss_init_budget",
3095             "sched_ss_max_repl",
3096         ].contains(&field))
3097     });
3098 
3099     cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs");
3100 }
3101 
3102 fn test_neutrino(target: &str) {
3103     assert!(target.contains("nto-qnx"));
3104 
3105     let mut cfg = ctest_cfg();
3106 
3107     headers! { cfg:
3108         "ctype.h",
3109         "dirent.h",
3110         "dlfcn.h",
3111         "sys/elf.h",
3112         "fcntl.h",
3113         "fnmatch.h",
3114         "glob.h",
3115         "grp.h",
3116         "iconv.h",
3117         "ifaddrs.h",
3118         "limits.h",
3119         "sys/link.h",
3120         "locale.h",
3121         "sys/malloc.h",
3122         "rcheck/malloc.h",
3123         "malloc.h",
3124         "mqueue.h",
3125         "net/if.h",
3126         "net/if_arp.h",
3127         "net/route.h",
3128         "netdb.h",
3129         "netinet/in.h",
3130         "netinet/ip.h",
3131         "netinet/tcp.h",
3132         "netinet/udp.h",
3133         "netinet/ip_var.h",
3134         "sys/poll.h",
3135         "pthread.h",
3136         "pwd.h",
3137         "regex.h",
3138         "resolv.h",
3139         "sys/sched.h",
3140         "sched.h",
3141         "semaphore.h",
3142         "shadow.h",
3143         "signal.h",
3144         "spawn.h",
3145         "stddef.h",
3146         "stdint.h",
3147         "stdio.h",
3148         "stdlib.h",
3149         "string.h",
3150         "sys/sysctl.h",
3151         "sys/file.h",
3152         "sys/inotify.h",
3153         "sys/ioctl.h",
3154         "sys/ipc.h",
3155         "sys/mman.h",
3156         "sys/mount.h",
3157         "sys/msg.h",
3158         "sys/resource.h",
3159         "sys/sem.h",
3160         "sys/socket.h",
3161         "sys/stat.h",
3162         "sys/statvfs.h",
3163         "sys/swap.h",
3164         "sys/termio.h",
3165         "sys/time.h",
3166         "sys/times.h",
3167         "sys/types.h",
3168         "sys/uio.h",
3169         "sys/un.h",
3170         "sys/utsname.h",
3171         "sys/wait.h",
3172         "syslog.h",
3173         "termios.h",
3174         "time.h",
3175         "sys/time.h",
3176         "ucontext.h",
3177         "unistd.h",
3178         "utime.h",
3179         "utmp.h",
3180         "wchar.h",
3181         "aio.h",
3182         "nl_types.h",
3183         "langinfo.h",
3184         "unix.h",
3185         "nbutil.h",
3186         "aio.h",
3187         "net/bpf.h",
3188         "net/if_dl.h",
3189         "sys/syspage.h",
3190 
3191         // TODO: The following header file doesn't appear as part of the default headers
3192         //       found in a standard installation of Neutrino 7.1 SDP.  The structures/
3193         //       functions dependent on it are currently commented out.
3194         //"sys/asyncmsg.h",
3195     }
3196 
3197     // Create and include a header file containing
3198     // items which are not included in any official
3199     // header file.
3200     let internal_header = "internal.h";
3201     let out_dir = env::var("OUT_DIR").unwrap();
3202     cfg.header(internal_header);
3203     cfg.include(&out_dir);
3204     std::fs::write(
3205         out_dir.to_owned() + "/" + internal_header,
3206         "#ifndef __internal_h__
3207         #define __internal_h__
3208         void __my_thread_exit(const void **);
3209         #endif",
3210     )
3211     .unwrap();
3212 
3213     cfg.type_name(move |ty, is_struct, is_union| {
3214         match ty {
3215             // Just pass all these through, no need for a "struct" prefix
3216             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr"
3217             | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr"
3218             | "Elf32_Chdr" | "Elf64_Chdr" | "aarch64_qreg_t" | "syspage_entry_info"
3219             | "syspage_array_info" => ty.to_string(),
3220 
3221             "Ioctl" => "int".to_string(),
3222 
3223             t if is_union => format!("union {}", t),
3224 
3225             t if t.ends_with("_t") => t.to_string(),
3226 
3227             // put `struct` in front of all structs:.
3228             t if is_struct => format!("struct {}", t),
3229 
3230             t => t.to_string(),
3231         }
3232     });
3233 
3234     cfg.field_name(move |_struct_, field| match field {
3235         "type_" => "type".to_string(),
3236 
3237         s => s.to_string(),
3238     });
3239 
3240     cfg.volatile_item(|i| {
3241         use ctest::VolatileItemKind::*;
3242         match i {
3243             // The following fields are volatie but since we cannot express that in
3244             // Rust types, we have to explicitly tell the checker about it here:
3245             StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
3246             StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec_tod_adjust" => true,
3247             StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec" => true,
3248             StructField(ref n, ref f) if n == "qtime_entry" && f == "nsec_stable" => true,
3249             StructField(ref n, ref f) if n == "intrspin" && f == "value" => true,
3250             _ => false,
3251         }
3252     });
3253 
3254     cfg.skip_type(move |ty| {
3255         match ty {
3256             // FIXME: `sighandler_t` type is incorrect, see:
3257             // https://github.com/rust-lang/libc/issues/1359
3258             "sighandler_t" => true,
3259 
3260             // Does not exist in Neutrino
3261             "locale_t" => true,
3262 
3263             _ => false,
3264         }
3265     });
3266 
3267     cfg.skip_struct(move |ty| {
3268         if ty.starts_with("__c_anonymous_") {
3269             return true;
3270         }
3271         match ty {
3272             "Elf64_Phdr" | "Elf32_Phdr" => true,
3273 
3274             // FIXME: This is actually a union, not a struct
3275             "sigval" => true,
3276 
3277             // union
3278             "_channel_connect_attr" => true,
3279 
3280             _ => false,
3281         }
3282     });
3283 
3284     cfg.skip_const(move |name| {
3285         match name {
3286             // These signal "functions" are actually integer values that are casted to a fn ptr
3287             // This causes the compiler to err because of "illegal cast of int to ptr".
3288             "SIG_DFL" => true,
3289             "SIG_IGN" => true,
3290             "SIG_ERR" => true,
3291 
3292             _ => false,
3293         }
3294     });
3295 
3296     cfg.skip_fn(move |name| {
3297         // skip those that are manually verified
3298         match name {
3299             // FIXME: https://github.com/rust-lang/libc/issues/1272
3300             "execv" | "execve" | "execvp" | "execvpe" => true,
3301 
3302             // wrong signature
3303             "signal" => true,
3304 
3305             // wrong signature of callback ptr
3306             "__cxa_atexit" => true,
3307 
3308             // FIXME: Our API is unsound. The Rust API allows aliasing
3309             // pointers, but the C API requires pointers not to alias.
3310             // We should probably be at least using `&`/`&mut` here, see:
3311             // https://github.com/gnzlbg/ctest/issues/68
3312             "lio_listio" => true,
3313 
3314             // 2 fields are actually unions which we're simply representing
3315             // as structures.
3316             "ChannelConnectAttr" => true,
3317 
3318             // fields contains unions
3319             "SignalKillSigval" => true,
3320             "SignalKillSigval_r" => true,
3321 
3322             // Not defined in any headers.  Defined to work around a
3323             // stack unwinding bug.
3324             "__my_thread_exit" => true,
3325 
3326             _ => false,
3327         }
3328     });
3329 
3330     cfg.skip_field_type(move |struct_, field| {
3331         // sigval is actually a union, but we pretend it's a struct
3332         struct_ == "sigevent" && field == "sigev_value" ||
3333         // Anonymous structures
3334         struct_ == "_idle_hook" && field == "time"
3335     });
3336 
3337     cfg.skip_field(move |struct_, field| {
3338         (struct_ == "__sched_param" && field == "reserved") ||
3339         (struct_ == "sched_param" && field == "reserved") ||
3340         (struct_ == "sigevent" && field == "__padding1") || // ensure alignment
3341         (struct_ == "sigevent" && field == "__padding2") || // union
3342         (struct_ == "sigevent" && field == "__sigev_un2") || // union
3343         // sighandler_t type is super weird
3344         (struct_ == "sigaction" && field == "sa_sigaction") ||
3345         // does not exist
3346         (struct_ == "syspage_entry" && field == "__reserved") ||
3347         false // keep me for smaller diffs when something is added above
3348     });
3349 
3350     cfg.skip_static(move |name| (name == "__dso_handle"));
3351 
3352     cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs");
3353 }
3354 
3355 fn test_vxworks(target: &str) {
3356     assert!(target.contains("vxworks"));
3357 
3358     let mut cfg = ctest::TestGenerator::new();
3359     headers! { cfg:
3360                "vxWorks.h",
3361                "yvals.h",
3362                "nfs/nfsCommon.h",
3363                "rtpLibCommon.h",
3364                "randomNumGen.h",
3365                "taskLib.h",
3366                "sysLib.h",
3367                "ioLib.h",
3368                "inetLib.h",
3369                "socket.h",
3370                "errnoLib.h",
3371                "ctype.h",
3372                "dirent.h",
3373                "dlfcn.h",
3374                "elf.h",
3375                "fcntl.h",
3376                "grp.h",
3377                "sys/poll.h",
3378                "ifaddrs.h",
3379                "langinfo.h",
3380                "limits.h",
3381                "link.h",
3382                "locale.h",
3383                "sys/stat.h",
3384                "netdb.h",
3385                "pthread.h",
3386                "pwd.h",
3387                "sched.h",
3388                "semaphore.h",
3389                "signal.h",
3390                "stddef.h",
3391                "stdint.h",
3392                "stdio.h",
3393                "stdlib.h",
3394                "string.h",
3395                "sys/file.h",
3396                "sys/ioctl.h",
3397                "sys/socket.h",
3398                "sys/time.h",
3399                "sys/times.h",
3400                "sys/types.h",
3401                "sys/uio.h",
3402                "sys/un.h",
3403                "sys/utsname.h",
3404                "sys/wait.h",
3405                "netinet/tcp.h",
3406                "syslog.h",
3407                "termios.h",
3408                "time.h",
3409                "ucontext.h",
3410                "unistd.h",
3411                "utime.h",
3412                "wchar.h",
3413                "errno.h",
3414                "sys/mman.h",
3415                "pathLib.h",
3416                "mqueue.h",
3417     }
3418     // FIXME
3419     cfg.skip_const(move |name| match name {
3420         // sighandler_t weirdness
3421         "SIG_DFL" | "SIG_ERR" | "SIG_IGN"
3422         // This is not defined in vxWorks
3423         | "RTLD_DEFAULT"   => true,
3424         _ => false,
3425     });
3426     // FIXME
3427     cfg.skip_type(move |ty| match ty {
3428         "stat64" | "sighandler_t" | "off64_t" => true,
3429         _ => false,
3430     });
3431 
3432     cfg.skip_field_type(move |struct_, field| match (struct_, field) {
3433         ("siginfo_t", "si_value") | ("stat", "st_size") | ("sigaction", "sa_u") => true,
3434         _ => false,
3435     });
3436 
3437     cfg.skip_roundtrip(move |s| match s {
3438         _ => false,
3439     });
3440 
3441     cfg.type_name(move |ty, is_struct, is_union| match ty {
3442         "DIR" | "FILE" | "Dl_info" | "RTP_DESC" => ty.to_string(),
3443         t if is_union => format!("union {}", t),
3444         t if t.ends_with("_t") => t.to_string(),
3445         t if is_struct => format!("struct {}", t),
3446         t => t.to_string(),
3447     });
3448 
3449     // FIXME
3450     cfg.skip_fn(move |name| match name {
3451         // sigval
3452         "sigqueue" | "_sigqueue"
3453         // sighandler_t
3454         | "signal"
3455         // not used in static linking by default
3456         | "dlerror" => true,
3457         _ => false,
3458     });
3459 
3460     cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs");
3461 }
3462 
3463 fn test_linux(target: &str) {
3464     assert!(target.contains("linux"));
3465 
3466     // target_env
3467     let gnu = target.contains("gnu");
3468     let musl = target.contains("musl") || target.contains("ohos");
3469     let uclibc = target.contains("uclibc");
3470 
3471     match (gnu, musl, uclibc) {
3472         (true, false, false) => (),
3473         (false, true, false) => (),
3474         (false, false, true) => (),
3475         (_, _, _) => panic!(
3476             "linux target lib is gnu: {}, musl: {}, uclibc: {}",
3477             gnu, musl, uclibc
3478         ),
3479     }
3480 
3481     let arm = target.contains("arm");
3482     let aarch64 = target.contains("aarch64");
3483     let i686 = target.contains("i686");
3484     let ppc = target.contains("powerpc");
3485     let ppc64 = target.contains("powerpc64");
3486     let s390x = target.contains("s390x");
3487     let sparc64 = target.contains("sparc64");
3488     let x32 = target.contains("x32");
3489     let x86_32 = target.contains("i686");
3490     let x86_64 = target.contains("x86_64");
3491     let aarch64_musl = aarch64 && musl;
3492     let gnueabihf = target.contains("gnueabihf");
3493     let x86_64_gnux32 = target.contains("gnux32") && x86_64;
3494     let riscv64 = target.contains("riscv64");
3495     let loongarch64 = target.contains("loongarch64");
3496     let uclibc = target.contains("uclibc");
3497 
3498     let mut cfg = ctest_cfg();
3499     cfg.define("_GNU_SOURCE", None);
3500     // This macro re-defines fscanf,scanf,sscanf to link to the symbols that are
3501     // deprecated since glibc >= 2.29. This allows Rust binaries to link against
3502     // glibc versions older than 2.29.
3503     cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None);
3504 
3505     headers! { cfg:
3506                "ctype.h",
3507                "dirent.h",
3508                "dlfcn.h",
3509                "elf.h",
3510                "fcntl.h",
3511                "fnmatch.h",
3512                "getopt.h",
3513                "glob.h",
3514                [gnu]: "gnu/libc-version.h",
3515                "grp.h",
3516                "iconv.h",
3517                "ifaddrs.h",
3518                "langinfo.h",
3519                "libgen.h",
3520                "limits.h",
3521                "link.h",
3522                "linux/sysctl.h",
3523                "locale.h",
3524                "malloc.h",
3525                "mntent.h",
3526                "mqueue.h",
3527                "net/ethernet.h",
3528                "net/if.h",
3529                "net/if_arp.h",
3530                "net/route.h",
3531                "netdb.h",
3532                "netinet/in.h",
3533                "netinet/ip.h",
3534                "netinet/tcp.h",
3535                "netinet/udp.h",
3536                "poll.h",
3537                "pthread.h",
3538                "pty.h",
3539                "pwd.h",
3540                "regex.h",
3541                "resolv.h",
3542                "sched.h",
3543                "semaphore.h",
3544                "shadow.h",
3545                "signal.h",
3546                "spawn.h",
3547                "stddef.h",
3548                "stdint.h",
3549                "stdio.h",
3550                "stdlib.h",
3551                "string.h",
3552                "sys/epoll.h",
3553                "sys/eventfd.h",
3554                "sys/file.h",
3555                "sys/fsuid.h",
3556                "sys/klog.h",
3557                "sys/inotify.h",
3558                "sys/ioctl.h",
3559                "sys/ipc.h",
3560                "sys/mman.h",
3561                "sys/mount.h",
3562                "sys/msg.h",
3563                "sys/personality.h",
3564                "sys/prctl.h",
3565                "sys/ptrace.h",
3566                "sys/quota.h",
3567                "sys/random.h",
3568                "sys/reboot.h",
3569                "sys/resource.h",
3570                "sys/sem.h",
3571                "sys/sendfile.h",
3572                "sys/shm.h",
3573                "sys/signalfd.h",
3574                "sys/socket.h",
3575                "sys/stat.h",
3576                "sys/statvfs.h",
3577                "sys/swap.h",
3578                "sys/syscall.h",
3579                "sys/time.h",
3580                "sys/timerfd.h",
3581                "sys/times.h",
3582                "sys/timex.h",
3583                "sys/types.h",
3584                "sys/uio.h",
3585                "sys/un.h",
3586                "sys/user.h",
3587                "sys/utsname.h",
3588                "sys/vfs.h",
3589                "sys/wait.h",
3590                "syslog.h",
3591                "termios.h",
3592                "time.h",
3593                "ucontext.h",
3594                "unistd.h",
3595                "utime.h",
3596                "utmp.h",
3597                "utmpx.h",
3598                "wchar.h",
3599                "errno.h",
3600                // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit
3601                // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162
3602                // Also unavailable on gnueabihf with glibc 2.30.
3603                // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6b33f373c7b9199e00ba5fbafd94ac9bfb4337b1
3604                [(x86_64 || x86_32 || arm) && !gnueabihf]: "sys/io.h",
3605                // `sys/reg.h` is only available on x86 and x86_64
3606                [x86_64 || x86_32]: "sys/reg.h",
3607                // sysctl system call is deprecated and not available on musl
3608                // It is also unsupported in x32, deprecated since glibc 2.30:
3609                [!(x32 || musl || gnu)]: "sys/sysctl.h",
3610                // <execinfo.h> is not supported by musl:
3611                // https://www.openwall.com/lists/musl/2015/04/09/3
3612                // <execinfo.h> is not present on uclibc.
3613                [!(musl || uclibc)]: "execinfo.h",
3614     }
3615 
3616     // Include linux headers at the end:
3617     headers! {
3618         cfg:
3619         [loongarch64 || riscv64]: "asm/hwcap.h",
3620         "asm/mman.h",
3621         [gnu]: "linux/aio_abi.h",
3622         "linux/can.h",
3623         "linux/can/raw.h",
3624         "linux/can/j1939.h",
3625         "linux/dccp.h",
3626         "linux/errqueue.h",
3627         "linux/falloc.h",
3628         "linux/filter.h",
3629         "linux/fs.h",
3630         "linux/futex.h",
3631         "linux/genetlink.h",
3632         "linux/if.h",
3633         "linux/if_addr.h",
3634         "linux/if_alg.h",
3635         "linux/if_ether.h",
3636         "linux/if_packet.h",
3637         "linux/if_tun.h",
3638         "linux/if_xdp.h",
3639         "linux/input.h",
3640         "linux/ipv6.h",
3641         "linux/kexec.h",
3642         "linux/keyctl.h",
3643         "linux/magic.h",
3644         "linux/memfd.h",
3645         "linux/membarrier.h",
3646         "linux/mempolicy.h",
3647         "linux/mman.h",
3648         "linux/module.h",
3649         "linux/mount.h",
3650         "linux/net_tstamp.h",
3651         "linux/netfilter/nfnetlink.h",
3652         "linux/netfilter/nfnetlink_log.h",
3653         "linux/netfilter/nfnetlink_queue.h",
3654         "linux/netfilter/nf_tables.h",
3655         "linux/netfilter_arp.h",
3656         "linux/netfilter_bridge.h",
3657         "linux/netfilter_ipv4.h",
3658         "linux/netfilter_ipv6.h",
3659         "linux/netfilter_ipv6/ip6_tables.h",
3660         "linux/netlink.h",
3661         "linux/openat2.h",
3662         // FIXME: some items require Linux >= 5.6:
3663         "linux/ptp_clock.h",
3664         "linux/ptrace.h",
3665         "linux/quota.h",
3666         "linux/random.h",
3667         "linux/reboot.h",
3668         "linux/rtnetlink.h",
3669         "linux/sched.h",
3670         "linux/sctp.h",
3671         "linux/seccomp.h",
3672         "linux/sock_diag.h",
3673         "linux/sockios.h",
3674         "linux/tls.h",
3675         "linux/uinput.h",
3676         "linux/vm_sockets.h",
3677         "linux/wait.h",
3678         "linux/wireless.h",
3679         "sys/fanotify.h",
3680         // <sys/auxv.h> is not present on uclibc
3681         [!uclibc]: "sys/auxv.h",
3682         [gnu || musl]: "linux/close_range.h",
3683     }
3684 
3685     // note: aio.h must be included before sys/mount.h
3686     headers! {
3687         cfg:
3688         "sys/xattr.h",
3689         "sys/sysinfo.h",
3690         // AIO is not supported by uclibc:
3691         [!uclibc]: "aio.h",
3692     }
3693 
3694     cfg.type_name(move |ty, is_struct, is_union| {
3695         match ty {
3696             // Just pass all these through, no need for a "struct" prefix
3697             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr"
3698             | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr"
3699             | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(),
3700 
3701             "Ioctl" if gnu => "unsigned long".to_string(),
3702             "Ioctl" => "int".to_string(),
3703 
3704             // LFS64 types have been removed in musl 1.2.4+
3705             "off64_t" if musl => "off_t".to_string(),
3706 
3707             // typedefs don't need any keywords
3708             t if t.ends_with("_t") => t.to_string(),
3709             // put `struct` in front of all structs:.
3710             t if is_struct => format!("struct {}", t),
3711             // put `union` in front of all unions:
3712             t if is_union => format!("union {}", t),
3713 
3714             t => t.to_string(),
3715         }
3716     });
3717 
3718     cfg.field_name(move |struct_, field| {
3719         match field {
3720             // Our stat *_nsec fields normally don't actually exist but are part
3721             // of a timeval struct
3722             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
3723                 s.replace("e_nsec", ".tv_nsec")
3724             }
3725             // FIXME: epoll_event.data is actually a union in C, but in Rust
3726             // it is only a u64 because we only expose one field
3727             // http://man7.org/linux/man-pages/man2/epoll_wait.2.html
3728             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
3729             // The following structs have a field called `type` in C,
3730             // but `type` is a Rust keyword, so these fields are translated
3731             // to `type_` in Rust.
3732             "type_"
3733                 if struct_ == "input_event"
3734                     || struct_ == "input_mask"
3735                     || struct_ == "ff_effect" =>
3736             {
3737                 "type".to_string()
3738             }
3739 
3740             s => s.to_string(),
3741         }
3742     });
3743 
3744     cfg.skip_type(move |ty| {
3745         // FIXME: very recent additions to musl, not yet released.
3746         // also apparently some glibc versions
3747         if ty == "Elf32_Relr" || ty == "Elf64_Relr" {
3748             return true;
3749         }
3750         if sparc64 && (ty == "Elf32_Rela" || ty == "Elf64_Rela") {
3751             return true;
3752         }
3753         match ty {
3754             // FIXME: `sighandler_t` type is incorrect, see:
3755             // https://github.com/rust-lang/libc/issues/1359
3756             "sighandler_t" => true,
3757 
3758             // These cannot be tested when "resolv.h" is included and are tested
3759             // in the `linux_elf.rs` file.
3760             "Elf64_Phdr" | "Elf32_Phdr" => true,
3761 
3762             // This type is private on Linux. It is implemented as a C `enum`
3763             // (`c_uint`) and this clashes with the type of the `rlimit` APIs
3764             // which expect a `c_int` even though both are ABI compatible.
3765             "__rlimit_resource_t" => true,
3766             // on Linux, this is a volatile int
3767             "pthread_spinlock_t" => true,
3768 
3769             // For internal use only, to define architecture specific ioctl constants with a libc
3770             // specific type.
3771             "Ioctl" => true,
3772 
3773             // FIXME: "'__uint128' undeclared" in C
3774             "__uint128" => true,
3775 
3776             t => {
3777                 if musl {
3778                     // LFS64 types have been removed in musl 1.2.4+
3779                     t.ends_with("64") || t.ends_with("64_t")
3780                 } else {
3781                     false
3782                 }
3783             }
3784         }
3785     });
3786 
3787     cfg.skip_struct(move |ty| {
3788         if ty.starts_with("__c_anonymous_") {
3789             return true;
3790         }
3791 
3792         // FIXME: CI has old headers
3793         if ty == "ptp_sys_offset_extended" {
3794             return true;
3795         }
3796 
3797         // LFS64 types have been removed in musl 1.2.4+
3798         if musl && (ty.ends_with("64") || ty.ends_with("64_t")) {
3799             return true;
3800         }
3801 
3802         // FIXME: sparc64 CI has old headers
3803         if sparc64 && (ty == "uinput_ff_erase" || ty == "uinput_abs_setup") {
3804             return true;
3805         }
3806 
3807         // FIXME(#1558): passing by value corrupts the value for reasons not understood.
3808         if (gnu && sparc64) && (ty == "ip_mreqn" || ty == "hwtstamp_config") {
3809             return true;
3810         }
3811 
3812         // FIXME(rust-lang/rust#43894): pass by value for structs that are not an even 32/64 bits
3813         // on big-endian systems corrupts the value for unknown reasons.
3814         if (sparc64 || ppc || ppc64 || s390x)
3815             && (ty == "sockaddr_pkt"
3816                 || ty == "tpacket_auxdata"
3817                 || ty == "tpacket_hdr_variant1"
3818                 || ty == "tpacket_req3"
3819                 || ty == "tpacket_stats_v3"
3820                 || ty == "tpacket_req_u")
3821         {
3822             return true;
3823         }
3824 
3825         // FIXME: musl doesn't compile with `struct fanout_args` for unknown reasons.
3826         if musl && ty == "fanout_args" {
3827             return true;
3828         }
3829         if sparc64 && ty == "fanotify_event_info_error" {
3830             return true;
3831         }
3832 
3833         match ty {
3834             // These cannot be tested when "resolv.h" is included and are tested
3835             // in the `linux_elf.rs` file.
3836             "Elf64_Phdr" | "Elf32_Phdr" => true,
3837 
3838             // On Linux, the type of `ut_tv` field of `struct utmpx`
3839             // can be an anonymous struct, so an extra struct,
3840             // which is absent in glibc, has to be defined.
3841             "__timeval" => true,
3842 
3843             // FIXME: This is actually a union, not a struct
3844             "sigval" => true,
3845 
3846             // This type is tested in the `linux_termios.rs` file since there
3847             // are header conflicts when including them with all the other
3848             // structs.
3849             "termios2" => true,
3850 
3851             // FIXME: remove once we set minimum supported glibc version.
3852             // ucontext_t added a new field as of glibc 2.28; our struct definition is
3853             // conservative and omits the field, but that means the size doesn't match for newer
3854             // glibcs (see https://github.com/rust-lang/libc/issues/1410)
3855             "ucontext_t" if gnu => true,
3856 
3857             // FIXME: Somehow we cannot include headers correctly in glibc 2.30.
3858             // So let's ignore for now and re-visit later.
3859             // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085
3860             "statx" => true,
3861             "statx_timestamp" => true,
3862 
3863             // On Linux, the type of `ut_exit` field of struct `utmpx`
3864             // can be an anonymous struct, so an extra struct,
3865             // which is absent in musl, has to be defined.
3866             "__exit_status" if musl => true,
3867 
3868             // clone_args might differ b/w libc versions
3869             "clone_args" => true,
3870 
3871             // Might differ between kernel versions
3872             "open_how" => true,
3873 
3874             "sctp_initmsg" | "sctp_sndrcvinfo" | "sctp_sndinfo" | "sctp_rcvinfo"
3875             | "sctp_nxtinfo" | "sctp_prinfo" | "sctp_authinfo" => true,
3876 
3877             // FIXME: requires >= 6.1 kernel headers
3878             "canxl_frame" => true,
3879 
3880             // FIXME: The size of `iv` has been changed since Linux v6.0
3881             // https://github.com/torvalds/linux/commit/94dfc73e7cf4a31da66b8843f0b9283ddd6b8381
3882             "af_alg_iv" => true,
3883 
3884             // FIXME: Requires >= 5.1 kernel headers.
3885             // Everything that uses install-musl.sh has 4.19 kernel headers.
3886             "tls12_crypto_info_aes_gcm_256"
3887                 if (aarch64 || arm || i686 || s390x || x86_64) && musl =>
3888             {
3889                 true
3890             }
3891 
3892             // FIXME: Requires >= 5.11 kernel headers.
3893             // Everything that uses install-musl.sh has 4.19 kernel headers.
3894             "tls12_crypto_info_chacha20_poly1305"
3895                 if (aarch64 || arm || i686 || s390x || x86_64) && musl =>
3896             {
3897                 true
3898             }
3899 
3900             // FIXME: Requires >= 5.3 kernel headers.
3901             // Everything that uses install-musl.sh has 4.19 kernel headers.
3902             "xdp_options" if musl => true,
3903 
3904             // FIXME: Requires >= 5.4 kernel headers.
3905             // Everything that uses install-musl.sh has 4.19 kernel headers.
3906             "xdp_ring_offset" | "xdp_mmap_offsets" if musl => true,
3907 
3908             // FIXME: Requires >= 6.8 kernel headers.
3909             // A field was added in 6.8.
3910             // https://github.com/torvalds/linux/commit/341ac980eab90ac1f6c22ee9f9da83ed9604d899
3911             // The previous version of the struct was removed in 6.11 due to a bug.
3912             // https://github.com/torvalds/linux/commit/32654bbd6313b4cfc82297e6634fa9725c3c900f
3913             "xdp_umem_reg" => true,
3914 
3915             // FIXME: Requires >= 5.9 kernel headers.
3916             // Everything that uses install-musl.sh has 4.19 kernel headers.
3917             "xdp_statistics" if musl => true,
3918 
3919             // FIXME: Requires >= 6.8 kernel headers.
3920             "xsk_tx_metadata"
3921             | "__c_anonymous_xsk_tx_metadata_union"
3922             | "xsk_tx_metadata_request"
3923             | "xsk_tx_metadata_completion" => true,
3924 
3925             // A new field was added in kernel 5.4, this is the old version for backwards compatibility.
3926             // https://github.com/torvalds/linux/commit/77cd0d7b3f257fd0e3096b4fdcff1a7d38e99e10
3927             "xdp_ring_offset_v1" | "xdp_mmap_offsets_v1" => true,
3928 
3929             // Multiple new fields were added in kernel 5.9, this is the old version for backwards compatibility.
3930             // https://github.com/torvalds/linux/commit/77cd0d7b3f257fd0e3096b4fdcff1a7d38e99e10
3931             "xdp_statistics_v1" => true,
3932 
3933             // A new field was added in kernel 5.4, this is the old version for backwards compatibility.
3934             // https://github.com/torvalds/linux/commit/c05cd3645814724bdeb32a2b4d953b12bdea5f8c
3935             "xdp_umem_reg_v1" => true,
3936 
3937             // Is defined in `<linux/sched/types.h>` but if this file is included at the same time
3938             // as `<sched.h>`, the `struct sched_param` is defined twice, causing the compilation to
3939             // fail. The problem doesn't seem to be present in more recent versions of the linux
3940             // kernel so we can drop this and test the type once this new version is used in CI.
3941             "sched_attr" => true,
3942 
3943             // FIXME: Requires >= 6.9 kernel headers.
3944             "epoll_params" => true,
3945 
3946             _ => false,
3947         }
3948     });
3949 
3950     cfg.skip_const(move |name| {
3951         if !gnu {
3952             // Skip definitions from the kernel on non-glibc Linux targets.
3953             // They're libc-independent, so we only need to check them on one
3954             // libc. We don't want to break CI if musl or another libc doesn't
3955             // have the definitions yet. (We do still want to check them on
3956             // every glibc target, though, as some of them can vary by
3957             // architecture.)
3958             //
3959             // This is not an exhaustive list of kernel constants, just a list
3960             // of prefixes of all those that have appeared here or that get
3961             // updated regularly and seem likely to cause breakage.
3962             if name.starts_with("AF_")
3963                 || name.starts_with("ARPHRD_")
3964                 || name.starts_with("EPOLL")
3965                 || name.starts_with("F_")
3966                 || name.starts_with("FALLOC_FL_")
3967                 || name.starts_with("IFLA_")
3968                 || name.starts_with("KEXEC_")
3969                 || name.starts_with("MS_")
3970                 || name.starts_with("MSG_")
3971                 || name.starts_with("OPEN_TREE_")
3972                 || name.starts_with("P_")
3973                 || name.starts_with("PF_")
3974                 || name.starts_with("RLIMIT_")
3975                 || name.starts_with("RTEXT_FILTER_")
3976                 || name.starts_with("SOL_")
3977                 || name.starts_with("STATX_")
3978                 || name.starts_with("SW_")
3979                 || name.starts_with("SYS_")
3980                 || name.starts_with("TCP_")
3981                 || name.starts_with("UINPUT_")
3982                 || name.starts_with("VMADDR_")
3983             {
3984                 return true;
3985             }
3986         }
3987         if musl {
3988             // FIXME: Requires >= 5.0 kernel headers
3989             if name == "SECCOMP_GET_NOTIF_SIZES"
3990                || name == "SECCOMP_FILTER_FLAG_NEW_LISTENER"
3991                || name == "SECCOMP_FILTER_FLAG_TSYNC_ESRCH"
3992                || name == "SECCOMP_USER_NOTIF_FLAG_CONTINUE"  // requires >= 5.5
3993                || name == "SECCOMP_ADDFD_FLAG_SETFD"  // requires >= 5.9
3994                || name == "SECCOMP_ADDFD_FLAG_SEND"   // requires >= 5.9
3995                || name == "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV"  // requires >= 5.19
3996             {
3997                 return true;
3998             }
3999             // FIXME: Requires >= 4.20 kernel headers
4000             if name == "PTP_SYS_OFFSET_EXTENDED" {
4001                 return true;
4002             }
4003             // FIXME: Requires >= 5.4 kernel headers
4004             if name == "PTP_CLOCK_GETCAPS2"
4005                 || name == "PTP_ENABLE_PPS2"
4006                 || name == "PTP_EXTTS_REQUEST2"
4007                 || name == "PTP_PEROUT_REQUEST2"
4008                 || name == "PTP_PIN_GETFUNC2"
4009                 || name == "PTP_PIN_SETFUNC2"
4010                 || name == "PTP_SYS_OFFSET2"
4011                 || name == "PTP_SYS_OFFSET_PRECISE2"
4012                 || name == "PTP_SYS_OFFSET_EXTENDED2"
4013             {
4014                 return true;
4015             }
4016             // FIXME: Requires >= 5.4.1 kernel headers
4017             if name.starts_with("J1939")
4018                 || name.starts_with("RTEXT_FILTER_")
4019                 || name.starts_with("SO_J1939")
4020                 || name.starts_with("SCM_J1939")
4021             {
4022                 return true;
4023             }
4024             // FIXME: Requires >= 5.10 kernel headers
4025             if name.starts_with("MEMBARRIER_CMD_REGISTER")
4026                 || name.starts_with("MEMBARRIER_CMD_PRIVATE")
4027             {
4028                 return true;
4029             }
4030             // LFS64 types have been removed in musl 1.2.4+
4031             if name.starts_with("RLIM64") {
4032                 return true;
4033             }
4034             // CI fails because musl targets use Linux v4 kernel
4035             if name.starts_with("NI_IDN") {
4036                 return true;
4037             }
4038             // FIXME: Requires >= 6.3 kernel headers
4039             if loongarch64 && (name == "MFD_NOEXEC_SEAL" || name == "MFD_EXEC") {
4040                 return true;
4041             }
4042         }
4043         match name {
4044             // These constants are not available if gnu headers have been included
4045             // and can therefore not be tested here
4046             //
4047             // The IPV6 constants are tested in the `linux_ipv6.rs` tests:
4048             | "IPV6_FLOWINFO"
4049             | "IPV6_FLOWLABEL_MGR"
4050             | "IPV6_FLOWINFO_SEND"
4051             | "IPV6_FLOWINFO_FLOWLABEL"
4052             | "IPV6_FLOWINFO_PRIORITY"
4053             // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests:
4054             | "F_CANCELLK"
4055             | "F_ADD_SEALS"
4056             | "F_GET_SEALS"
4057             | "F_SEAL_SEAL"
4058             | "F_SEAL_SHRINK"
4059             | "F_SEAL_GROW"
4060             | "F_SEAL_WRITE" => true,
4061             // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests
4062             // because including `linux/if_arp.h` causes some conflicts:
4063             "ARPHRD_CAN" => true,
4064 
4065             // FIXME: deprecated: not available in any header
4066             // See: https://github.com/rust-lang/libc/issues/1356
4067             "ENOATTR" => true,
4068 
4069             // FIXME: SIGUNUSED was removed in glibc 2.26
4070             // Users should use SIGSYS instead.
4071             "SIGUNUSED" => true,
4072 
4073             // FIXME: conflicts with glibc headers and is tested in
4074             // `linux_termios.rs` below:
4075             | "BOTHER"
4076             | "IBSHIFT"
4077             | "TCGETS2"
4078             | "TCSETS2"
4079             | "TCSETSW2"
4080             | "TCSETSF2" => true,
4081 
4082             // FIXME: on musl the pthread types are defined a little differently
4083             // - these constants are used by the glibc implementation.
4084             n if musl && n.contains("__SIZEOF_PTHREAD") => true,
4085 
4086             // FIXME: It was extended to 4096 since glibc 2.31 (Linux 5.4).
4087             // We should do so after a while.
4088             "SOMAXCONN" if gnu => true,
4089 
4090             // deprecated: not available from Linux kernel 5.6:
4091             "VMADDR_CID_RESERVED" => true,
4092 
4093             // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP:
4094             | "IPPROTO_MAX"
4095             | "IPPROTO_ETHERNET"
4096             | "IPPROTO_MPTCP" => true,
4097 
4098             // FIXME: Not yet implemented on sparc64
4099             "SYS_clone3" if sparc64 => true,
4100 
4101             // FIXME: Not defined on ARM, gnueabihf, musl, PowerPC, riscv64, s390x, and sparc64.
4102             "SYS_memfd_secret" if arm | gnueabihf | musl | ppc | riscv64 | s390x | sparc64 => true,
4103 
4104             // FIXME: Added in Linux 5.16
4105             // https://github.com/torvalds/linux/commit/039c0ec9bb77446d7ada7f55f90af9299b28ca49
4106             "SYS_futex_waitv" => true,
4107 
4108             // FIXME: Added in Linux 5.17
4109             // https://github.com/torvalds/linux/commit/c6018b4b254971863bd0ad36bb5e7d0fa0f0ddb0
4110             "SYS_set_mempolicy_home_node" => true,
4111 
4112             // FIXME: Added in Linux 5.18
4113             // https://github.com/torvalds/linux/commit/8b5413647262dda8d8d0e07e14ea1de9ac7cf0b2
4114             "NFQA_PRIORITY" => true,
4115 
4116             // FIXME: requires more recent kernel headers on CI
4117             | "UINPUT_VERSION"
4118             | "SW_MAX"
4119             | "SW_CNT"
4120                 if ppc64 || riscv64 => true,
4121 
4122             // FIXME: requires more recent kernel headers on CI
4123             | "MFD_EXEC"
4124             | "MFD_NOEXEC_SEAL"
4125             | "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV"
4126                 if sparc64 => true,
4127 
4128             // FIXME: Not currently available in headers on ARM and musl.
4129             "NETLINK_GET_STRICT_CHK" if arm => true,
4130 
4131             // kernel constants not available in uclibc 1.0.34
4132             | "EXTPROC"
4133             | "IPPROTO_BEETPH"
4134             | "IPPROTO_MPLS"
4135             | "IPV6_HDRINCL"
4136             | "IPV6_MULTICAST_ALL"
4137             | "IPV6_PMTUDISC_INTERFACE"
4138             | "IPV6_PMTUDISC_OMIT"
4139             | "IPV6_ROUTER_ALERT_ISOLATE"
4140             | "PACKET_MR_UNICAST"
4141             | "RUSAGE_THREAD"
4142             | "SHM_EXEC"
4143             | "UDP_GRO"
4144             | "UDP_SEGMENT"
4145                 if uclibc => true,
4146 
4147             // headers conflicts with linux/pidfd.h
4148             "PIDFD_NONBLOCK" => true,
4149 
4150             // is a private value for kernel usage normally
4151             "FUSE_SUPER_MAGIC" => true,
4152 
4153             // linux 5.17 min
4154             "PR_SET_VMA" | "PR_SET_VMA_ANON_NAME" => true,
4155 
4156             // present in recent kernels only
4157             "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,
4158 
4159             // present in recent kernels only >= 5.13
4160             "PR_PAC_SET_ENABLED_KEYS" | "PR_PAC_GET_ENABLED_KEYS" => true,
4161             // present in recent kernels only >= 5.19
4162             "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,
4163 
4164             // Added in Linux 5.14
4165             "FUTEX_LOCK_PI2" => true,
4166 
4167             // Added in  linux 6.1
4168             "STATX_DIOALIGN"
4169             | "CAN_RAW_XL_FRAMES"
4170             | "CANXL_HDR_SIZE"
4171             | "CANXL_MAX_DLC"
4172             | "CANXL_MAX_DLC_MASK"
4173             | "CANXL_MAX_DLEN"
4174             | "CANXL_MAX_MTU"
4175             | "CANXL_MIN_DLC"
4176             | "CANXL_MIN_DLEN"
4177             | "CANXL_MIN_MTU"
4178             | "CANXL_MTU"
4179             | "CANXL_PRIO_BITS"
4180             | "CANXL_PRIO_MASK"
4181             | "CANXL_SEC"
4182             | "CANXL_XLF"
4183              => true,
4184 
4185             // FIXME: Parts of netfilter/nfnetlink*.h require more recent kernel headers:
4186             | "RTNLGRP_MCTP_IFADDR" // linux v5.17+
4187             | "RTNLGRP_TUNNEL" // linux v5.18+
4188             | "RTNLGRP_STATS" // linux v5.18+
4189                 => true,
4190 
4191             // FIXME: The below is no longer const in glibc 2.34:
4192             // https://github.com/bminor/glibc/commit/5d98a7dae955bafa6740c26eaba9c86060ae0344
4193             | "PTHREAD_STACK_MIN"
4194             | "SIGSTKSZ"
4195             | "MINSIGSTKSZ"
4196                 if gnu => true,
4197 
4198             // FIXME: Linux >= 5.16:
4199             // https://github.com/torvalds/linux/commit/42df6e1d221dddc0f2acf2be37e68d553ad65f96
4200             "NF_NETDEV_EGRESS" if sparc64 => true,
4201             // value changed
4202             "NF_NETDEV_NUMHOOKS" if sparc64 => true,
4203 
4204             // FIXME: requires Linux >= v5.8
4205             "IF_LINK_MODE_TESTING" if sparc64 => true,
4206 
4207             // DIFF(main): fixed in 1.0 with e9abac9ac2
4208             "CLONE_CLEAR_SIGHAND" | "CLONE_INTO_CGROUP" => true,
4209 
4210             // kernel 6.1 minimum
4211             "MADV_COLLAPSE" => true,
4212 
4213             // kernel 6.2 minimum
4214             "TUN_F_USO4" | "TUN_F_USO6" | "IFF_NO_CARRIER" => true,
4215 
4216             // FIXME: Requires more recent kernel headers
4217             | "IFLA_PARENT_DEV_NAME"     // linux v5.13+
4218             | "IFLA_PARENT_DEV_BUS_NAME" // linux v5.13+
4219             | "IFLA_GRO_MAX_SIZE"        // linux v5.16+
4220             | "IFLA_TSO_MAX_SIZE"        // linux v5.18+
4221             | "IFLA_TSO_MAX_SEGS"        // linux v5.18+
4222             | "IFLA_ALLMULTI"            // linux v6.0+
4223             | "MADV_DONTNEED_LOCKED"     // linux v5.18+
4224                 => true,
4225             "SCTP_FUTURE_ASSOC" | "SCTP_CURRENT_ASSOC" | "SCTP_ALL_ASSOC" | "SCTP_PEER_ADDR_THLDS_V2" => true, // linux 5.5+
4226 
4227             // kernel 6.5 minimum
4228             "MOVE_MOUNT_BENEATH" => true,
4229             // FIXME: Requires linux 6.1
4230             "ALG_SET_KEY_BY_KEY_SERIAL" | "ALG_SET_DRBG_ENTROPY" => true,
4231 
4232             // FIXME: Requires more recent kernel headers
4233             | "FAN_FS_ERROR"                      // linux v5.16+
4234             | "FAN_RENAME"                        // linux v5.17+
4235             | "FAN_REPORT_TARGET_FID"             // linux v5.17+
4236             | "FAN_REPORT_DFID_NAME_TARGET"       // linux v5.17+
4237             | "FAN_MARK_EVICTABLE"                // linux v5.19+
4238             | "FAN_MARK_IGNORE"                   // linux v6.0+
4239             | "FAN_MARK_IGNORE_SURV"              // linux v6.0+
4240             | "FAN_EVENT_INFO_TYPE_ERROR"         // linux v5.16+
4241             | "FAN_EVENT_INFO_TYPE_OLD_DFID_NAME" // linux v5.17+
4242             | "FAN_EVENT_INFO_TYPE_NEW_DFID_NAME" // linux v5.17+
4243             | "FAN_RESPONSE_INFO_NONE"            // linux v5.16+
4244             | "FAN_RESPONSE_INFO_AUDIT_RULE"      // linux v5.16+
4245             | "FAN_INFO"                          // linux v5.16+
4246                 => true,
4247 
4248             // musl doesn't use <linux/fanotify.h> in <sys/fanotify.h>
4249             "FAN_REPORT_PIDFD"
4250             | "FAN_REPORT_DIR_FID"
4251             | "FAN_REPORT_NAME"
4252             | "FAN_REPORT_DFID_NAME"
4253             | "FAN_EVENT_INFO_TYPE_DFID_NAME"
4254             | "FAN_EVENT_INFO_TYPE_DFID"
4255             | "FAN_EVENT_INFO_TYPE_PIDFD"
4256             | "FAN_NOPIDFD"
4257             | "FAN_EPIDFD"
4258             if musl => true,
4259 
4260             // FIXME: Requires linux 6.5
4261             "NFT_MSG_MAX" => true,
4262 
4263             // FIXME: Requires >= 6.6 kernel headers.
4264             "XDP_USE_SG"
4265             | "XDP_PKT_CONTD"
4266                 =>
4267             {
4268                 true
4269             }
4270 
4271             // FIXME: Requires >= 6.8 kernel headers.
4272             "XDP_UMEM_TX_SW_CSUM"
4273             | "XDP_TXMD_FLAGS_TIMESTAMP"
4274             | "XDP_TXMD_FLAGS_CHECKSUM"
4275             | "XDP_TX_METADATA"
4276                 =>
4277             {
4278                 true
4279             }
4280 
4281             // FIXME: Requires >= 6.11 kernel headers.
4282             "XDP_UMEM_TX_METADATA_LEN"
4283                 =>
4284             {
4285                 true
4286             }
4287 
4288             // FIXME: Requires >= 6.6 kernel headers.
4289             "SYS_fchmodat2" => true,
4290 
4291             // FIXME: Requires >= 6.10 kernel headers.
4292             "SYS_mseal" => true,
4293 
4294             // FIXME: seems to not be available all the time (from <include/linux/sched.h>:
4295             "PF_VCPU"
4296             | "PF_IDLE"
4297             | "PF_EXITING"
4298             | "PF_POSTCOREDUMP"
4299             | "PF_IO_WORKER"
4300             | "PF_WQ_WORKER"
4301             | "PF_FORKNOEXEC"
4302             | "PF_MCE_PROCESS"
4303             | "PF_SUPERPRIV"
4304             | "PF_DUMPCORE"
4305             | "PF_SIGNALED"
4306             | "PF_MEMALLOC"
4307             | "PF_NPROC_EXCEEDED"
4308             | "PF_USED_MATH"
4309             | "PF_USER_WORKER"
4310             | "PF_NOFREEZE"
4311             | "PF_KSWAPD"
4312             | "PF_MEMALLOC_NOFS"
4313             | "PF_MEMALLOC_NOIO"
4314             | "PF_LOCAL_THROTTLE"
4315             | "PF_KTHREAD"
4316             | "PF_RANDOMIZE"
4317             | "PF_NO_SETAFFINITY"
4318             | "PF_MCE_EARLY"
4319             | "PF_MEMALLOC_PIN"
4320             | "PF_BLOCK_TS"
4321             | "PF_SUSPEND_TASK" => true,
4322 
4323             // FIXME: Requires >= 6.9 kernel headers.
4324             "EPIOCSPARAMS"
4325             | "EPIOCGPARAMS" => true,
4326 
4327             // FIXME: Requires >= 6.11 kernel headers.
4328             "MAP_DROPPABLE" => true,
4329 
4330             _ => false,
4331         }
4332     });
4333 
4334     cfg.skip_fn(move |name| {
4335         // skip those that are manually verified
4336         match name {
4337             // FIXME: https://github.com/rust-lang/libc/issues/1272
4338             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
4339 
4340             // There are two versions of the sterror_r function, see
4341             //
4342             // https://linux.die.net/man/3/strerror_r
4343             //
4344             // An XSI-compliant version provided if:
4345             //
4346             // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
4347             //  && ! _GNU_SOURCE
4348             //
4349             // and a GNU specific version provided if _GNU_SOURCE is defined.
4350             //
4351             // libc provides bindings for the XSI-compliant version, which is
4352             // preferred for portable applications.
4353             //
4354             // We skip the test here since here _GNU_SOURCE is defined, and
4355             // test the XSI version below.
4356             "strerror_r" => true,
4357 
4358             // FIXME: Our API is unsound. The Rust API allows aliasing
4359             // pointers, but the C API requires pointers not to alias.
4360             // We should probably be at least using `&`/`&mut` here, see:
4361             // https://github.com/gnzlbg/ctest/issues/68
4362             "lio_listio" if musl => true,
4363 
4364             // Needs glibc 2.34 or later.
4365             "posix_spawn_file_actions_addclosefrom_np" if gnu && sparc64 => true,
4366             // Needs glibc 2.35 or later.
4367             "posix_spawn_file_actions_addtcsetpgrp_np" if gnu && sparc64 => true,
4368 
4369             // FIXME: Deprecated since glibc 2.30. Remove fn once upstream does.
4370             "sysctl" if gnu => true,
4371 
4372             // FIXME: It now takes c_void instead of timezone since glibc 2.31.
4373             "gettimeofday" if gnu => true,
4374 
4375             // These are all implemented as static inline functions in uclibc, so
4376             // they cannot be linked against.
4377             // If implementations are required, they might need to be implemented
4378             // in this crate.
4379             "posix_spawnattr_init" if uclibc => true,
4380             "posix_spawnattr_destroy" if uclibc => true,
4381             "posix_spawnattr_getsigdefault" if uclibc => true,
4382             "posix_spawnattr_setsigdefault" if uclibc => true,
4383             "posix_spawnattr_getsigmask" if uclibc => true,
4384             "posix_spawnattr_setsigmask" if uclibc => true,
4385             "posix_spawnattr_getflags" if uclibc => true,
4386             "posix_spawnattr_setflags" if uclibc => true,
4387             "posix_spawnattr_getpgroup" if uclibc => true,
4388             "posix_spawnattr_setpgroup" if uclibc => true,
4389             "posix_spawnattr_getschedpolicy" if uclibc => true,
4390             "posix_spawnattr_setschedpolicy" if uclibc => true,
4391             "posix_spawnattr_getschedparam" if uclibc => true,
4392             "posix_spawnattr_setschedparam" if uclibc => true,
4393             "posix_spawn_file_actions_init" if uclibc => true,
4394             "posix_spawn_file_actions_destroy" if uclibc => true,
4395 
4396             // uclibc defines the flags type as a uint, but dependent crates
4397             // assume it's a int instead.
4398             "getnameinfo" if uclibc => true,
4399 
4400             // FIXME: This needs musl 1.2.2 or later.
4401             "gettid" if musl => true,
4402 
4403             // Needs glibc 2.33 or later.
4404             "mallinfo2" => true,
4405 
4406             "reallocarray" if musl => true,
4407 
4408             // Not defined in uclibc as of 1.0.34
4409             "gettid" if uclibc => true,
4410 
4411             // Needs musl 1.2.3 or later.
4412             "pthread_getname_np" if musl => true,
4413 
4414             // pthread_sigqueue uses sigval, which was initially declared
4415             // as a struct but should be defined as a union. However due
4416             // to the issues described here: https://github.com/rust-lang/libc/issues/2816
4417             // it can't be changed from struct.
4418             "pthread_sigqueue" => true,
4419 
4420             // There are two versions of basename(3) on Linux with glibc, see
4421             //
4422             // https://man7.org/linux/man-pages/man3/basename.3.html
4423             //
4424             // If libgen.h is included, then the POSIX version will be available;
4425             // If _GNU_SOURCE is defined and string.h is included, then the GNU one
4426             // will be used.
4427             //
4428             // libc exposes both of them, providing a prefix to differentiate between
4429             // them.
4430             //
4431             // Because the name with prefix is not a valid symbol in C, we have to
4432             // skip the tests.
4433             "posix_basename" if gnu => true,
4434             "gnu_basename" if gnu => true,
4435 
4436             // FIXME: function pointers changed since Ubuntu 23.10
4437             "strtol" | "strtoll" | "strtoul" | "strtoull" | "fscanf" | "scanf" | "sscanf" => true,
4438 
4439             // Added in musl 1.2.5
4440             "preadv2" | "pwritev2" if musl => true,
4441 
4442             _ => false,
4443         }
4444     });
4445 
4446     cfg.skip_field_type(move |struct_, field| {
4447         // This is a weird union, don't check the type.
4448         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
4449         // sighandler_t type is super weird
4450         (struct_ == "sigaction" && field == "sa_sigaction") ||
4451         // __timeval type is a patch which doesn't exist in glibc
4452         (struct_ == "utmpx" && field == "ut_tv") ||
4453         // sigval is actually a union, but we pretend it's a struct
4454         (struct_ == "sigevent" && field == "sigev_value") ||
4455         // this one is an anonymous union
4456         (struct_ == "ff_effect" && field == "u") ||
4457         // `__exit_status` type is a patch which is absent in musl
4458         (struct_ == "utmpx" && field == "ut_exit" && musl) ||
4459         // `can_addr` is an anonymous union
4460         (struct_ == "sockaddr_can" && field == "can_addr") ||
4461         // `anonymous_1` is an anonymous union
4462         (struct_ == "ptp_perout_request" && field == "anonymous_1") ||
4463         // `anonymous_2` is an anonymous union
4464         (struct_ == "ptp_perout_request" && field == "anonymous_2") ||
4465         // FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers
4466         // FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers
4467         // the rsv field shrunk when those fields got added, so is omitted too
4468         (struct_ == "ptp_clock_caps" && (loongarch64 || sparc64) && (["adjust_phase", "max_phase_adj", "rsv"].contains(&field)))
4469     });
4470 
4471     cfg.volatile_item(|i| {
4472         use ctest::VolatileItemKind::*;
4473         match i {
4474             // aio_buf is a volatile void** but since we cannot express that in
4475             // Rust types, we have to explicitly tell the checker about it here:
4476             StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
4477             _ => false,
4478         }
4479     });
4480 
4481     cfg.skip_field(move |struct_, field| {
4482         // this is actually a union on linux, so we can't represent it well and
4483         // just insert some padding.
4484         (struct_ == "siginfo_t" && field == "_pad") ||
4485         // musl names this __dummy1 but it's still there
4486         (musl && struct_ == "glob_t" && field == "gl_flags") ||
4487         // musl seems to define this as an *anonymous* bitfield
4488         (musl && struct_ == "statvfs" && field == "__f_unused") ||
4489         // sigev_notify_thread_id is actually part of a sigev_un union
4490         (struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
4491         // signalfd had SIGSYS fields added in Linux 4.18, but no libc release
4492         // has them yet.
4493         (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" ||
4494                                            field == "_pad2" ||
4495                                            field == "ssi_syscall" ||
4496                                            field == "ssi_call_addr" ||
4497                                            field == "ssi_arch")) ||
4498         // FIXME: After musl 1.1.24, it have only one field `sched_priority`,
4499         // while other fields become reserved.
4500         (struct_ == "sched_param" && [
4501             "sched_ss_low_priority",
4502             "sched_ss_repl_period",
4503             "sched_ss_init_budget",
4504             "sched_ss_max_repl",
4505         ].contains(&field) && musl) ||
4506         // FIXME: After musl 1.1.24, the type becomes `int` instead of `unsigned short`.
4507         (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) ||
4508         // glibc uses unnamed fields here and Rust doesn't support that yet
4509         (struct_ == "timex" && field.starts_with("__unused")) ||
4510         // FIXME: It now takes mode_t since glibc 2.31 on some targets.
4511         (struct_ == "ipc_perm" && field == "mode"
4512             && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32)
4513         ) ||
4514         // the `u` field is in fact an anonymous union
4515         (gnu && struct_ == "ptrace_syscall_info" && (field == "u" || field == "pad")) ||
4516         // the vregs field is a `__uint128_t` C's type.
4517         (struct_ == "user_fpsimd_struct" && field == "vregs") ||
4518         // Linux >= 5.11 tweaked the `svm_zero` field of the `sockaddr_vm` struct.
4519         // https://github.com/torvalds/linux/commit/dc8eeef73b63ed8988224ba6b5ed19a615163a7f
4520         (struct_ == "sockaddr_vm" && field == "svm_zero") ||
4521         // the `ifr_ifru` field is an anonymous union
4522         (struct_ == "ifreq" && field == "ifr_ifru") ||
4523         // the `ifc_ifcu` field is an anonymous union
4524         (struct_ == "ifconf" && field == "ifc_ifcu") ||
4525         // glibc uses a single array `uregs` instead of individual fields.
4526         (struct_ == "user_regs" && arm) ||
4527         // the `ifr_ifrn` field is an anonymous union
4528         (struct_ == "iwreq" && field == "ifr_ifrn") ||
4529         // the `key` field is a zero-sized array
4530         (struct_ == "iw_encode_ext" && field == "key") ||
4531         // the `tcpi_snd_rcv_wscale` map two bitfield fields stored in a u8
4532         (struct_ == "tcp_info" && field == "tcpi_snd_rcv_wscale") ||
4533         // the `tcpi_delivery_fastopen_bitfields` map two bitfield fields stored in a u8
4534         (musl && struct_ == "tcp_info" && field == "tcpi_delivery_fastopen_bitfields") ||
4535         // either fsid_t or int[2] type
4536         (struct_ == "fanotify_event_info_fid" && field == "fsid") ||
4537         // `handle` is a VLA
4538         (struct_ == "fanotify_event_info_fid" && field == "handle") ||
4539         // `anonymous_1` is an anonymous union
4540         (struct_ == "ptp_perout_request" && field == "anonymous_1") ||
4541         // `anonymous_2` is an anonymous union
4542         (struct_ == "ptp_perout_request" && field == "anonymous_2") ||
4543         // FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers
4544         // FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers
4545         // the rsv field shrunk when those fields got added, so is omitted too
4546         (struct_ == "ptp_clock_caps" && (loongarch64 || sparc64) && (["adjust_phase", "max_phase_adj", "rsv"].contains(&field))) ||
4547         // invalid application of 'sizeof' to incomplete type 'long unsigned int[]'
4548         (musl && struct_ == "mcontext_t" && field == "__extcontext" && loongarch64) ||
4549         // FIXME(#4121): a new field was added from `f_spare`
4550         (struct_ == "statvfs" && field == "__f_spare") ||
4551         (struct_ == "statvfs64" && field == "__f_spare") ||
4552         // the `xsk_tx_metadata_union` field is an anonymous union
4553         (struct_ == "xsk_tx_metadata" && field == "xsk_tx_metadata_union")
4554     });
4555 
4556     cfg.skip_roundtrip(move |s| match s {
4557         // FIXME:
4558         "mcontext_t" if s390x => true,
4559         // FIXME: This is actually a union.
4560         "fpreg_t" if s390x => true,
4561 
4562         // The test doesn't work on some env:
4563         "ipv6_mreq"
4564         | "ip_mreq_source"
4565         | "sockaddr_in6"
4566         | "sockaddr_ll"
4567         | "in_pktinfo"
4568         | "arpreq"
4569         | "arpreq_old"
4570         | "sockaddr_un"
4571         | "ff_constant_effect"
4572         | "ff_ramp_effect"
4573         | "ff_condition_effect"
4574         | "Elf32_Ehdr"
4575         | "Elf32_Chdr"
4576         | "ucred"
4577         | "in6_pktinfo"
4578         | "sockaddr_nl"
4579         | "termios"
4580         | "nlmsgerr"
4581             if sparc64 && gnu =>
4582         {
4583             true
4584         }
4585 
4586         // The following types contain Flexible Array Member fields which have unspecified calling
4587         // convention. The roundtripping tests deliberately pass the structs by value to check "by
4588         // value" layout consistency, but this would be UB for the these types.
4589         "inotify_event" => true,
4590         "fanotify_event_info_fid" => true,
4591         "cmsghdr" => true,
4592 
4593         // FIXME: the call ABI of max_align_t is incorrect on these platforms:
4594         "max_align_t" if i686 || ppc64 => true,
4595 
4596         _ => false,
4597     });
4598 
4599     cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs");
4600 
4601     test_linux_like_apis(target);
4602 }
4603 
4604 // This function tests APIs that are incompatible to test when other APIs
4605 // are included (e.g. because including both sets of headers clashes)
4606 fn test_linux_like_apis(target: &str) {
4607     let gnu = target.contains("gnu");
4608     let musl = target.contains("musl") || target.contains("ohos");
4609     let linux = target.contains("linux");
4610     let emscripten = target.contains("emscripten");
4611     let android = target.contains("android");
4612     assert!(linux || android || emscripten);
4613 
4614     if linux || android || emscripten {
4615         // test strerror_r from the `string.h` header
4616         let mut cfg = ctest_cfg();
4617         cfg.skip_type(|_| true).skip_static(|_| true);
4618 
4619         headers! { cfg: "string.h" }
4620         cfg.skip_fn(|f| match f {
4621             "strerror_r" => false,
4622             _ => true,
4623         })
4624         .skip_const(|_| true)
4625         .skip_struct(|_| true);
4626         cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_strerror_r.rs");
4627     }
4628 
4629     if linux || android || emscripten {
4630         // test fcntl - see:
4631         // http://man7.org/linux/man-pages/man2/fcntl.2.html
4632         let mut cfg = ctest_cfg();
4633 
4634         if musl {
4635             cfg.header("fcntl.h");
4636         } else {
4637             cfg.header("linux/fcntl.h");
4638         }
4639 
4640         cfg.skip_type(|_| true)
4641             .skip_static(|_| true)
4642             .skip_struct(|_| true)
4643             .skip_fn(|_| true)
4644             .skip_const(move |name| match name {
4645                 // test fcntl constants:
4646                 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK"
4647                 | "F_SEAL_GROW" | "F_SEAL_WRITE" => false,
4648                 _ => true,
4649             })
4650             .type_name(move |ty, is_struct, is_union| match ty {
4651                 t if is_struct => format!("struct {}", t),
4652                 t if is_union => format!("union {}", t),
4653                 t => t.to_string(),
4654             });
4655 
4656         cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_fcntl.rs");
4657     }
4658 
4659     if linux || android {
4660         // test termios
4661         let mut cfg = ctest_cfg();
4662         cfg.header("asm/termbits.h");
4663         cfg.header("linux/termios.h");
4664         cfg.skip_type(|_| true)
4665             .skip_static(|_| true)
4666             .skip_fn(|_| true)
4667             .skip_const(|c| match c {
4668                 "BOTHER" | "IBSHIFT" => false,
4669                 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => false,
4670                 _ => true,
4671             })
4672             .skip_struct(|s| s != "termios2")
4673             .type_name(move |ty, is_struct, is_union| match ty {
4674                 "Ioctl" if gnu => "unsigned long".to_string(),
4675                 "Ioctl" => "int".to_string(),
4676                 t if is_struct => format!("struct {}", t),
4677                 t if is_union => format!("union {}", t),
4678                 t => t.to_string(),
4679             });
4680         cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_termios.rs");
4681     }
4682 
4683     if linux || android {
4684         // test IPV6_ constants:
4685         let mut cfg = ctest_cfg();
4686         headers! {
4687             cfg:
4688             "linux/in6.h"
4689         }
4690         cfg.skip_type(|_| true)
4691             .skip_static(|_| true)
4692             .skip_fn(|_| true)
4693             .skip_const(|_| true)
4694             .skip_struct(|_| true)
4695             .skip_const(move |name| match name {
4696                 "IPV6_FLOWINFO"
4697                 | "IPV6_FLOWLABEL_MGR"
4698                 | "IPV6_FLOWINFO_SEND"
4699                 | "IPV6_FLOWINFO_FLOWLABEL"
4700                 | "IPV6_FLOWINFO_PRIORITY" => false,
4701                 _ => true,
4702             })
4703             .type_name(move |ty, is_struct, is_union| match ty {
4704                 t if is_struct => format!("struct {}", t),
4705                 t if is_union => format!("union {}", t),
4706                 t => t.to_string(),
4707             });
4708         cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_ipv6.rs");
4709     }
4710 
4711     if linux || android {
4712         // Test Elf64_Phdr and Elf32_Phdr
4713         // These types have a field called `p_type`, but including
4714         // "resolve.h" defines a `p_type` macro that expands to `__p_type`
4715         // making the tests for these fails when both are included.
4716         let mut cfg = ctest_cfg();
4717         cfg.header("elf.h");
4718         cfg.skip_fn(|_| true)
4719             .skip_static(|_| true)
4720             .skip_const(|_| true)
4721             .type_name(move |ty, _is_struct, _is_union| ty.to_string())
4722             .skip_struct(move |ty| match ty {
4723                 "Elf64_Phdr" | "Elf32_Phdr" => false,
4724                 _ => true,
4725             })
4726             .skip_type(move |ty| match ty {
4727                 "Elf64_Phdr" | "Elf32_Phdr" => false,
4728                 _ => true,
4729             });
4730         cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_elf.rs");
4731     }
4732 
4733     if linux || android {
4734         // Test `ARPHRD_CAN`.
4735         let mut cfg = ctest_cfg();
4736         cfg.header("linux/if_arp.h");
4737         cfg.skip_fn(|_| true)
4738             .skip_static(|_| true)
4739             .skip_const(move |name| match name {
4740                 "ARPHRD_CAN" => false,
4741                 _ => true,
4742             })
4743             .skip_struct(|_| true)
4744             .skip_type(|_| true);
4745         cfg.generate(src_hotfix_dir().join("lib.rs"), "linux_if_arp.rs");
4746     }
4747 }
4748 
4749 fn which_freebsd() -> Option<i32> {
4750     if let Ok(version) = env::var("RUST_LIBC_UNSTABLE_FREEBSD_VERSION") {
4751         let vers = version.parse().unwrap();
4752         println!("cargo:warning=setting FreeBSD version to {vers}");
4753         return Some(vers);
4754     }
4755 
4756     let output = std::process::Command::new("freebsd-version")
4757         .output()
4758         .ok()?;
4759 
4760     if !output.status.success() {
4761         return None;
4762     }
4763 
4764     let stdout = String::from_utf8(output.stdout).ok()?;
4765 
4766     match &stdout {
4767         s if s.starts_with("10") => Some(10),
4768         s if s.starts_with("11") => Some(11),
4769         s if s.starts_with("12") => Some(12),
4770         s if s.starts_with("13") => Some(13),
4771         s if s.starts_with("14") => Some(14),
4772         s if s.starts_with("15") => Some(15),
4773         _ => None,
4774     }
4775 }
4776 
4777 fn test_haiku(target: &str) {
4778     assert!(target.contains("haiku"));
4779 
4780     let mut cfg = ctest_cfg();
4781     cfg.flag("-Wno-deprecated-declarations");
4782     cfg.define("__USE_GNU", Some("1"));
4783     cfg.define("_GNU_SOURCE", None);
4784     cfg.language(ctest::Lang::CXX);
4785 
4786     // POSIX API
4787     headers! { cfg:
4788                "alloca.h",
4789                "arpa/inet.h",
4790                "arpa/nameser.h",
4791                "arpa/nameser_compat.h",
4792                "assert.h",
4793                "complex.h",
4794                "ctype.h",
4795                "dirent.h",
4796                "div_t.h",
4797                "dlfcn.h",
4798                "endian.h",
4799                "errno.h",
4800                "fcntl.h",
4801                "fenv.h",
4802                "fnmatch.h",
4803                "fts.h",
4804                "ftw.h",
4805                "getopt.h",
4806                "glob.h",
4807                "grp.h",
4808                "inttypes.h",
4809                "iovec.h",
4810                "langinfo.h",
4811                "libgen.h",
4812                "libio.h",
4813                "limits.h",
4814                "locale.h",
4815                "malloc.h",
4816                "malloc_debug.h",
4817                "math.h",
4818                "memory.h",
4819                "monetary.h",
4820                "net/if.h",
4821                "net/if_dl.h",
4822                "net/if_media.h",
4823                "net/if_tun.h",
4824                "net/if_types.h",
4825                "net/route.h",
4826                "netdb.h",
4827                "netinet/in.h",
4828                "netinet/ip.h",
4829                "netinet/ip6.h",
4830                "netinet/ip_icmp.h",
4831                "netinet/ip_var.h",
4832                "netinet/tcp.h",
4833                "netinet/udp.h",
4834                "netinet6/in6.h",
4835                "nl_types.h",
4836                "null.h",
4837                "poll.h",
4838                "pthread.h",
4839                "pwd.h",
4840                "regex.h",
4841                "resolv.h",
4842                "sched.h",
4843                "search.h",
4844                "semaphore.h",
4845                "setjmp.h",
4846                "shadow.h",
4847                "signal.h",
4848                "size_t.h",
4849                "spawn.h",
4850                "stdint.h",
4851                "stdio.h",
4852                "stdlib.h",
4853                "string.h",
4854                "strings.h",
4855                "sys/cdefs.h",
4856                "sys/file.h",
4857                "sys/ioctl.h",
4858                "sys/ipc.h",
4859                "sys/mman.h",
4860                "sys/msg.h",
4861                "sys/param.h",
4862                "sys/poll.h",
4863                "sys/resource.h",
4864                "sys/select.h",
4865                "sys/sem.h",
4866                "sys/socket.h",
4867                "sys/sockio.h",
4868                "sys/stat.h",
4869                "sys/statvfs.h",
4870                "sys/time.h",
4871                "sys/timeb.h",
4872                "sys/times.h",
4873                "sys/types.h",
4874                "sys/uio.h",
4875                "sys/un.h",
4876                "sys/utsname.h",
4877                "sys/wait.h",
4878                "syslog.h",
4879                "tar.h",
4880                "termios.h",
4881                "time.h",
4882                "uchar.h",
4883                "unistd.h",
4884                "utime.h",
4885                "utmpx.h",
4886                "wchar.h",
4887                "wchar_t.h",
4888                "wctype.h"
4889     }
4890 
4891     // BSD Extensions
4892     headers! { cfg:
4893                "ifaddrs.h",
4894                "libutil.h",
4895                "link.h",
4896                "pty.h",
4897                "stdlib.h",
4898                "stringlist.h",
4899                "sys/link_elf.h",
4900     }
4901 
4902     // Native API
4903     headers! { cfg:
4904                "kernel/OS.h",
4905                "kernel/fs_attr.h",
4906                "kernel/fs_index.h",
4907                "kernel/fs_info.h",
4908                "kernel/fs_query.h",
4909                "kernel/fs_volume.h",
4910                "kernel/image.h",
4911                "kernel/scheduler.h",
4912                "storage/FindDirectory.h",
4913                "storage/StorageDefs.h",
4914                "support/Errors.h",
4915                "support/SupportDefs.h",
4916                "support/TypeConstants.h"
4917     }
4918 
4919     cfg.skip_struct(move |ty| {
4920         if ty.starts_with("__c_anonymous_") {
4921             return true;
4922         }
4923         match ty {
4924             // FIXME: actually a union
4925             "sigval" => true,
4926             // FIXME: locale_t does not exist on Haiku
4927             "locale_t" => true,
4928             // FIXME: rusage has a different layout on Haiku
4929             "rusage" => true,
4930             // FIXME?: complains that rust aligns on 4 byte boundary, but
4931             //         Haiku does not align it at all.
4932             "in6_addr" => true,
4933             // The d_name attribute is an array of 1 on Haiku, with the
4934             // intention that the developer allocates a larger or smaller
4935             // piece of memory depending on the expected/actual size of the name.
4936             // Other platforms have sensible defaults. In Rust, the d_name field
4937             // is sized as the _POSIX_MAX_PATH, so that path names will fit in
4938             // newly allocated dirent objects. This breaks the automated tests.
4939             "dirent" => true,
4940             // The following structs contain function pointers, which cannot be initialized
4941             // with mem::zeroed(), so skip the automated test
4942             "image_info" | "thread_info" => true,
4943 
4944             "Elf64_Phdr" => true,
4945 
4946             // is an union
4947             "cpuid_info" => true,
4948 
4949             _ => false,
4950         }
4951     });
4952 
4953     cfg.skip_type(move |ty| {
4954         match ty {
4955             // FIXME: locale_t does not exist on Haiku
4956             "locale_t" => true,
4957             // These cause errors, to be reviewed in the future
4958             "sighandler_t" => true,
4959             "pthread_t" => true,
4960             "pthread_condattr_t" => true,
4961             "pthread_mutexattr_t" => true,
4962             "pthread_rwlockattr_t" => true,
4963             _ => false,
4964         }
4965     });
4966 
4967     cfg.skip_fn(move |name| {
4968         // skip those that are manually verified
4969         match name {
4970             // FIXME: https://github.com/rust-lang/libc/issues/1272
4971             "execv" | "execve" | "execvp" | "execvpe" => true,
4972             // FIXME: does not exist on haiku
4973             "open_wmemstream" => true,
4974             "mlockall" | "munlockall" => true,
4975             "tcgetsid" => true,
4976             "cfsetspeed" => true,
4977             // ignore for now, will be part of Haiku R1 beta 3
4978             "mlock" | "munlock" => true,
4979             // returns const char * on Haiku
4980             "strsignal" => true,
4981             // uses an enum as a parameter argument, which is incorrectly
4982             // translated into a struct argument
4983             "find_path" => true,
4984 
4985             "get_cpuid" => true,
4986 
4987             // uses varargs parameter
4988             "ioctl" => true,
4989 
4990             _ => false,
4991         }
4992     });
4993 
4994     cfg.skip_const(move |name| {
4995         match name {
4996             // FIXME: these constants do not exist on Haiku
4997             "DT_UNKNOWN" | "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK"
4998             | "DT_SOCK" => true,
4999             "USRQUOTA" | "GRPQUOTA" => true,
5000             "SIGIOT" => true,
5001             "ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM" | "ATF_PUBL"
5002             | "ATF_USETRAILERS" => true,
5003             // Haiku does not have MAP_FILE, but rustc requires it
5004             "MAP_FILE" => true,
5005             // The following does not exist on Haiku but is required by
5006             // several crates
5007             "FIOCLEX" => true,
5008             // just skip this one, it is not defined on Haiku beta 2 but
5009             // since it is meant as a mask and not a parameter it can exist
5010             // here
5011             "LOG_PRIMASK" => true,
5012             // not defined on Haiku, but [get|set]priority is, so they are
5013             // useful
5014             "PRIO_MIN" | "PRIO_MAX" => true,
5015             //
5016             _ => false,
5017         }
5018     });
5019 
5020     cfg.skip_field(move |struct_, field| {
5021         match (struct_, field) {
5022             // FIXME: the stat struct actually has timespec members, whereas
5023             //        the current representation has these unpacked.
5024             ("stat", "st_atime") => true,
5025             ("stat", "st_atime_nsec") => true,
5026             ("stat", "st_mtime") => true,
5027             ("stat", "st_mtime_nsec") => true,
5028             ("stat", "st_ctime") => true,
5029             ("stat", "st_ctime_nsec") => true,
5030             ("stat", "st_crtime") => true,
5031             ("stat", "st_crtime_nsec") => true,
5032 
5033             // these are actually unions, but we cannot represent it well
5034             ("siginfo_t", "sigval") => true,
5035             ("sem_t", "named_sem_id") => true,
5036             ("sigaction", "sa_sigaction") => true,
5037             ("sigevent", "sigev_value") => true,
5038             ("fpu_state", "_fpreg") => true,
5039             ("cpu_topology_node_info", "data") => true,
5040             // these fields have a simplified data definition in libc
5041             ("fpu_state", "_xmm") => true,
5042             ("savefpu", "_fp_ymm") => true,
5043 
5044             // skip these enum-type fields
5045             ("thread_info", "state") => true,
5046             ("image_info", "image_type") => true,
5047             _ => false,
5048         }
5049     });
5050 
5051     cfg.skip_roundtrip(move |s| match s {
5052         // FIXME: for some reason the roundtrip check fails for cpu_info
5053         "cpu_info" => true,
5054         _ => false,
5055     });
5056 
5057     cfg.type_name(move |ty, is_struct, is_union| {
5058         match ty {
5059             // Just pass all these through, no need for a "struct" prefix
5060             "area_info"
5061             | "port_info"
5062             | "port_message_info"
5063             | "team_info"
5064             | "sem_info"
5065             | "team_usage_info"
5066             | "thread_info"
5067             | "cpu_info"
5068             | "system_info"
5069             | "object_wait_info"
5070             | "image_info"
5071             | "attr_info"
5072             | "index_info"
5073             | "fs_info"
5074             | "FILE"
5075             | "DIR"
5076             | "Dl_info"
5077             | "topology_level_type"
5078             | "cpu_topology_node_info"
5079             | "cpu_topology_root_info"
5080             | "cpu_topology_package_info"
5081             | "cpu_topology_core_info" => ty.to_string(),
5082 
5083             // enums don't need a prefix
5084             "directory_which" | "path_base_directory" | "cpu_platform" | "cpu_vendor" => {
5085                 ty.to_string()
5086             }
5087 
5088             // is actually a union
5089             "sigval" => format!("union sigval"),
5090             t if is_union => format!("union {}", t),
5091             t if t.ends_with("_t") => t.to_string(),
5092             t if is_struct => format!("struct {}", t),
5093             t => t.to_string(),
5094         }
5095     });
5096 
5097     cfg.field_name(move |struct_, field| {
5098         match field {
5099             // Field is named `type` in C but that is a Rust keyword,
5100             // so these fields are translated to `type_` in the bindings.
5101             "type_" if struct_ == "object_wait_info" => "type".to_string(),
5102             "type_" if struct_ == "sem_t" => "type".to_string(),
5103             "type_" if struct_ == "attr_info" => "type".to_string(),
5104             "type_" if struct_ == "index_info" => "type".to_string(),
5105             "type_" if struct_ == "cpu_topology_node_info" => "type".to_string(),
5106             "image_type" if struct_ == "image_info" => "type".to_string(),
5107             s => s.to_string(),
5108         }
5109     });
5110     cfg.generate(src_hotfix_dir().join("lib.rs"), "main.rs");
5111 }
5112