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