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