xref: /rust-libc-0.2.174/libc-test/build.rs (revision fe4def5d)
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         "linux/can/j1939.h",
3580         "linux/dccp.h",
3581         "linux/errqueue.h",
3582         "linux/falloc.h",
3583         "linux/filter.h",
3584         "linux/fs.h",
3585         "linux/futex.h",
3586         "linux/genetlink.h",
3587         "linux/if.h",
3588         "linux/if_addr.h",
3589         "linux/if_alg.h",
3590         "linux/if_ether.h",
3591         "linux/if_packet.h",
3592         "linux/if_tun.h",
3593         "linux/if_xdp.h",
3594         "linux/input.h",
3595         "linux/ipv6.h",
3596         "linux/kexec.h",
3597         "linux/keyctl.h",
3598         "linux/magic.h",
3599         "linux/memfd.h",
3600         "linux/membarrier.h",
3601         "linux/mempolicy.h",
3602         "linux/mman.h",
3603         "linux/module.h",
3604         "linux/mount.h",
3605         "linux/net_tstamp.h",
3606         "linux/netfilter/nfnetlink.h",
3607         "linux/netfilter/nfnetlink_log.h",
3608         "linux/netfilter/nfnetlink_queue.h",
3609         "linux/netfilter/nf_tables.h",
3610         "linux/netfilter_arp.h",
3611         "linux/netfilter_bridge.h",
3612         "linux/netfilter_ipv4.h",
3613         "linux/netfilter_ipv6.h",
3614         "linux/netfilter_ipv6/ip6_tables.h",
3615         "linux/netlink.h",
3616         "linux/openat2.h",
3617         // FIXME: some items require Linux >= 5.6:
3618         "linux/ptp_clock.h",
3619         "linux/ptrace.h",
3620         "linux/quota.h",
3621         "linux/random.h",
3622         "linux/reboot.h",
3623         "linux/rtnetlink.h",
3624         "linux/sched.h",
3625         "linux/sctp.h",
3626         "linux/seccomp.h",
3627         "linux/sock_diag.h",
3628         "linux/sockios.h",
3629         "linux/tls.h",
3630         "linux/uinput.h",
3631         "linux/vm_sockets.h",
3632         "linux/wait.h",
3633         "linux/wireless.h",
3634         "sys/fanotify.h",
3635         // <sys/auxv.h> is not present on uclibc
3636         [!uclibc]: "sys/auxv.h",
3637         [gnu || musl]: "linux/close_range.h",
3638     }
3639 
3640     // note: aio.h must be included before sys/mount.h
3641     headers! {
3642         cfg:
3643         "sys/xattr.h",
3644         "sys/sysinfo.h",
3645         // AIO is not supported by uclibc:
3646         [!uclibc]: "aio.h",
3647     }
3648 
3649     cfg.type_name(move |ty, is_struct, is_union| {
3650         match ty {
3651             // Just pass all these through, no need for a "struct" prefix
3652             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr"
3653             | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr"
3654             | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(),
3655 
3656             "Ioctl" if gnu => "unsigned long".to_string(),
3657             "Ioctl" => "int".to_string(),
3658 
3659             // LFS64 types have been removed in musl 1.2.4+
3660             "off64_t" if musl => "off_t".to_string(),
3661 
3662             // typedefs don't need any keywords
3663             t if t.ends_with("_t") => t.to_string(),
3664             // put `struct` in front of all structs:.
3665             t if is_struct => format!("struct {}", t),
3666             // put `union` in front of all unions:
3667             t if is_union => format!("union {}", t),
3668 
3669             t => t.to_string(),
3670         }
3671     });
3672 
3673     cfg.field_name(move |struct_, field| {
3674         match field {
3675             // Our stat *_nsec fields normally don't actually exist but are part
3676             // of a timeval struct
3677             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
3678                 s.replace("e_nsec", ".tv_nsec")
3679             }
3680             // FIXME: epoll_event.data is actually a union in C, but in Rust
3681             // it is only a u64 because we only expose one field
3682             // http://man7.org/linux/man-pages/man2/epoll_wait.2.html
3683             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
3684             // The following structs have a field called `type` in C,
3685             // but `type` is a Rust keyword, so these fields are translated
3686             // to `type_` in Rust.
3687             "type_"
3688                 if struct_ == "input_event"
3689                     || struct_ == "input_mask"
3690                     || struct_ == "ff_effect" =>
3691             {
3692                 "type".to_string()
3693             }
3694 
3695             s => s.to_string(),
3696         }
3697     });
3698 
3699     cfg.skip_type(move |ty| {
3700         // FIXME: very recent additions to musl, not yet released.
3701         // also apparently some glibc versions
3702         if ty == "Elf32_Relr" || ty == "Elf64_Relr" {
3703             return true;
3704         }
3705         if sparc64 && (ty == "Elf32_Rela" || ty == "Elf64_Rela") {
3706             return true;
3707         }
3708         match ty {
3709             // FIXME: `sighandler_t` type is incorrect, see:
3710             // https://github.com/rust-lang/libc/issues/1359
3711             "sighandler_t" => true,
3712 
3713             // These cannot be tested when "resolv.h" is included and are tested
3714             // in the `linux_elf.rs` file.
3715             "Elf64_Phdr" | "Elf32_Phdr" => true,
3716 
3717             // This type is private on Linux. It is implemented as a C `enum`
3718             // (`c_uint`) and this clashes with the type of the `rlimit` APIs
3719             // which expect a `c_int` even though both are ABI compatible.
3720             "__rlimit_resource_t" => true,
3721             // on Linux, this is a volatile int
3722             "pthread_spinlock_t" => true,
3723 
3724             // For internal use only, to define architecture specific ioctl constants with a libc
3725             // specific type.
3726             "Ioctl" => true,
3727 
3728             // FIXME: "'__uint128' undeclared" in C
3729             "__uint128" => true,
3730 
3731             t => {
3732                 if musl {
3733                     // LFS64 types have been removed in musl 1.2.4+
3734                     t.ends_with("64") || t.ends_with("64_t")
3735                 } else {
3736                     false
3737                 }
3738             }
3739         }
3740     });
3741 
3742     cfg.skip_struct(move |ty| {
3743         if ty.starts_with("__c_anonymous_") {
3744             return true;
3745         }
3746 
3747         // FIXME: CI has old headers
3748         if ty == "ptp_sys_offset_extended" {
3749             return true;
3750         }
3751 
3752         // LFS64 types have been removed in musl 1.2.4+
3753         if musl && (ty.ends_with("64") || ty.ends_with("64_t")) {
3754             return true;
3755         }
3756 
3757         // FIXME: sparc64 CI has old headers
3758         if sparc64 && (ty == "uinput_ff_erase" || ty == "uinput_abs_setup") {
3759             return true;
3760         }
3761 
3762         // FIXME(#1558): passing by value corrupts the value for reasons not understood.
3763         if (gnu && sparc64) && (ty == "ip_mreqn" || ty == "hwtstamp_config") {
3764             return true;
3765         }
3766 
3767         // FIXME(rust-lang/rust#43894): pass by value for structs that are not an even 32/64 bits
3768         // on big-endian systems corrupts the value for unknown reasons.
3769         if (sparc64 || ppc || ppc64 || s390x)
3770             && (ty == "sockaddr_pkt"
3771                 || ty == "tpacket_auxdata"
3772                 || ty == "tpacket_hdr_variant1"
3773                 || ty == "tpacket_req3"
3774                 || ty == "tpacket_stats_v3"
3775                 || ty == "tpacket_req_u")
3776         {
3777             return true;
3778         }
3779 
3780         // FIXME: musl doesn't compile with `struct fanout_args` for unknown reasons.
3781         if musl && ty == "fanout_args" {
3782             return true;
3783         }
3784         if sparc64 && ty == "fanotify_event_info_error" {
3785             return true;
3786         }
3787 
3788         match ty {
3789             // These cannot be tested when "resolv.h" is included and are tested
3790             // in the `linux_elf.rs` file.
3791             "Elf64_Phdr" | "Elf32_Phdr" => true,
3792 
3793             // On Linux, the type of `ut_tv` field of `struct utmpx`
3794             // can be an anonymous struct, so an extra struct,
3795             // which is absent in glibc, has to be defined.
3796             "__timeval" => true,
3797 
3798             // FIXME: This is actually a union, not a struct
3799             "sigval" => true,
3800 
3801             // This type is tested in the `linux_termios.rs` file since there
3802             // are header conflicts when including them with all the other
3803             // structs.
3804             "termios2" => true,
3805 
3806             // FIXME: remove once we set minimum supported glibc version.
3807             // ucontext_t added a new field as of glibc 2.28; our struct definition is
3808             // conservative and omits the field, but that means the size doesn't match for newer
3809             // glibcs (see https://github.com/rust-lang/libc/issues/1410)
3810             "ucontext_t" if gnu => true,
3811 
3812             // FIXME: Somehow we cannot include headers correctly in glibc 2.30.
3813             // So let's ignore for now and re-visit later.
3814             // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085
3815             "statx" => true,
3816             "statx_timestamp" => true,
3817 
3818             // On Linux, the type of `ut_exit` field of struct `utmpx`
3819             // can be an anonymous struct, so an extra struct,
3820             // which is absent in musl, has to be defined.
3821             "__exit_status" if musl => true,
3822 
3823             // clone_args might differ b/w libc versions
3824             "clone_args" => true,
3825 
3826             // Might differ between kernel versions
3827             "open_how" => true,
3828 
3829             "sctp_initmsg" | "sctp_sndrcvinfo" | "sctp_sndinfo" | "sctp_rcvinfo"
3830             | "sctp_nxtinfo" | "sctp_prinfo" | "sctp_authinfo" => true,
3831 
3832             // FIXME: requires >= 6.1 kernel headers
3833             "canxl_frame" => true,
3834 
3835             // FIXME: The size of `iv` has been changed since Linux v6.0
3836             // https://github.com/torvalds/linux/commit/94dfc73e7cf4a31da66b8843f0b9283ddd6b8381
3837             "af_alg_iv" => true,
3838 
3839             // FIXME: Requires >= 5.1 kernel headers.
3840             // Everything that uses install-musl.sh has 4.19 kernel headers.
3841             "tls12_crypto_info_aes_gcm_256"
3842                 if (aarch64 || arm || i686 || s390x || x86_64) && musl =>
3843             {
3844                 true
3845             }
3846 
3847             // FIXME: Requires >= 5.11 kernel headers.
3848             // Everything that uses install-musl.sh has 4.19 kernel headers.
3849             "tls12_crypto_info_chacha20_poly1305"
3850                 if (aarch64 || arm || i686 || s390x || x86_64) && musl =>
3851             {
3852                 true
3853             }
3854 
3855             // FIXME: Requires >= 5.3 kernel headers.
3856             // Everything that uses install-musl.sh has 4.19 kernel headers.
3857             "xdp_options" if musl => true,
3858 
3859             // FIXME: Requires >= 5.4 kernel headers.
3860             // Everything that uses install-musl.sh has 4.19 kernel headers.
3861             "xdp_ring_offset" | "xdp_mmap_offsets" if musl => true,
3862 
3863             // FIXME: Requires >= 6.8 kernel headers.
3864             // A field was added in 6.8.
3865             // https://github.com/torvalds/linux/commit/341ac980eab90ac1f6c22ee9f9da83ed9604d899
3866             // The previous version of the struct was removed in 6.11 due to a bug.
3867             // https://github.com/torvalds/linux/commit/32654bbd6313b4cfc82297e6634fa9725c3c900f
3868             "xdp_umem_reg" => true,
3869 
3870             // FIXME: Requires >= 5.9 kernel headers.
3871             // Everything that uses install-musl.sh has 4.19 kernel headers.
3872             "xdp_statistics" if musl => true,
3873 
3874             // FIXME: Requires >= 6.8 kernel headers.
3875             "xsk_tx_metadata"
3876             | "__c_anonymous_xsk_tx_metadata_union"
3877             | "xsk_tx_metadata_request"
3878             | "xsk_tx_metadata_completion" => true,
3879 
3880             // A new field was added in kernel 5.4, this is the old version for backwards compatibility.
3881             // https://github.com/torvalds/linux/commit/77cd0d7b3f257fd0e3096b4fdcff1a7d38e99e10
3882             "xdp_ring_offset_v1" | "xdp_mmap_offsets_v1" => true,
3883 
3884             // Multiple new fields were added in kernel 5.9, this is the old version for backwards compatibility.
3885             // https://github.com/torvalds/linux/commit/77cd0d7b3f257fd0e3096b4fdcff1a7d38e99e10
3886             "xdp_statistics_v1" => true,
3887 
3888             // A new field was added in kernel 5.4, this is the old version for backwards compatibility.
3889             // https://github.com/torvalds/linux/commit/c05cd3645814724bdeb32a2b4d953b12bdea5f8c
3890             "xdp_umem_reg_v1" => true,
3891 
3892             // Is defined in `<linux/sched/types.h>` but if this file is included at the same time
3893             // as `<sched.h>`, the `struct sched_param` is defined twice, causing the compilation to
3894             // fail. The problem doesn't seem to be present in more recent versions of the linux
3895             // kernel so we can drop this and test the type once this new version is used in CI.
3896             "sched_attr" => true,
3897 
3898             // FIXME: Requires >= 6.9 kernel headers.
3899             "epoll_params" => true,
3900 
3901             _ => false,
3902         }
3903     });
3904 
3905     cfg.skip_const(move |name| {
3906         if !gnu {
3907             // Skip definitions from the kernel on non-glibc Linux targets.
3908             // They're libc-independent, so we only need to check them on one
3909             // libc. We don't want to break CI if musl or another libc doesn't
3910             // have the definitions yet. (We do still want to check them on
3911             // every glibc target, though, as some of them can vary by
3912             // architecture.)
3913             //
3914             // This is not an exhaustive list of kernel constants, just a list
3915             // of prefixes of all those that have appeared here or that get
3916             // updated regularly and seem likely to cause breakage.
3917             if name.starts_with("AF_")
3918                 || name.starts_with("ARPHRD_")
3919                 || name.starts_with("EPOLL")
3920                 || name.starts_with("F_")
3921                 || name.starts_with("FALLOC_FL_")
3922                 || name.starts_with("IFLA_")
3923                 || name.starts_with("KEXEC_")
3924                 || name.starts_with("MS_")
3925                 || name.starts_with("MSG_")
3926                 || name.starts_with("OPEN_TREE_")
3927                 || name.starts_with("P_")
3928                 || name.starts_with("PF_")
3929                 || name.starts_with("RLIMIT_")
3930                 || name.starts_with("RTEXT_FILTER_")
3931                 || name.starts_with("SOL_")
3932                 || name.starts_with("STATX_")
3933                 || name.starts_with("SW_")
3934                 || name.starts_with("SYS_")
3935                 || name.starts_with("TCP_")
3936                 || name.starts_with("UINPUT_")
3937                 || name.starts_with("VMADDR_")
3938             {
3939                 return true;
3940             }
3941         }
3942         if musl {
3943             // FIXME: Requires >= 5.0 kernel headers
3944             if name == "SECCOMP_GET_NOTIF_SIZES"
3945                || name == "SECCOMP_FILTER_FLAG_NEW_LISTENER"
3946                || name == "SECCOMP_FILTER_FLAG_TSYNC_ESRCH"
3947                || name == "SECCOMP_USER_NOTIF_FLAG_CONTINUE"  // requires >= 5.5
3948                || name == "SECCOMP_ADDFD_FLAG_SETFD"  // requires >= 5.9
3949                || name == "SECCOMP_ADDFD_FLAG_SEND"   // requires >= 5.9
3950                || name == "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV"  // requires >= 5.19
3951             {
3952                 return true;
3953             }
3954             // FIXME: Requires >= 4.20 kernel headers
3955             if name == "PTP_SYS_OFFSET_EXTENDED" {
3956                 return true;
3957             }
3958             // FIXME: Requires >= 5.4 kernel headers
3959             if name == "PTP_CLOCK_GETCAPS2"
3960                 || name == "PTP_ENABLE_PPS2"
3961                 || name == "PTP_EXTTS_REQUEST2"
3962                 || name == "PTP_PEROUT_REQUEST2"
3963                 || name == "PTP_PIN_GETFUNC2"
3964                 || name == "PTP_PIN_SETFUNC2"
3965                 || name == "PTP_SYS_OFFSET2"
3966                 || name == "PTP_SYS_OFFSET_PRECISE2"
3967                 || name == "PTP_SYS_OFFSET_EXTENDED2"
3968             {
3969                 return true;
3970             }
3971             // FIXME: Requires >= 5.4.1 kernel headers
3972             if name.starts_with("J1939")
3973                 || name.starts_with("RTEXT_FILTER_")
3974                 || name.starts_with("SO_J1939")
3975                 || name.starts_with("SCM_J1939")
3976             {
3977                 return true;
3978             }
3979             // FIXME: Requires >= 5.10 kernel headers
3980             if name.starts_with("MEMBARRIER_CMD_REGISTER")
3981                 || name.starts_with("MEMBARRIER_CMD_PRIVATE")
3982             {
3983                 return true;
3984             }
3985             // LFS64 types have been removed in musl 1.2.4+
3986             if name.starts_with("RLIM64") {
3987                 return true;
3988             }
3989             // CI fails because musl targets use Linux v4 kernel
3990             if name.starts_with("NI_IDN") {
3991                 return true;
3992             }
3993             // FIXME: Requires >= 6.3 kernel headers
3994             if loongarch64 && (name == "MFD_NOEXEC_SEAL" || name == "MFD_EXEC") {
3995                 return true;
3996             }
3997         }
3998         match name {
3999             // These constants are not available if gnu headers have been included
4000             // and can therefore not be tested here
4001             //
4002             // The IPV6 constants are tested in the `linux_ipv6.rs` tests:
4003             | "IPV6_FLOWINFO"
4004             | "IPV6_FLOWLABEL_MGR"
4005             | "IPV6_FLOWINFO_SEND"
4006             | "IPV6_FLOWINFO_FLOWLABEL"
4007             | "IPV6_FLOWINFO_PRIORITY"
4008             // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests:
4009             | "F_CANCELLK"
4010             | "F_ADD_SEALS"
4011             | "F_GET_SEALS"
4012             | "F_SEAL_SEAL"
4013             | "F_SEAL_SHRINK"
4014             | "F_SEAL_GROW"
4015             | "F_SEAL_WRITE" => true,
4016             // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests
4017             // because including `linux/if_arp.h` causes some conflicts:
4018             "ARPHRD_CAN" => true,
4019 
4020             // FIXME: deprecated: not available in any header
4021             // See: https://github.com/rust-lang/libc/issues/1356
4022             "ENOATTR" => true,
4023 
4024             // FIXME: SIGUNUSED was removed in glibc 2.26
4025             // Users should use SIGSYS instead.
4026             "SIGUNUSED" => true,
4027 
4028             // FIXME: conflicts with glibc headers and is tested in
4029             // `linux_termios.rs` below:
4030             | "BOTHER"
4031             | "IBSHIFT"
4032             | "TCGETS2"
4033             | "TCSETS2"
4034             | "TCSETSW2"
4035             | "TCSETSF2" => true,
4036 
4037             // FIXME: on musl the pthread types are defined a little differently
4038             // - these constants are used by the glibc implementation.
4039             n if musl && n.contains("__SIZEOF_PTHREAD") => true,
4040 
4041             // FIXME: It was extended to 4096 since glibc 2.31 (Linux 5.4).
4042             // We should do so after a while.
4043             "SOMAXCONN" if gnu => true,
4044 
4045             // deprecated: not available from Linux kernel 5.6:
4046             "VMADDR_CID_RESERVED" => true,
4047 
4048             // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP:
4049             | "IPPROTO_MAX"
4050             | "IPPROTO_ETHERNET"
4051             | "IPPROTO_MPTCP" => true,
4052 
4053             // FIXME: Not yet implemented on sparc64
4054             "SYS_clone3" if sparc64 => true,
4055 
4056             // FIXME: Not defined on ARM, gnueabihf, musl, PowerPC, riscv64, s390x, and sparc64.
4057             "SYS_memfd_secret" if arm | gnueabihf | musl | ppc | riscv64 | s390x | sparc64 => true,
4058 
4059             // FIXME: Added in Linux 5.16
4060             // https://github.com/torvalds/linux/commit/039c0ec9bb77446d7ada7f55f90af9299b28ca49
4061             "SYS_futex_waitv" => true,
4062 
4063             // FIXME: Added in Linux 5.17
4064             // https://github.com/torvalds/linux/commit/c6018b4b254971863bd0ad36bb5e7d0fa0f0ddb0
4065             "SYS_set_mempolicy_home_node" => true,
4066 
4067             // FIXME: Added in Linux 5.18
4068             // https://github.com/torvalds/linux/commit/8b5413647262dda8d8d0e07e14ea1de9ac7cf0b2
4069             "NFQA_PRIORITY" => true,
4070 
4071             // FIXME: requires more recent kernel headers on CI
4072             | "UINPUT_VERSION"
4073             | "SW_MAX"
4074             | "SW_CNT"
4075                 if ppc64 || riscv64 => true,
4076 
4077             // FIXME: requires more recent kernel headers on CI
4078             | "MFD_EXEC"
4079             | "MFD_NOEXEC_SEAL"
4080             | "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV"
4081                 if sparc64 => true,
4082 
4083             // FIXME: Not currently available in headers on ARM and musl.
4084             "NETLINK_GET_STRICT_CHK" if arm => true,
4085 
4086             // kernel constants not available in uclibc 1.0.34
4087             | "EXTPROC"
4088             | "IPPROTO_BEETPH"
4089             | "IPPROTO_MPLS"
4090             | "IPV6_HDRINCL"
4091             | "IPV6_MULTICAST_ALL"
4092             | "IPV6_PMTUDISC_INTERFACE"
4093             | "IPV6_PMTUDISC_OMIT"
4094             | "IPV6_ROUTER_ALERT_ISOLATE"
4095             | "PACKET_MR_UNICAST"
4096             | "RUSAGE_THREAD"
4097             | "SHM_EXEC"
4098             | "UDP_GRO"
4099             | "UDP_SEGMENT"
4100                 if uclibc => true,
4101 
4102             // headers conflicts with linux/pidfd.h
4103             "PIDFD_NONBLOCK" => true,
4104 
4105             // is a private value for kernel usage normally
4106             "FUSE_SUPER_MAGIC" => true,
4107 
4108             // linux 5.17 min
4109             "PR_SET_VMA" | "PR_SET_VMA_ANON_NAME" => true,
4110 
4111             // present in recent kernels only
4112             "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,
4113 
4114             // present in recent kernels only >= 5.13
4115             "PR_PAC_SET_ENABLED_KEYS" | "PR_PAC_GET_ENABLED_KEYS" => true,
4116             // present in recent kernels only >= 5.19
4117             "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,
4118 
4119             // Added in Linux 5.14
4120             "FUTEX_LOCK_PI2" => true,
4121 
4122             // Added in  linux 6.1
4123             "STATX_DIOALIGN"
4124             | "CAN_RAW_XL_FRAMES"
4125             | "CANXL_HDR_SIZE"
4126             | "CANXL_MAX_DLC"
4127             | "CANXL_MAX_DLC_MASK"
4128             | "CANXL_MAX_DLEN"
4129             | "CANXL_MAX_MTU"
4130             | "CANXL_MIN_DLC"
4131             | "CANXL_MIN_DLEN"
4132             | "CANXL_MIN_MTU"
4133             | "CANXL_MTU"
4134             | "CANXL_PRIO_BITS"
4135             | "CANXL_PRIO_MASK"
4136             | "CANXL_SEC"
4137             | "CANXL_XLF"
4138              => true,
4139 
4140             // FIXME: Parts of netfilter/nfnetlink*.h require more recent kernel headers:
4141             | "RTNLGRP_MCTP_IFADDR" // linux v5.17+
4142             | "RTNLGRP_TUNNEL" // linux v5.18+
4143             | "RTNLGRP_STATS" // linux v5.18+
4144                 => true,
4145 
4146             // FIXME: The below is no longer const in glibc 2.34:
4147             // https://github.com/bminor/glibc/commit/5d98a7dae955bafa6740c26eaba9c86060ae0344
4148             | "PTHREAD_STACK_MIN"
4149             | "SIGSTKSZ"
4150             | "MINSIGSTKSZ"
4151                 if gnu => true,
4152 
4153             // FIXME: Linux >= 5.16:
4154             // https://github.com/torvalds/linux/commit/42df6e1d221dddc0f2acf2be37e68d553ad65f96
4155             "NF_NETDEV_EGRESS" if sparc64 => true,
4156             // value changed
4157             "NF_NETDEV_NUMHOOKS" if sparc64 => true,
4158 
4159             // FIXME: requires Linux >= v5.8
4160             "IF_LINK_MODE_TESTING" if sparc64 => true,
4161 
4162             // DIFF(main): fixed in 1.0 with e9abac9ac2
4163             "CLONE_CLEAR_SIGHAND" | "CLONE_INTO_CGROUP" => true,
4164 
4165             // kernel 6.1 minimum
4166             "MADV_COLLAPSE" => true,
4167 
4168             // kernel 6.2 minimum
4169             "TUN_F_USO4" | "TUN_F_USO6" | "IFF_NO_CARRIER" => true,
4170 
4171             // FIXME: Requires more recent kernel headers
4172             | "IFLA_PARENT_DEV_NAME"     // linux v5.13+
4173             | "IFLA_PARENT_DEV_BUS_NAME" // linux v5.13+
4174             | "IFLA_GRO_MAX_SIZE"        // linux v5.16+
4175             | "IFLA_TSO_MAX_SIZE"        // linux v5.18+
4176             | "IFLA_TSO_MAX_SEGS"        // linux v5.18+
4177             | "IFLA_ALLMULTI"            // linux v6.0+
4178             | "MADV_DONTNEED_LOCKED"     // linux v5.18+
4179                 => true,
4180             "SCTP_FUTURE_ASSOC" | "SCTP_CURRENT_ASSOC" | "SCTP_ALL_ASSOC" | "SCTP_PEER_ADDR_THLDS_V2" => true, // linux 5.5+
4181 
4182             // kernel 6.5 minimum
4183             "MOVE_MOUNT_BENEATH" => true,
4184             // FIXME: Requires linux 6.1
4185             "ALG_SET_KEY_BY_KEY_SERIAL" | "ALG_SET_DRBG_ENTROPY" => true,
4186 
4187             // FIXME: Requires more recent kernel headers
4188             | "FAN_FS_ERROR"                      // linux v5.16+
4189             | "FAN_RENAME"                        // linux v5.17+
4190             | "FAN_REPORT_TARGET_FID"             // linux v5.17+
4191             | "FAN_REPORT_DFID_NAME_TARGET"       // linux v5.17+
4192             | "FAN_MARK_EVICTABLE"                // linux v5.19+
4193             | "FAN_MARK_IGNORE"                   // linux v6.0+
4194             | "FAN_MARK_IGNORE_SURV"              // linux v6.0+
4195             | "FAN_EVENT_INFO_TYPE_ERROR"         // linux v5.16+
4196             | "FAN_EVENT_INFO_TYPE_OLD_DFID_NAME" // linux v5.17+
4197             | "FAN_EVENT_INFO_TYPE_NEW_DFID_NAME" // linux v5.17+
4198             | "FAN_RESPONSE_INFO_NONE"            // linux v5.16+
4199             | "FAN_RESPONSE_INFO_AUDIT_RULE"      // linux v5.16+
4200             | "FAN_INFO"                          // linux v5.16+
4201                 => true,
4202 
4203             // musl doesn't use <linux/fanotify.h> in <sys/fanotify.h>
4204             "FAN_REPORT_PIDFD"
4205             | "FAN_REPORT_DIR_FID"
4206             | "FAN_REPORT_NAME"
4207             | "FAN_REPORT_DFID_NAME"
4208             | "FAN_EVENT_INFO_TYPE_DFID_NAME"
4209             | "FAN_EVENT_INFO_TYPE_DFID"
4210             | "FAN_EVENT_INFO_TYPE_PIDFD"
4211             | "FAN_NOPIDFD"
4212             | "FAN_EPIDFD"
4213             if musl => true,
4214 
4215             // FIXME: Requires linux 6.5
4216             "NFT_MSG_MAX" => true,
4217 
4218             // FIXME: Requires >= 6.6 kernel headers.
4219             "XDP_USE_SG"
4220             | "XDP_PKT_CONTD"
4221                 =>
4222             {
4223                 true
4224             }
4225 
4226             // FIXME: Requires >= 6.8 kernel headers.
4227             "XDP_UMEM_TX_SW_CSUM"
4228             | "XDP_TXMD_FLAGS_TIMESTAMP"
4229             | "XDP_TXMD_FLAGS_CHECKSUM"
4230             | "XDP_TX_METADATA"
4231                 =>
4232             {
4233                 true
4234             }
4235 
4236             // FIXME: Requires >= 6.11 kernel headers.
4237             "XDP_UMEM_TX_METADATA_LEN"
4238                 =>
4239             {
4240                 true
4241             }
4242 
4243             // FIXME: Requires >= 6.6 kernel headers.
4244             "SYS_fchmodat2" => true,
4245 
4246             // FIXME: Requires >= 6.10 kernel headers.
4247             "SYS_mseal" => true,
4248 
4249             // FIXME: seems to not be available all the time (from <include/linux/sched.h>:
4250             "PF_VCPU"
4251             | "PF_IDLE"
4252             | "PF_EXITING"
4253             | "PF_POSTCOREDUMP"
4254             | "PF_IO_WORKER"
4255             | "PF_WQ_WORKER"
4256             | "PF_FORKNOEXEC"
4257             | "PF_MCE_PROCESS"
4258             | "PF_SUPERPRIV"
4259             | "PF_DUMPCORE"
4260             | "PF_SIGNALED"
4261             | "PF_MEMALLOC"
4262             | "PF_NPROC_EXCEEDED"
4263             | "PF_USED_MATH"
4264             | "PF_USER_WORKER"
4265             | "PF_NOFREEZE"
4266             | "PF_KSWAPD"
4267             | "PF_MEMALLOC_NOFS"
4268             | "PF_MEMALLOC_NOIO"
4269             | "PF_LOCAL_THROTTLE"
4270             | "PF_KTHREAD"
4271             | "PF_RANDOMIZE"
4272             | "PF_NO_SETAFFINITY"
4273             | "PF_MCE_EARLY"
4274             | "PF_MEMALLOC_PIN" => true,
4275 
4276             // FIXME: Requires >= 6.9 kernel headers.
4277             "EPIOCSPARAMS"
4278             | "EPIOCGPARAMS" => true,
4279 
4280             _ => false,
4281         }
4282     });
4283 
4284     cfg.skip_fn(move |name| {
4285         // skip those that are manually verified
4286         match name {
4287             // FIXME: https://github.com/rust-lang/libc/issues/1272
4288             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
4289 
4290             // There are two versions of the sterror_r function, see
4291             //
4292             // https://linux.die.net/man/3/strerror_r
4293             //
4294             // An XSI-compliant version provided if:
4295             //
4296             // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
4297             //  && ! _GNU_SOURCE
4298             //
4299             // and a GNU specific version provided if _GNU_SOURCE is defined.
4300             //
4301             // libc provides bindings for the XSI-compliant version, which is
4302             // preferred for portable applications.
4303             //
4304             // We skip the test here since here _GNU_SOURCE is defined, and
4305             // test the XSI version below.
4306             "strerror_r" => true,
4307 
4308             // FIXME: Our API is unsound. The Rust API allows aliasing
4309             // pointers, but the C API requires pointers not to alias.
4310             // We should probably be at least using `&`/`&mut` here, see:
4311             // https://github.com/gnzlbg/ctest/issues/68
4312             "lio_listio" if musl => true,
4313 
4314             // Needs glibc 2.34 or later.
4315             "posix_spawn_file_actions_addclosefrom_np" if gnu && sparc64 => true,
4316             // Needs glibc 2.35 or later.
4317             "posix_spawn_file_actions_addtcsetpgrp_np" if gnu && sparc64 => true,
4318 
4319             // FIXME: Deprecated since glibc 2.30. Remove fn once upstream does.
4320             "sysctl" if gnu => true,
4321 
4322             // FIXME: It now takes c_void instead of timezone since glibc 2.31.
4323             "gettimeofday" if gnu => true,
4324 
4325             // These are all implemented as static inline functions in uclibc, so
4326             // they cannot be linked against.
4327             // If implementations are required, they might need to be implemented
4328             // in this crate.
4329             "posix_spawnattr_init" if uclibc => true,
4330             "posix_spawnattr_destroy" if uclibc => true,
4331             "posix_spawnattr_getsigdefault" if uclibc => true,
4332             "posix_spawnattr_setsigdefault" if uclibc => true,
4333             "posix_spawnattr_getsigmask" if uclibc => true,
4334             "posix_spawnattr_setsigmask" if uclibc => true,
4335             "posix_spawnattr_getflags" if uclibc => true,
4336             "posix_spawnattr_setflags" if uclibc => true,
4337             "posix_spawnattr_getpgroup" if uclibc => true,
4338             "posix_spawnattr_setpgroup" if uclibc => true,
4339             "posix_spawnattr_getschedpolicy" if uclibc => true,
4340             "posix_spawnattr_setschedpolicy" if uclibc => true,
4341             "posix_spawnattr_getschedparam" if uclibc => true,
4342             "posix_spawnattr_setschedparam" if uclibc => true,
4343             "posix_spawn_file_actions_init" if uclibc => true,
4344             "posix_spawn_file_actions_destroy" if uclibc => true,
4345 
4346             // uclibc defines the flags type as a uint, but dependent crates
4347             // assume it's a int instead.
4348             "getnameinfo" if uclibc => true,
4349 
4350             // FIXME: This needs musl 1.2.2 or later.
4351             "gettid" if musl => true,
4352 
4353             // Needs glibc 2.33 or later.
4354             "mallinfo2" => true,
4355 
4356             "reallocarray" if musl => true,
4357 
4358             // Not defined in uclibc as of 1.0.34
4359             "gettid" if uclibc => true,
4360 
4361             // Needs musl 1.2.3 or later.
4362             "pthread_getname_np" if musl => true,
4363 
4364             // pthread_sigqueue uses sigval, which was initially declared
4365             // as a struct but should be defined as a union. However due
4366             // to the issues described here: https://github.com/rust-lang/libc/issues/2816
4367             // it can't be changed from struct.
4368             "pthread_sigqueue" => true,
4369 
4370             // There are two versions of basename(3) on Linux with glibc, see
4371             //
4372             // https://man7.org/linux/man-pages/man3/basename.3.html
4373             //
4374             // If libgen.h is included, then the POSIX version will be available;
4375             // If _GNU_SOURCE is defined and string.h is included, then the GNU one
4376             // will be used.
4377             //
4378             // libc exposes both of them, providing a prefix to differentiate between
4379             // them.
4380             //
4381             // Because the name with prefix is not a valid symbol in C, we have to
4382             // skip the tests.
4383             "posix_basename" if gnu => true,
4384             "gnu_basename" if gnu => true,
4385 
4386             // FIXME: function pointers changed since Ubuntu 23.10
4387             "strtol" | "strtoll" | "strtoul" | "strtoull" | "fscanf" | "scanf" | "sscanf" => true,
4388 
4389             // Added in musl 1.2.5
4390             "preadv2" | "pwritev2" if musl => true,
4391 
4392             _ => false,
4393         }
4394     });
4395 
4396     cfg.skip_field_type(move |struct_, field| {
4397         // This is a weird union, don't check the type.
4398         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
4399         // sighandler_t type is super weird
4400         (struct_ == "sigaction" && field == "sa_sigaction") ||
4401         // __timeval type is a patch which doesn't exist in glibc
4402         (struct_ == "utmpx" && field == "ut_tv") ||
4403         // sigval is actually a union, but we pretend it's a struct
4404         (struct_ == "sigevent" && field == "sigev_value") ||
4405         // this one is an anonymous union
4406         (struct_ == "ff_effect" && field == "u") ||
4407         // `__exit_status` type is a patch which is absent in musl
4408         (struct_ == "utmpx" && field == "ut_exit" && musl) ||
4409         // `can_addr` is an anonymous union
4410         (struct_ == "sockaddr_can" && field == "can_addr") ||
4411         // `anonymous_1` is an anonymous union
4412         (struct_ == "ptp_perout_request" && field == "anonymous_1") ||
4413         // `anonymous_2` is an anonymous union
4414         (struct_ == "ptp_perout_request" && field == "anonymous_2") ||
4415         // FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers
4416         // FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers
4417         // the rsv field shrunk when those fields got added, so is omitted too
4418         (struct_ == "ptp_clock_caps" && (loongarch64 || sparc64) && (["adjust_phase", "max_phase_adj", "rsv"].contains(&field)))
4419     });
4420 
4421     cfg.volatile_item(|i| {
4422         use ctest::VolatileItemKind::*;
4423         match i {
4424             // aio_buf is a volatile void** but since we cannot express that in
4425             // Rust types, we have to explicitly tell the checker about it here:
4426             StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
4427             _ => false,
4428         }
4429     });
4430 
4431     cfg.skip_field(move |struct_, field| {
4432         // this is actually a union on linux, so we can't represent it well and
4433         // just insert some padding.
4434         (struct_ == "siginfo_t" && field == "_pad") ||
4435         // musl names this __dummy1 but it's still there
4436         (musl && struct_ == "glob_t" && field == "gl_flags") ||
4437         // musl seems to define this as an *anonymous* bitfield
4438         (musl && struct_ == "statvfs" && field == "__f_unused") ||
4439         // sigev_notify_thread_id is actually part of a sigev_un union
4440         (struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
4441         // signalfd had SIGSYS fields added in Linux 4.18, but no libc release
4442         // has them yet.
4443         (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" ||
4444                                            field == "_pad2" ||
4445                                            field == "ssi_syscall" ||
4446                                            field == "ssi_call_addr" ||
4447                                            field == "ssi_arch")) ||
4448         // FIXME: After musl 1.1.24, it have only one field `sched_priority`,
4449         // while other fields become reserved.
4450         (struct_ == "sched_param" && [
4451             "sched_ss_low_priority",
4452             "sched_ss_repl_period",
4453             "sched_ss_init_budget",
4454             "sched_ss_max_repl",
4455         ].contains(&field) && musl) ||
4456         // FIXME: After musl 1.1.24, the type becomes `int` instead of `unsigned short`.
4457         (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) ||
4458         // glibc uses unnamed fields here and Rust doesn't support that yet
4459         (struct_ == "timex" && field.starts_with("__unused")) ||
4460         // FIXME: It now takes mode_t since glibc 2.31 on some targets.
4461         (struct_ == "ipc_perm" && field == "mode"
4462             && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32)
4463         ) ||
4464         // the `u` field is in fact an anonymous union
4465         (gnu && struct_ == "ptrace_syscall_info" && (field == "u" || field == "pad")) ||
4466         // the vregs field is a `__uint128_t` C's type.
4467         (struct_ == "user_fpsimd_struct" && field == "vregs") ||
4468         // Linux >= 5.11 tweaked the `svm_zero` field of the `sockaddr_vm` struct.
4469         // https://github.com/torvalds/linux/commit/dc8eeef73b63ed8988224ba6b5ed19a615163a7f
4470         (struct_ == "sockaddr_vm" && field == "svm_zero") ||
4471         // the `ifr_ifru` field is an anonymous union
4472         (struct_ == "ifreq" && field == "ifr_ifru") ||
4473         // the `ifc_ifcu` field is an anonymous union
4474         (struct_ == "ifconf" && field == "ifc_ifcu") ||
4475         // glibc uses a single array `uregs` instead of individual fields.
4476         (struct_ == "user_regs" && arm) ||
4477         // the `ifr_ifrn` field is an anonymous union
4478         (struct_ == "iwreq" && field == "ifr_ifrn") ||
4479         // the `key` field is a zero-sized array
4480         (struct_ == "iw_encode_ext" && field == "key") ||
4481         // the `tcpi_snd_rcv_wscale` map two bitfield fields stored in a u8
4482         (struct_ == "tcp_info" && field == "tcpi_snd_rcv_wscale") ||
4483         // the `tcpi_delivery_fastopen_bitfields` map two bitfield fields stored in a u8
4484         (musl && struct_ == "tcp_info" && field == "tcpi_delivery_fastopen_bitfields") ||
4485         // either fsid_t or int[2] type
4486         (struct_ == "fanotify_event_info_fid" && field == "fsid") ||
4487         // `handle` is a VLA
4488         (struct_ == "fanotify_event_info_fid" && field == "handle") ||
4489         // `anonymous_1` is an anonymous union
4490         (struct_ == "ptp_perout_request" && field == "anonymous_1") ||
4491         // `anonymous_2` is an anonymous union
4492         (struct_ == "ptp_perout_request" && field == "anonymous_2") ||
4493         // FIXME(linux): `adjust_phase` requires >= 5.7 kernel headers
4494         // FIXME(linux): `max_phase_adj` requires >= 5.19 kernel headers
4495         // the rsv field shrunk when those fields got added, so is omitted too
4496         (struct_ == "ptp_clock_caps" && (loongarch64 || sparc64) && (["adjust_phase", "max_phase_adj", "rsv"].contains(&field))) ||
4497         // invalid application of 'sizeof' to incomplete type 'long unsigned int[]'
4498         (musl && struct_ == "mcontext_t" && field == "__extcontext" && loongarch64) ||
4499         // FIXME(#4121): a new field was added from `f_spare`
4500         (struct_ == "statvfs" && field == "__f_spare") ||
4501         (struct_ == "statvfs64" && field == "__f_spare") ||
4502         // the `xsk_tx_metadata_union` field is an anonymous union
4503         (struct_ == "xsk_tx_metadata" && field == "xsk_tx_metadata_union")
4504     });
4505 
4506     cfg.skip_roundtrip(move |s| match s {
4507         // FIXME:
4508         "mcontext_t" if s390x => true,
4509         // FIXME: This is actually a union.
4510         "fpreg_t" if s390x => true,
4511 
4512         // The test doesn't work on some env:
4513         "ipv6_mreq"
4514         | "ip_mreq_source"
4515         | "sockaddr_in6"
4516         | "sockaddr_ll"
4517         | "in_pktinfo"
4518         | "arpreq"
4519         | "arpreq_old"
4520         | "sockaddr_un"
4521         | "ff_constant_effect"
4522         | "ff_ramp_effect"
4523         | "ff_condition_effect"
4524         | "Elf32_Ehdr"
4525         | "Elf32_Chdr"
4526         | "ucred"
4527         | "in6_pktinfo"
4528         | "sockaddr_nl"
4529         | "termios"
4530         | "nlmsgerr"
4531             if sparc64 && gnu =>
4532         {
4533             true
4534         }
4535 
4536         // The following types contain Flexible Array Member fields which have unspecified calling
4537         // convention. The roundtripping tests deliberately pass the structs by value to check "by
4538         // value" layout consistency, but this would be UB for the these types.
4539         "inotify_event" => true,
4540         "fanotify_event_info_fid" => true,
4541         "cmsghdr" => true,
4542 
4543         // FIXME: the call ABI of max_align_t is incorrect on these platforms:
4544         "max_align_t" if i686 || ppc64 => true,
4545 
4546         _ => false,
4547     });
4548 
4549     cfg.generate("../src/lib.rs", "main.rs");
4550 
4551     test_linux_like_apis(target);
4552 }
4553 
4554 // This function tests APIs that are incompatible to test when other APIs
4555 // are included (e.g. because including both sets of headers clashes)
4556 fn test_linux_like_apis(target: &str) {
4557     let gnu = target.contains("gnu");
4558     let musl = target.contains("musl") || target.contains("ohos");
4559     let linux = target.contains("linux");
4560     let emscripten = target.contains("emscripten");
4561     let android = target.contains("android");
4562     assert!(linux || android || emscripten);
4563 
4564     if linux || android || emscripten {
4565         // test strerror_r from the `string.h` header
4566         let mut cfg = ctest_cfg();
4567         cfg.skip_type(|_| true).skip_static(|_| true);
4568 
4569         headers! { cfg: "string.h" }
4570         cfg.skip_fn(|f| match f {
4571             "strerror_r" => false,
4572             _ => true,
4573         })
4574         .skip_const(|_| true)
4575         .skip_struct(|_| true);
4576         cfg.generate("../src/lib.rs", "linux_strerror_r.rs");
4577     }
4578 
4579     if linux || android || emscripten {
4580         // test fcntl - see:
4581         // http://man7.org/linux/man-pages/man2/fcntl.2.html
4582         let mut cfg = ctest_cfg();
4583 
4584         if musl {
4585             cfg.header("fcntl.h");
4586         } else {
4587             cfg.header("linux/fcntl.h");
4588         }
4589 
4590         cfg.skip_type(|_| true)
4591             .skip_static(|_| true)
4592             .skip_struct(|_| true)
4593             .skip_fn(|_| true)
4594             .skip_const(move |name| match name {
4595                 // test fcntl constants:
4596                 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK"
4597                 | "F_SEAL_GROW" | "F_SEAL_WRITE" => false,
4598                 _ => true,
4599             })
4600             .type_name(move |ty, is_struct, is_union| match ty {
4601                 t if is_struct => format!("struct {}", t),
4602                 t if is_union => format!("union {}", t),
4603                 t => t.to_string(),
4604             });
4605 
4606         cfg.generate("../src/lib.rs", "linux_fcntl.rs");
4607     }
4608 
4609     if linux || android {
4610         // test termios
4611         let mut cfg = ctest_cfg();
4612         cfg.header("asm/termbits.h");
4613         cfg.header("linux/termios.h");
4614         cfg.skip_type(|_| true)
4615             .skip_static(|_| true)
4616             .skip_fn(|_| true)
4617             .skip_const(|c| match c {
4618                 "BOTHER" | "IBSHIFT" => false,
4619                 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => false,
4620                 _ => true,
4621             })
4622             .skip_struct(|s| s != "termios2")
4623             .type_name(move |ty, is_struct, is_union| match ty {
4624                 "Ioctl" if gnu => "unsigned long".to_string(),
4625                 "Ioctl" => "int".to_string(),
4626                 t if is_struct => format!("struct {}", t),
4627                 t if is_union => format!("union {}", t),
4628                 t => t.to_string(),
4629             });
4630         cfg.generate("../src/lib.rs", "linux_termios.rs");
4631     }
4632 
4633     if linux || android {
4634         // test IPV6_ constants:
4635         let mut cfg = ctest_cfg();
4636         headers! {
4637             cfg:
4638             "linux/in6.h"
4639         }
4640         cfg.skip_type(|_| true)
4641             .skip_static(|_| true)
4642             .skip_fn(|_| true)
4643             .skip_const(|_| true)
4644             .skip_struct(|_| true)
4645             .skip_const(move |name| match name {
4646                 "IPV6_FLOWINFO"
4647                 | "IPV6_FLOWLABEL_MGR"
4648                 | "IPV6_FLOWINFO_SEND"
4649                 | "IPV6_FLOWINFO_FLOWLABEL"
4650                 | "IPV6_FLOWINFO_PRIORITY" => false,
4651                 _ => true,
4652             })
4653             .type_name(move |ty, is_struct, is_union| match ty {
4654                 t if is_struct => format!("struct {}", t),
4655                 t if is_union => format!("union {}", t),
4656                 t => t.to_string(),
4657             });
4658         cfg.generate("../src/lib.rs", "linux_ipv6.rs");
4659     }
4660 
4661     if linux || android {
4662         // Test Elf64_Phdr and Elf32_Phdr
4663         // These types have a field called `p_type`, but including
4664         // "resolve.h" defines a `p_type` macro that expands to `__p_type`
4665         // making the tests for these fails when both are included.
4666         let mut cfg = ctest_cfg();
4667         cfg.header("elf.h");
4668         cfg.skip_fn(|_| true)
4669             .skip_static(|_| true)
4670             .skip_const(|_| true)
4671             .type_name(move |ty, _is_struct, _is_union| ty.to_string())
4672             .skip_struct(move |ty| match ty {
4673                 "Elf64_Phdr" | "Elf32_Phdr" => false,
4674                 _ => true,
4675             })
4676             .skip_type(move |ty| match ty {
4677                 "Elf64_Phdr" | "Elf32_Phdr" => false,
4678                 _ => true,
4679             });
4680         cfg.generate("../src/lib.rs", "linux_elf.rs");
4681     }
4682 
4683     if linux || android {
4684         // Test `ARPHRD_CAN`.
4685         let mut cfg = ctest_cfg();
4686         cfg.header("linux/if_arp.h");
4687         cfg.skip_fn(|_| true)
4688             .skip_static(|_| true)
4689             .skip_const(move |name| match name {
4690                 "ARPHRD_CAN" => false,
4691                 _ => true,
4692             })
4693             .skip_struct(|_| true)
4694             .skip_type(|_| true);
4695         cfg.generate("../src/lib.rs", "linux_if_arp.rs");
4696     }
4697 }
4698 
4699 fn which_freebsd() -> Option<i32> {
4700     let output = std::process::Command::new("freebsd-version")
4701         .output()
4702         .ok()?;
4703     if !output.status.success() {
4704         return None;
4705     }
4706 
4707     let stdout = String::from_utf8(output.stdout).ok()?;
4708 
4709     match &stdout {
4710         s if s.starts_with("10") => Some(10),
4711         s if s.starts_with("11") => Some(11),
4712         s if s.starts_with("12") => Some(12),
4713         s if s.starts_with("13") => Some(13),
4714         s if s.starts_with("14") => Some(14),
4715         s if s.starts_with("15") => Some(15),
4716         _ => None,
4717     }
4718 }
4719 
4720 fn test_haiku(target: &str) {
4721     assert!(target.contains("haiku"));
4722 
4723     let mut cfg = ctest_cfg();
4724     cfg.flag("-Wno-deprecated-declarations");
4725     cfg.define("__USE_GNU", Some("1"));
4726     cfg.define("_GNU_SOURCE", None);
4727     cfg.language(ctest::Lang::CXX);
4728 
4729     // POSIX API
4730     headers! { cfg:
4731                "alloca.h",
4732                "arpa/inet.h",
4733                "arpa/nameser.h",
4734                "arpa/nameser_compat.h",
4735                "assert.h",
4736                "complex.h",
4737                "ctype.h",
4738                "dirent.h",
4739                "div_t.h",
4740                "dlfcn.h",
4741                "endian.h",
4742                "errno.h",
4743                "fcntl.h",
4744                "fenv.h",
4745                "fnmatch.h",
4746                "fts.h",
4747                "ftw.h",
4748                "getopt.h",
4749                "glob.h",
4750                "grp.h",
4751                "inttypes.h",
4752                "iovec.h",
4753                "langinfo.h",
4754                "libgen.h",
4755                "libio.h",
4756                "limits.h",
4757                "locale.h",
4758                "malloc.h",
4759                "malloc_debug.h",
4760                "math.h",
4761                "memory.h",
4762                "monetary.h",
4763                "net/if.h",
4764                "net/if_dl.h",
4765                "net/if_media.h",
4766                "net/if_tun.h",
4767                "net/if_types.h",
4768                "net/route.h",
4769                "netdb.h",
4770                "netinet/in.h",
4771                "netinet/ip.h",
4772                "netinet/ip6.h",
4773                "netinet/ip_icmp.h",
4774                "netinet/ip_var.h",
4775                "netinet/tcp.h",
4776                "netinet/udp.h",
4777                "netinet6/in6.h",
4778                "nl_types.h",
4779                "null.h",
4780                "poll.h",
4781                "pthread.h",
4782                "pwd.h",
4783                "regex.h",
4784                "resolv.h",
4785                "sched.h",
4786                "search.h",
4787                "semaphore.h",
4788                "setjmp.h",
4789                "shadow.h",
4790                "signal.h",
4791                "size_t.h",
4792                "spawn.h",
4793                "stdint.h",
4794                "stdio.h",
4795                "stdlib.h",
4796                "string.h",
4797                "strings.h",
4798                "sys/cdefs.h",
4799                "sys/file.h",
4800                "sys/ioctl.h",
4801                "sys/ipc.h",
4802                "sys/mman.h",
4803                "sys/msg.h",
4804                "sys/param.h",
4805                "sys/poll.h",
4806                "sys/resource.h",
4807                "sys/select.h",
4808                "sys/sem.h",
4809                "sys/socket.h",
4810                "sys/sockio.h",
4811                "sys/stat.h",
4812                "sys/statvfs.h",
4813                "sys/time.h",
4814                "sys/timeb.h",
4815                "sys/times.h",
4816                "sys/types.h",
4817                "sys/uio.h",
4818                "sys/un.h",
4819                "sys/utsname.h",
4820                "sys/wait.h",
4821                "syslog.h",
4822                "tar.h",
4823                "termios.h",
4824                "time.h",
4825                "uchar.h",
4826                "unistd.h",
4827                "utime.h",
4828                "utmpx.h",
4829                "wchar.h",
4830                "wchar_t.h",
4831                "wctype.h"
4832     }
4833 
4834     // BSD Extensions
4835     headers! { cfg:
4836                "ifaddrs.h",
4837                "libutil.h",
4838                "link.h",
4839                "pty.h",
4840                "stdlib.h",
4841                "stringlist.h",
4842                "sys/link_elf.h",
4843     }
4844 
4845     // Native API
4846     headers! { cfg:
4847                "kernel/OS.h",
4848                "kernel/fs_attr.h",
4849                "kernel/fs_index.h",
4850                "kernel/fs_info.h",
4851                "kernel/fs_query.h",
4852                "kernel/fs_volume.h",
4853                "kernel/image.h",
4854                "kernel/scheduler.h",
4855                "storage/FindDirectory.h",
4856                "storage/StorageDefs.h",
4857                "support/Errors.h",
4858                "support/SupportDefs.h",
4859                "support/TypeConstants.h"
4860     }
4861 
4862     cfg.skip_struct(move |ty| {
4863         if ty.starts_with("__c_anonymous_") {
4864             return true;
4865         }
4866         match ty {
4867             // FIXME: actually a union
4868             "sigval" => true,
4869             // FIXME: locale_t does not exist on Haiku
4870             "locale_t" => true,
4871             // FIXME: rusage has a different layout on Haiku
4872             "rusage" => true,
4873             // FIXME?: complains that rust aligns on 4 byte boundary, but
4874             //         Haiku does not align it at all.
4875             "in6_addr" => true,
4876             // The d_name attribute is an array of 1 on Haiku, with the
4877             // intention that the developer allocates a larger or smaller
4878             // piece of memory depending on the expected/actual size of the name.
4879             // Other platforms have sensible defaults. In Rust, the d_name field
4880             // is sized as the _POSIX_MAX_PATH, so that path names will fit in
4881             // newly allocated dirent objects. This breaks the automated tests.
4882             "dirent" => true,
4883             // The following structs contain function pointers, which cannot be initialized
4884             // with mem::zeroed(), so skip the automated test
4885             "image_info" | "thread_info" => true,
4886 
4887             "Elf64_Phdr" => true,
4888 
4889             // is an union
4890             "cpuid_info" => true,
4891 
4892             _ => false,
4893         }
4894     });
4895 
4896     cfg.skip_type(move |ty| {
4897         match ty {
4898             // FIXME: locale_t does not exist on Haiku
4899             "locale_t" => true,
4900             // These cause errors, to be reviewed in the future
4901             "sighandler_t" => true,
4902             "pthread_t" => true,
4903             "pthread_condattr_t" => true,
4904             "pthread_mutexattr_t" => true,
4905             "pthread_rwlockattr_t" => true,
4906             _ => false,
4907         }
4908     });
4909 
4910     cfg.skip_fn(move |name| {
4911         // skip those that are manually verified
4912         match name {
4913             // FIXME: https://github.com/rust-lang/libc/issues/1272
4914             "execv" | "execve" | "execvp" | "execvpe" => true,
4915             // FIXME: does not exist on haiku
4916             "open_wmemstream" => true,
4917             "mlockall" | "munlockall" => true,
4918             "tcgetsid" => true,
4919             "cfsetspeed" => true,
4920             // ignore for now, will be part of Haiku R1 beta 3
4921             "mlock" | "munlock" => true,
4922             // returns const char * on Haiku
4923             "strsignal" => true,
4924             // uses an enum as a parameter argument, which is incorrectly
4925             // translated into a struct argument
4926             "find_path" => true,
4927 
4928             "get_cpuid" => true,
4929 
4930             // uses varargs parameter
4931             "ioctl" => true,
4932 
4933             _ => false,
4934         }
4935     });
4936 
4937     cfg.skip_const(move |name| {
4938         match name {
4939             // FIXME: these constants do not exist on Haiku
4940             "DT_UNKNOWN" | "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK"
4941             | "DT_SOCK" => true,
4942             "USRQUOTA" | "GRPQUOTA" => true,
4943             "SIGIOT" => true,
4944             "ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM" | "ATF_PUBL"
4945             | "ATF_USETRAILERS" => true,
4946             // Haiku does not have MAP_FILE, but rustc requires it
4947             "MAP_FILE" => true,
4948             // The following does not exist on Haiku but is required by
4949             // several crates
4950             "FIOCLEX" => true,
4951             // just skip this one, it is not defined on Haiku beta 2 but
4952             // since it is meant as a mask and not a parameter it can exist
4953             // here
4954             "LOG_PRIMASK" => true,
4955             // not defined on Haiku, but [get|set]priority is, so they are
4956             // useful
4957             "PRIO_MIN" | "PRIO_MAX" => true,
4958             //
4959             _ => false,
4960         }
4961     });
4962 
4963     cfg.skip_field(move |struct_, field| {
4964         match (struct_, field) {
4965             // FIXME: the stat struct actually has timespec members, whereas
4966             //        the current representation has these unpacked.
4967             ("stat", "st_atime") => true,
4968             ("stat", "st_atime_nsec") => true,
4969             ("stat", "st_mtime") => true,
4970             ("stat", "st_mtime_nsec") => true,
4971             ("stat", "st_ctime") => true,
4972             ("stat", "st_ctime_nsec") => true,
4973             ("stat", "st_crtime") => true,
4974             ("stat", "st_crtime_nsec") => true,
4975 
4976             // these are actually unions, but we cannot represent it well
4977             ("siginfo_t", "sigval") => true,
4978             ("sem_t", "named_sem_id") => true,
4979             ("sigaction", "sa_sigaction") => true,
4980             ("sigevent", "sigev_value") => true,
4981             ("fpu_state", "_fpreg") => true,
4982             ("cpu_topology_node_info", "data") => true,
4983             // these fields have a simplified data definition in libc
4984             ("fpu_state", "_xmm") => true,
4985             ("savefpu", "_fp_ymm") => true,
4986 
4987             // skip these enum-type fields
4988             ("thread_info", "state") => true,
4989             ("image_info", "image_type") => true,
4990             _ => false,
4991         }
4992     });
4993 
4994     cfg.skip_roundtrip(move |s| match s {
4995         // FIXME: for some reason the roundtrip check fails for cpu_info
4996         "cpu_info" => true,
4997         _ => false,
4998     });
4999 
5000     cfg.type_name(move |ty, is_struct, is_union| {
5001         match ty {
5002             // Just pass all these through, no need for a "struct" prefix
5003             "area_info"
5004             | "port_info"
5005             | "port_message_info"
5006             | "team_info"
5007             | "sem_info"
5008             | "team_usage_info"
5009             | "thread_info"
5010             | "cpu_info"
5011             | "system_info"
5012             | "object_wait_info"
5013             | "image_info"
5014             | "attr_info"
5015             | "index_info"
5016             | "fs_info"
5017             | "FILE"
5018             | "DIR"
5019             | "Dl_info"
5020             | "topology_level_type"
5021             | "cpu_topology_node_info"
5022             | "cpu_topology_root_info"
5023             | "cpu_topology_package_info"
5024             | "cpu_topology_core_info" => ty.to_string(),
5025 
5026             // enums don't need a prefix
5027             "directory_which" | "path_base_directory" | "cpu_platform" | "cpu_vendor" => {
5028                 ty.to_string()
5029             }
5030 
5031             // is actually a union
5032             "sigval" => format!("union sigval"),
5033             t if is_union => format!("union {}", t),
5034             t if t.ends_with("_t") => t.to_string(),
5035             t if is_struct => format!("struct {}", t),
5036             t => t.to_string(),
5037         }
5038     });
5039 
5040     cfg.field_name(move |struct_, field| {
5041         match field {
5042             // Field is named `type` in C but that is a Rust keyword,
5043             // so these fields are translated to `type_` in the bindings.
5044             "type_" if struct_ == "object_wait_info" => "type".to_string(),
5045             "type_" if struct_ == "sem_t" => "type".to_string(),
5046             "type_" if struct_ == "attr_info" => "type".to_string(),
5047             "type_" if struct_ == "index_info" => "type".to_string(),
5048             "type_" if struct_ == "cpu_topology_node_info" => "type".to_string(),
5049             "image_type" if struct_ == "image_info" => "type".to_string(),
5050             s => s.to_string(),
5051         }
5052     });
5053     cfg.generate("../src/lib.rs", "main.rs");
5054 }
5055