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