xref: /rust-libc-0.2.174/libc-test/build.rs (revision 72c8a305)
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("android") || target.contains("linux") {
27         cc::Build::new().file("src/errqueue.c").compile("errqueue");
28     }
29     if target.contains("linux")
30         || target.contains("l4re")
31         || target.contains("android")
32         || target.contains("emscripten")
33     {
34         cc::Build::new().file("src/sigrt.c").compile("sigrt");
35     }
36 }
37 
38 fn do_ctest() {
39     match &env::var("TARGET").unwrap() {
40         t if t.contains("android") => return test_android(t),
41         t if t.contains("apple") => return test_apple(t),
42         t if t.contains("dragonfly") => return test_dragonflybsd(t),
43         t if t.contains("emscripten") => return test_emscripten(t),
44         t if t.contains("freebsd") => return test_freebsd(t),
45         t if t.contains("haiku") => return test_haiku(t),
46         t if t.contains("linux") => return test_linux(t),
47         t if t.contains("netbsd") => return test_netbsd(t),
48         t if t.contains("openbsd") => return test_openbsd(t),
49         t if t.contains("redox") => return test_redox(t),
50         t if t.contains("solaris") => return test_solarish(t),
51         t if t.contains("illumos") => return test_solarish(t),
52         t if t.contains("wasi") => return test_wasi(t),
53         t if t.contains("windows") => return test_windows(t),
54         t if t.contains("vxworks") => return test_vxworks(t),
55         t => panic!("unknown target {}", t),
56     }
57 }
58 
59 fn ctest_cfg() -> ctest::TestGenerator {
60     let mut cfg = ctest::TestGenerator::new();
61     let libc_cfgs = [
62         "libc_priv_mod_use",
63         "libc_union",
64         "libc_const_size_of",
65         "libc_align",
66         "libc_core_cvoid",
67         "libc_packedN",
68         "libc_thread_local",
69     ];
70     for f in &libc_cfgs {
71         cfg.cfg(f, None);
72     }
73     cfg
74 }
75 
76 fn do_semver() {
77     let mut out = PathBuf::from(env::var("OUT_DIR").unwrap());
78     out.push("semver.rs");
79     let mut output = BufWriter::new(File::create(&out).unwrap());
80 
81     let family = env::var("CARGO_CFG_TARGET_FAMILY").unwrap();
82     let vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
83     let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
84     let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
85     let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
86 
87     // `libc-test/semver` dir.
88     let mut semver_root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
89     semver_root.push("semver");
90 
91     // NOTE: Windows has the same `family` as `os`, no point in including it
92     // twice.
93     // NOTE: Android doesn't include the unix file (or the Linux file) because
94     // there are some many definitions missing it's actually easier just to
95     // maintain a file for Android.
96     if family != os && os != "android" {
97         process_semver_file(&mut output, &mut semver_root, &family);
98     }
99     process_semver_file(&mut output, &mut semver_root, &vendor);
100     process_semver_file(&mut output, &mut semver_root, &os);
101     let os_arch = format!("{}-{}", os, arch);
102     process_semver_file(&mut output, &mut semver_root, &os_arch);
103     if target_env != "" {
104         let os_env = format!("{}-{}", os, target_env);
105         process_semver_file(&mut output, &mut semver_root, &os_env);
106 
107         let os_env_arch = format!("{}-{}-{}", os, target_env, arch);
108         process_semver_file(&mut output, &mut semver_root, &os_env_arch);
109     }
110 }
111 
112 fn process_semver_file<W: Write, P: AsRef<Path>>(output: &mut W, path: &mut PathBuf, file: P) {
113     // NOTE: `path` is reused between calls, so always remove the file again.
114     path.push(file);
115     path.set_extension("txt");
116 
117     println!("cargo:rerun-if-changed={}", path.display());
118     let input_file = match File::open(&*path) {
119         Ok(file) => file,
120         Err(ref err) if err.kind() == io::ErrorKind::NotFound => {
121             path.pop();
122             return;
123         }
124         Err(err) => panic!("unexpected error opening file: {}", err),
125     };
126     let input = BufReader::new(input_file);
127 
128     write!(output, "// Source: {}.\n", path.display()).unwrap();
129     output.write(b"use libc::{\n").unwrap();
130     for line in input.lines() {
131         let line = line.unwrap().into_bytes();
132         match line.first() {
133             // Ignore comments and empty lines.
134             Some(b'#') | None => continue,
135             _ => {
136                 output.write(b"    ").unwrap();
137                 output.write(&line).unwrap();
138                 output.write(b",\n").unwrap();
139             }
140         }
141     }
142     output.write(b"};\n\n").unwrap();
143     path.pop();
144 }
145 
146 fn main() {
147     do_cc();
148     do_ctest();
149     do_semver();
150 }
151 
152 macro_rules! headers {
153     ($cfg:ident: [$m:expr]: $header:literal) => {
154         if $m {
155             $cfg.header($header);
156         }
157     };
158     ($cfg:ident: $header:literal) => {
159         $cfg.header($header);
160     };
161     ($($cfg:ident: $([$c:expr]:)* $header:literal,)*) => {
162         $(headers!($cfg: $([$c]:)* $header);)*
163     };
164     ($cfg:ident: $( $([$c:expr]:)* $header:literal,)*) => {
165         headers!($($cfg: $([$c]:)* $header,)*);
166     };
167     ($cfg:ident: $( $([$c:expr]:)* $header:literal),*) => {
168         headers!($($cfg: $([$c]:)* $header,)*);
169     };
170 }
171 
172 fn test_apple(target: &str) {
173     assert!(target.contains("apple"));
174     let x86_64 = target.contains("x86_64");
175     let i686 = target.contains("i686");
176 
177     let mut cfg = ctest_cfg();
178     cfg.flag("-Wno-deprecated-declarations");
179     cfg.define("__APPLE_USE_RFC_3542", None);
180 
181     headers! { cfg:
182         "aio.h",
183         "CommonCrypto/CommonCrypto.h",
184         "CommonCrypto/CommonRandom.h",
185         "crt_externs.h",
186         "ctype.h",
187         "dirent.h",
188         "dlfcn.h",
189         "errno.h",
190         "execinfo.h",
191         "fcntl.h",
192         "glob.h",
193         "grp.h",
194         "iconv.h",
195         "ifaddrs.h",
196         "langinfo.h",
197         "libproc.h",
198         "limits.h",
199         "locale.h",
200         "mach-o/dyld.h",
201         "mach/mach_init.h",
202         "mach/mach.h",
203         "mach/mach_time.h",
204         "mach/mach_types.h",
205         "mach/mach_vm.h",
206         "mach/thread_act.h",
207         "mach/thread_policy.h",
208         "malloc/malloc.h",
209         "net/bpf.h",
210         "net/if.h",
211         "net/if_arp.h",
212         "net/if_dl.h",
213         "net/if_utun.h",
214         "net/route.h",
215         "netdb.h",
216         "netinet/if_ether.h",
217         "netinet/in.h",
218         "netinet/ip.h",
219         "netinet/tcp.h",
220         "netinet/udp.h",
221         "poll.h",
222         "pthread.h",
223         "pthread_spis.h",
224         "pthread/introspection.h",
225         "pwd.h",
226         "regex.h",
227         "resolv.h",
228         "sched.h",
229         "semaphore.h",
230         "signal.h",
231         "spawn.h",
232         "stddef.h",
233         "stdint.h",
234         "stdio.h",
235         "stdlib.h",
236         "string.h",
237         "sysdir.h",
238         "sys/attr.h",
239         "sys/clonefile.h",
240         "sys/event.h",
241         "sys/file.h",
242         "sys/ioctl.h",
243         "sys/ipc.h",
244         "sys/kern_control.h",
245         "sys/mman.h",
246         "sys/mount.h",
247         "sys/proc_info.h",
248         "sys/ptrace.h",
249         "sys/quota.h",
250         "sys/resource.h",
251         "sys/sem.h",
252         "sys/shm.h",
253         "sys/socket.h",
254         "sys/stat.h",
255         "sys/statvfs.h",
256         "sys/sys_domain.h",
257         "sys/sysctl.h",
258         "sys/time.h",
259         "sys/times.h",
260         "sys/timex.h",
261         "sys/types.h",
262         "sys/uio.h",
263         "sys/un.h",
264         "sys/utsname.h",
265         "sys/wait.h",
266         "sys/xattr.h",
267         "syslog.h",
268         "termios.h",
269         "time.h",
270         "unistd.h",
271         "util.h",
272         "utime.h",
273         "utmpx.h",
274         "wchar.h",
275         "xlocale.h",
276         [x86_64]: "crt_externs.h",
277     }
278 
279     cfg.skip_struct(move |ty| {
280         match ty {
281             // FIXME: actually a union
282             "sigval" => true,
283 
284             _ => false,
285         }
286     });
287 
288     cfg.skip_type(move |ty| match ty {
289         _ => false,
290     });
291 
292     cfg.skip_const(move |name| {
293         // They're declared via `deprecated_mach` and we don't support it anymore.
294         if name.starts_with("VM_FLAGS_") {
295             return true;
296         }
297         match name {
298             // These OSX constants are removed in Sierra.
299             // https://developer.apple.com/library/content/releasenotes/General/APIDiffsMacOS10_12/Swift/Darwin.html
300             "KERN_KDENABLE_BG_TRACE" | "KERN_KDDISABLE_BG_TRACE" => true,
301             // FIXME: the value has been changed since Catalina (0xffff0000 -> 0x3fff0000).
302             "SF_SETTABLE" => true,
303             _ => false,
304         }
305     });
306 
307     cfg.skip_fn(move |name| {
308         // skip those that are manually verified
309         match name {
310             // FIXME: https://github.com/rust-lang/libc/issues/1272
311             "execv" | "execve" | "execvp" => true,
312 
313             // close calls the close_nocancel system call
314             "close" => true,
315 
316             _ => false,
317         }
318     });
319 
320     cfg.skip_field(move |struct_, field| {
321         match (struct_, field) {
322             // FIXME: the array size has been changed since macOS 10.15 ([8] -> [7]).
323             ("statfs", "f_reserved") => true,
324             ("__darwin_arm_neon_state64", "__v") => true,
325             // MAXPATHLEN is too big for auto-derive traits on arrays.
326             ("vnode_info_path", "vip_path") => true,
327             _ => false,
328         }
329     });
330 
331     cfg.skip_field_type(move |struct_, field| {
332         match (struct_, field) {
333             // FIXME: actually a union
334             ("sigevent", "sigev_value") => true,
335             _ => false,
336         }
337     });
338 
339     cfg.volatile_item(|i| {
340         use ctest::VolatileItemKind::*;
341         match i {
342             StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
343             _ => false,
344         }
345     });
346 
347     cfg.type_name(move |ty, is_struct, is_union| {
348         match ty {
349             // Just pass all these through, no need for a "struct" prefix
350             "FILE" | "DIR" | "Dl_info" => ty.to_string(),
351 
352             // OSX calls this something else
353             "sighandler_t" => "sig_t".to_string(),
354 
355             t if is_union => format!("union {}", t),
356             t if t.ends_with("_t") => t.to_string(),
357             t if is_struct => format!("struct {}", t),
358             t => t.to_string(),
359         }
360     });
361 
362     cfg.field_name(move |struct_, field| {
363         match field {
364             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
365                 s.replace("e_nsec", "espec.tv_nsec")
366             }
367             // FIXME: sigaction actually contains a union with two variants:
368             // a sa_sigaction with type: (*)(int, struct __siginfo *, void *)
369             // a sa_handler with type sig_t
370             "sa_sigaction" if struct_ == "sigaction" => "sa_handler".to_string(),
371             s => s.to_string(),
372         }
373     });
374 
375     cfg.skip_roundtrip(move |s| match s {
376         // FIXME: this type has the wrong ABI
377         "max_align_t" if i686 => true,
378         // Can't return an array from a C function.
379         "uuid_t" => true,
380         _ => false,
381     });
382     cfg.generate("../src/lib.rs", "main.rs");
383 }
384 
385 fn test_openbsd(target: &str) {
386     assert!(target.contains("openbsd"));
387 
388     let mut cfg = ctest_cfg();
389     cfg.flag("-Wno-deprecated-declarations");
390 
391     let x86_64 = target.contains("x86_64");
392 
393     headers! { cfg:
394         "elf.h",
395         "errno.h",
396         "fcntl.h",
397         "limits.h",
398         "link.h",
399         "locale.h",
400         "stddef.h",
401         "stdint.h",
402         "stdio.h",
403         "stdlib.h",
404         "sys/stat.h",
405         "sys/types.h",
406         "time.h",
407         "wchar.h",
408         "ctype.h",
409         "dirent.h",
410         "sys/socket.h",
411         [x86_64]:"machine/fpu.h",
412         "net/if.h",
413         "net/route.h",
414         "net/if_arp.h",
415         "netdb.h",
416         "netinet/in.h",
417         "netinet/ip.h",
418         "netinet/tcp.h",
419         "netinet/udp.h",
420         "net/bpf.h",
421         "regex.h",
422         "resolv.h",
423         "pthread.h",
424         "dlfcn.h",
425         "signal.h",
426         "string.h",
427         "sys/file.h",
428         "sys/ioctl.h",
429         "sys/mman.h",
430         "sys/param.h",
431         "sys/resource.h",
432         "sys/shm.h",
433         "sys/socket.h",
434         "sys/time.h",
435         "sys/uio.h",
436         "sys/ktrace.h",
437         "sys/un.h",
438         "sys/wait.h",
439         "unistd.h",
440         "utime.h",
441         "pwd.h",
442         "grp.h",
443         "sys/utsname.h",
444         "sys/ptrace.h",
445         "sys/mount.h",
446         "sys/uio.h",
447         "sched.h",
448         "termios.h",
449         "poll.h",
450         "syslog.h",
451         "semaphore.h",
452         "sys/statvfs.h",
453         "sys/times.h",
454         "glob.h",
455         "ifaddrs.h",
456         "langinfo.h",
457         "sys/sysctl.h",
458         "utmp.h",
459         "sys/event.h",
460         "net/if_dl.h",
461         "util.h",
462         "ufs/ufs/quota.h",
463         "pthread_np.h",
464         "sys/syscall.h",
465         "sys/shm.h",
466         "sys/param.h",
467     }
468 
469     cfg.skip_struct(move |ty| {
470         match ty {
471             // FIXME: actually a union
472             "sigval" => true,
473 
474             _ => false,
475         }
476     });
477 
478     cfg.skip_const(move |name| {
479         match name {
480             // Removed in OpenBSD 6.0
481             "KERN_USERMOUNT" | "KERN_ARND" => true,
482             // Good chance it's going to be wrong depending on the host release
483             "KERN_MAXID" | "NET_RT_MAXID" => true,
484             _ => false,
485         }
486     });
487 
488     cfg.skip_fn(move |name| {
489         match name {
490             // FIXME: https://github.com/rust-lang/libc/issues/1272
491             "execv" | "execve" | "execvp" | "execvpe" => true,
492 
493             // Removed in OpenBSD 6.5
494             // https://marc.info/?l=openbsd-cvs&m=154723400730318
495             "mincore" => true,
496 
497             _ => false,
498         }
499     });
500 
501     cfg.type_name(move |ty, is_struct, is_union| {
502         match ty {
503             // Just pass all these through, no need for a "struct" prefix
504             "FILE" | "DIR" | "Dl_info" | "Elf32_Phdr" | "Elf64_Phdr" => ty.to_string(),
505 
506             // OSX calls this something else
507             "sighandler_t" => "sig_t".to_string(),
508 
509             t if is_union => format!("union {}", t),
510             t if t.ends_with("_t") => t.to_string(),
511             t if is_struct => format!("struct {}", t),
512             t => t.to_string(),
513         }
514     });
515 
516     cfg.field_name(move |struct_, field| match field {
517         "st_birthtime" if struct_.starts_with("stat") => "__st_birthtime".to_string(),
518         "st_birthtime_nsec" if struct_.starts_with("stat") => "__st_birthtimensec".to_string(),
519         s if s.ends_with("_nsec") && struct_.starts_with("stat") => s.replace("e_nsec", ".tv_nsec"),
520         "sa_sigaction" if struct_ == "sigaction" => "sa_handler".to_string(),
521         s => s.to_string(),
522     });
523 
524     cfg.skip_field_type(move |struct_, field| {
525         // type siginfo_t.si_addr changed from OpenBSD 6.0 to 6.1
526         struct_ == "siginfo_t" && field == "si_addr"
527     });
528 
529     cfg.skip_field(|struct_, field| {
530         match (struct_, field) {
531             // conflicting with `p_type` macro from <resolve.h>.
532             ("Elf32_Phdr", "p_type") => true,
533             ("Elf64_Phdr", "p_type") => true,
534             _ => false,
535         }
536     });
537 
538     cfg.generate("../src/lib.rs", "main.rs");
539 }
540 
541 fn test_windows(target: &str) {
542     assert!(target.contains("windows"));
543     let gnu = target.contains("gnu");
544 
545     let mut cfg = ctest_cfg();
546     if target.contains("msvc") {
547         cfg.flag("/wd4324");
548     }
549     cfg.define("_WIN32_WINNT", Some("0x8000"));
550 
551     headers! { cfg:
552         "direct.h",
553         "errno.h",
554         "fcntl.h",
555         "io.h",
556         "limits.h",
557         "locale.h",
558         "process.h",
559         "signal.h",
560         "stddef.h",
561         "stdint.h",
562         "stdio.h",
563         "stdlib.h",
564         "sys/stat.h",
565         "sys/types.h",
566         "sys/utime.h",
567         "time.h",
568         "wchar.h",
569         [gnu]: "ws2tcpip.h",
570         [!gnu]: "Winsock2.h",
571     }
572 
573     cfg.type_name(move |ty, is_struct, is_union| {
574         match ty {
575             // Just pass all these through, no need for a "struct" prefix
576             "FILE" | "DIR" | "Dl_info" => ty.to_string(),
577 
578             // FIXME: these don't exist:
579             "time64_t" => "__time64_t".to_string(),
580             "ssize_t" => "SSIZE_T".to_string(),
581 
582             "sighandler_t" if !gnu => "_crt_signal_t".to_string(),
583             "sighandler_t" if gnu => "__p_sig_fn_t".to_string(),
584 
585             t if is_union => format!("union {}", t),
586             t if t.ends_with("_t") => t.to_string(),
587 
588             // Windows uppercase structs don't have `struct` in front:
589             t if is_struct => {
590                 if ty.clone().chars().next().unwrap().is_uppercase() {
591                     t.to_string()
592                 } else if t == "stat" {
593                     "struct __stat64".to_string()
594                 } else if t == "utimbuf" {
595                     "struct __utimbuf64".to_string()
596                 } else {
597                     // put `struct` in front of all structs:
598                     format!("struct {}", t)
599                 }
600             }
601             t => t.to_string(),
602         }
603     });
604 
605     cfg.fn_cname(move |name, cname| cname.unwrap_or(name).to_string());
606 
607     cfg.skip_type(move |name| match name {
608         "SSIZE_T" if !gnu => true,
609         "ssize_t" if !gnu => true,
610         _ => false,
611     });
612 
613     cfg.skip_struct(move |ty| {
614         if ty.starts_with("__c_anonymous_") {
615             return true;
616         }
617         return false;
618     });
619 
620     cfg.skip_const(move |name| {
621         match name {
622             // FIXME: API error:
623             // SIG_ERR type is "void (*)(int)", not "int"
624             "SIG_ERR" |
625             // Similar for SIG_DFL/IGN/GET/SGE/ACK
626             "SIG_DFL" | "SIG_IGN" | "SIG_GET" | "SIG_SGE" | "SIG_ACK" => true,
627             // FIXME: newer windows-gnu environment on CI?
628             "_O_OBTAIN_DIR" if gnu => true,
629             _ => false,
630         }
631     });
632 
633     cfg.skip_field(move |s, field| match s {
634         "CONTEXT" if field == "Fp" => true,
635         _ => false,
636     });
637     // FIXME: All functions point to the wrong addresses?
638     cfg.skip_fn_ptrcheck(|_| true);
639 
640     cfg.skip_signededness(move |c| {
641         match c {
642             // windows-isms
643             n if n.starts_with("P") => true,
644             n if n.starts_with("H") => true,
645             n if n.starts_with("LP") => true,
646             "sighandler_t" if gnu => true,
647             _ => false,
648         }
649     });
650 
651     cfg.skip_fn(move |name| {
652         match name {
653             // FIXME: https://github.com/rust-lang/libc/issues/1272
654             "execv" | "execve" | "execvp" | "execvpe" => true,
655 
656             _ => false,
657         }
658     });
659 
660     cfg.generate("../src/lib.rs", "main.rs");
661 }
662 
663 fn test_redox(target: &str) {
664     assert!(target.contains("redox"));
665 
666     let mut cfg = ctest_cfg();
667     cfg.flag("-Wno-deprecated-declarations");
668 
669     headers! {
670         cfg:
671         "ctype.h",
672         "dirent.h",
673         "dlfcn.h",
674         "errno.h",
675         "fcntl.h",
676         "grp.h",
677         "limits.h",
678         "locale.h",
679         "netdb.h",
680         "netinet/in.h",
681         "netinet/ip.h",
682         "netinet/tcp.h",
683         "poll.h",
684         "pwd.h",
685         "semaphore.h",
686         "string.h",
687         "strings.h",
688         "sys/file.h",
689         "sys/ioctl.h",
690         "sys/mman.h",
691         "sys/ptrace.h",
692         "sys/resource.h",
693         "sys/socket.h",
694         "sys/stat.h",
695         "sys/statvfs.h",
696         "sys/time.h",
697         "sys/types.h",
698         "sys/uio.h",
699         "sys/un.h",
700         "sys/utsname.h",
701         "sys/wait.h",
702         "termios.h",
703         "time.h",
704         "unistd.h",
705         "utime.h",
706         "wchar.h",
707     }
708 
709     cfg.generate("../src/lib.rs", "main.rs");
710 }
711 
712 fn test_solarish(target: &str) {
713     let is_solaris = target.contains("solaris");
714     let is_illumos = target.contains("illumos");
715     assert!(is_solaris || is_illumos);
716 
717     // ctest generates arguments supported only by clang, so make sure to run with CC=clang.
718     // While debugging, "CFLAGS=-ferror-limit=<large num>" is useful to get more error output.
719     let mut cfg = ctest_cfg();
720     cfg.flag("-Wno-deprecated-declarations");
721 
722     cfg.define("_XOPEN_SOURCE", Some("700"));
723     cfg.define("__EXTENSIONS__", None);
724     cfg.define("_LCONV_C99", None);
725 
726     headers! {
727         cfg:
728         "ctype.h",
729         "dirent.h",
730         "dlfcn.h",
731         "door.h",
732         "errno.h",
733         "execinfo.h",
734         "fcntl.h",
735         "glob.h",
736         "grp.h",
737         "ifaddrs.h",
738         "langinfo.h",
739         "limits.h",
740         "locale.h",
741         "mqueue.h",
742         "net/if.h",
743         "net/if_arp.h",
744         "net/route.h",
745         "netdb.h",
746         "netinet/in.h",
747         "netinet/ip.h",
748         "netinet/tcp.h",
749         "netinet/udp.h",
750         "poll.h",
751         "port.h",
752         "pthread.h",
753         "pwd.h",
754         "resolv.h",
755         "sched.h",
756         "semaphore.h",
757         "signal.h",
758         "stddef.h",
759         "stdint.h",
760         "stdio.h",
761         "stdlib.h",
762         "string.h",
763         "sys/epoll.h",
764         "sys/eventfd.h",
765         "sys/file.h",
766         "sys/filio.h",
767         "sys/ioctl.h",
768         "sys/loadavg.h",
769         "sys/mman.h",
770         "sys/mount.h",
771         "sys/priv.h",
772         "sys/pset.h",
773         "sys/resource.h",
774         "sys/socket.h",
775         "sys/stat.h",
776         "sys/statvfs.h",
777         "sys/stropts.h",
778         "sys/shm.h",
779         "sys/time.h",
780         "sys/times.h",
781         "sys/timex.h",
782         "sys/types.h",
783         "sys/uio.h",
784         "sys/un.h",
785         "sys/utsname.h",
786         "sys/wait.h",
787         "syslog.h",
788         "termios.h",
789         "thread.h",
790         "time.h",
791         "ucontext.h",
792         "unistd.h",
793         "utime.h",
794         "utmpx.h",
795         "wchar.h",
796     }
797 
798     cfg.skip_type(move |ty| {
799         match ty {
800             // sighandler_t is not present here
801             "sighandler_t" => true,
802             _ => false,
803         }
804     });
805 
806     cfg.type_name(move |ty, is_struct, is_union| match ty {
807         "FILE" => "__FILE".to_string(),
808         "DIR" | "Dl_info" => ty.to_string(),
809         t if t.ends_with("_t") => t.to_string(),
810         t if is_struct => format!("struct {}", t),
811         t if is_union => format!("union {}", t),
812         t => t.to_string(),
813     });
814 
815     cfg.field_name(move |struct_, field| {
816         match struct_ {
817             // rust struct uses raw u64, rather than union
818             "epoll_event" if field == "u64" => "data.u64".to_string(),
819             // rust struct was committed with typo for Solaris
820             "door_arg_t" if field == "dec_num" => "desc_num".to_string(),
821             "stat" if field.ends_with("_nsec") => {
822                 // expose stat.Xtim.tv_nsec fields
823                 field.trim_end_matches("e_nsec").to_string() + ".tv_nsec"
824             }
825             _ => field.to_string(),
826         }
827     });
828 
829     cfg.skip_const(move |name| match name {
830         "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK" | "DT_SOCK"
831         | "USRQUOTA" | "GRPQUOTA" | "PRIO_MIN" | "PRIO_MAX" => true,
832 
833         // skip sighandler_t assignments
834         "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true,
835 
836         "DT_UNKNOWN" => true,
837 
838         "_UTX_LINESIZE" | "_UTX_USERSIZE" | "_UTX_PADSIZE" | "_UTX_IDSIZE" | "_UTX_HOSTSIZE" => {
839             true
840         }
841 
842         "EADI" | "EXTPROC" | "IPC_SEAT" => true,
843 
844         // This evaluates to a sysconf() call rather than a constant
845         "PTHREAD_STACK_MIN" => true,
846 
847         // EPOLLEXCLUSIVE is a relatively recent addition to the epoll interface and may not be
848         // defined on older systems.  It is, however, safe to use on systems which do not
849         // explicitly support it. (A no-op is an acceptable implementation of EPOLLEXCLUSIVE.)
850         "EPOLLEXCLUSIVE" => true,
851 
852         _ => false,
853     });
854 
855     cfg.skip_struct(move |ty| {
856         if ty.starts_with("__c_anonymous_") {
857             return true;
858         }
859         // the union handling is a mess
860         if ty.contains("door_desc_t_") {
861             return true;
862         }
863         match ty {
864             // union, not a struct
865             "sigval" => true,
866             // a bunch of solaris-only fields
867             "utmpx" if is_illumos => true,
868             _ => false,
869         }
870     });
871 
872     cfg.skip_field(move |s, field| {
873         match s {
874             // C99 sizing on this is tough
875             "dirent" if field == "d_name" => true,
876             // the union/macro makes this rough
877             "sigaction" if field == "sa_sigaction" => true,
878             // Missing in illumos
879             "sigevent" if field == "ss_sp" => true,
880             // Avoid sigval union issues
881             "sigevent" if field == "sigev_value" => true,
882             // const issues
883             "sigevent" if field == "sigev_notify_attributes" => true,
884 
885             // Avoid const and union issues
886             "door_arg" if field == "desc_ptr" => true,
887             "door_desc_t" if field == "d_data" => true,
888             "door_arg_t" if field.ends_with("_ptr") => true,
889             "door_arg_t" if field.ends_with("rbuf") => true,
890 
891             _ => false,
892         }
893     });
894 
895     cfg.skip_fn(move |name| {
896         // skip those that are manually verified
897         match name {
898             // const-ness only added recently
899             "dladdr" => true,
900 
901             // Definition of those functions as changed since unified headers
902             // from NDK r14b These changes imply some API breaking changes but
903             // are still ABI compatible. We can wait for the next major release
904             // to be compliant with the new API.
905             //
906             // FIXME: unskip these for next major release
907             "setpriority" | "personality" => true,
908 
909             // signal is defined in terms of sighandler_t, so ignore
910             "signal" => true,
911 
912             // Currently missing
913             "cfmakeraw" | "cfsetspeed" => true,
914 
915             // const-ness issues
916             "execv" | "execve" | "execvp" | "settimeofday" | "sethostname" => true,
917 
918             // Solaris-different
919             "getpwent_r" | "getgrent_r" | "updwtmpx" if is_illumos => true,
920             "madvise" | "mprotect" if is_illumos => true,
921             "door_call" | "door_return" | "door_create" if is_illumos => true,
922 
923             // These functions may return int or void depending on the exact
924             // configuration of the compilation environment, but the return
925             // value is not useful (always 0) so we can ignore it:
926             "setservent" | "endservent" if is_illumos => true,
927 
928             _ => false,
929         }
930     });
931 
932     cfg.generate("../src/lib.rs", "main.rs");
933 }
934 
935 fn test_netbsd(target: &str) {
936     assert!(target.contains("netbsd"));
937     let rumprun = target.contains("rumprun");
938     let mut cfg = ctest_cfg();
939 
940     cfg.flag("-Wno-deprecated-declarations");
941     cfg.define("_NETBSD_SOURCE", Some("1"));
942 
943     headers! {
944         cfg:
945         "elf.h",
946         "errno.h",
947         "fcntl.h",
948         "limits.h",
949         "link.h",
950         "locale.h",
951         "stddef.h",
952         "stdint.h",
953         "stdio.h",
954         "stdlib.h",
955         "sys/stat.h",
956         "sys/types.h",
957         "time.h",
958         "wchar.h",
959         "aio.h",
960         "ctype.h",
961         "dirent.h",
962         "dlfcn.h",
963         "glob.h",
964         "grp.h",
965         "ifaddrs.h",
966         "langinfo.h",
967         "net/bpf.h",
968         "net/if.h",
969         "net/if_arp.h",
970         "net/if_dl.h",
971         "net/route.h",
972         "netdb.h",
973         "netinet/in.h",
974         "netinet/ip.h",
975         "netinet/tcp.h",
976         "netinet/udp.h",
977         "poll.h",
978         "pthread.h",
979         "pwd.h",
980         "regex.h",
981         "resolv.h",
982         "sched.h",
983         "semaphore.h",
984         "signal.h",
985         "string.h",
986         "sys/endian.h",
987         "sys/exec_elf.h",
988         "sys/extattr.h",
989         "sys/file.h",
990         "sys/ioctl.h",
991         "sys/ioctl_compat.h",
992         "sys/ktrace.h",
993         "sys/mman.h",
994         "sys/mount.h",
995         "sys/ptrace.h",
996         "sys/resource.h",
997         "sys/shm.h",
998         "sys/socket.h",
999         "sys/statvfs.h",
1000         "sys/sysctl.h",
1001         "sys/time.h",
1002         "sys/times.h",
1003         "sys/timex.h",
1004         "sys/ucontext.h",
1005         "sys/uio.h",
1006         "sys/un.h",
1007         "sys/utsname.h",
1008         "sys/wait.h",
1009         "syslog.h",
1010         "termios.h",
1011         "ufs/ufs/quota.h",
1012         "ufs/ufs/quota1.h",
1013         "unistd.h",
1014         "util.h",
1015         "utime.h",
1016         "mqueue.h",
1017         "netinet/dccp.h",
1018         "sys/event.h",
1019         "sys/quota.h",
1020         "sys/shm.h",
1021         "iconv.h",
1022     }
1023 
1024     cfg.type_name(move |ty, is_struct, is_union| {
1025         match ty {
1026             // Just pass all these through, no need for a "struct" prefix
1027             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr"
1028             | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr"
1029             | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(),
1030 
1031             // OSX calls this something else
1032             "sighandler_t" => "sig_t".to_string(),
1033 
1034             t if is_union => format!("union {}", t),
1035 
1036             t if t.ends_with("_t") => t.to_string(),
1037 
1038             // put `struct` in front of all structs:.
1039             t if is_struct => format!("struct {}", t),
1040 
1041             t => t.to_string(),
1042         }
1043     });
1044 
1045     cfg.field_name(move |struct_, field| {
1046         match field {
1047             // Our stat *_nsec fields normally don't actually exist but are part
1048             // of a timeval struct
1049             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
1050                 s.replace("e_nsec", ".tv_nsec")
1051             }
1052             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
1053             s => s.to_string(),
1054         }
1055     });
1056 
1057     cfg.skip_type(move |ty| {
1058         if ty.starts_with("__c_anonymous_") {
1059             return true;
1060         }
1061         match ty {
1062             // FIXME: sighandler_t is crazy across platforms
1063             "sighandler_t" => true,
1064             _ => false,
1065         }
1066     });
1067 
1068     cfg.skip_struct(move |ty| {
1069         match ty {
1070             // This is actually a union, not a struct
1071             "sigval" => true,
1072             // These are tested as part of the linux_fcntl tests since there are
1073             // header conflicts when including them with all the other structs.
1074             "termios2" => true,
1075             _ => false,
1076         }
1077     });
1078 
1079     cfg.skip_signededness(move |c| {
1080         match c {
1081             "LARGE_INTEGER" | "float" | "double" => true,
1082             n if n.starts_with("pthread") => true,
1083             // sem_t is a struct or pointer
1084             "sem_t" => true,
1085             _ => false,
1086         }
1087     });
1088 
1089     cfg.skip_const(move |name| {
1090         match name {
1091             "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness
1092             "SIGUNUSED" => true,                       // removed in glibc 2.26
1093 
1094             // weird signed extension or something like that?
1095             "MS_NOUSER" => true,
1096             "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13
1097             "BOTHER" => true,
1098 
1099             _ => false,
1100         }
1101     });
1102 
1103     cfg.skip_fn(move |name| {
1104         match name {
1105             // FIXME: https://github.com/rust-lang/libc/issues/1272
1106             "execv" | "execve" | "execvp" => true,
1107 
1108             "getrlimit" | "getrlimit64" |    // non-int in 1st arg
1109             "setrlimit" | "setrlimit64" |    // non-int in 1st arg
1110             "prlimit" | "prlimit64" |        // non-int in 2nd arg
1111 
1112             // These functions presumably exist on netbsd but don't look like
1113             // they're implemented on rumprun yet, just let them slide for now.
1114             // Some of them look like they have headers but then don't have
1115             // corresponding actual definitions either...
1116             "shm_open" |
1117             "shm_unlink" |
1118             "syscall" |
1119             "mq_open" |
1120             "mq_close" |
1121             "mq_getattr" |
1122             "mq_notify" |
1123             "mq_receive" |
1124             "mq_send" |
1125             "mq_setattr" |
1126             "mq_timedreceive" |
1127             "mq_timedsend" |
1128             "mq_unlink" |
1129             "ptrace" |
1130             "sigaltstack" if rumprun => true,
1131 
1132             _ => false,
1133         }
1134     });
1135 
1136     cfg.skip_field_type(move |struct_, field| {
1137         // This is a weird union, don't check the type.
1138         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
1139         // sighandler_t type is super weird
1140         (struct_ == "sigaction" && field == "sa_sigaction") ||
1141         // sigval is actually a union, but we pretend it's a struct
1142         (struct_ == "sigevent" && field == "sigev_value") ||
1143         // aio_buf is "volatile void*" and Rust doesn't understand volatile
1144         (struct_ == "aiocb" && field == "aio_buf")
1145     });
1146 
1147     cfg.skip_field(|struct_, field| {
1148         match (struct_, field) {
1149             // conflicting with `p_type` macro from <resolve.h>.
1150             ("Elf32_Phdr", "p_type") => true,
1151             ("Elf64_Phdr", "p_type") => true,
1152             // pthread_spin_t is a volatile uchar
1153             ("pthread_spinlock_t", "pts_spin") => true,
1154             _ => false,
1155         }
1156     });
1157 
1158     cfg.generate("../src/lib.rs", "main.rs");
1159 }
1160 
1161 fn test_dragonflybsd(target: &str) {
1162     assert!(target.contains("dragonfly"));
1163     let mut cfg = ctest_cfg();
1164     cfg.flag("-Wno-deprecated-declarations");
1165 
1166     headers! {
1167         cfg:
1168         "aio.h",
1169         "ctype.h",
1170         "dirent.h",
1171         "dlfcn.h",
1172         "errno.h",
1173         "execinfo.h",
1174         "fcntl.h",
1175         "glob.h",
1176         "grp.h",
1177         "ifaddrs.h",
1178         "langinfo.h",
1179         "limits.h",
1180         "link.h",
1181         "locale.h",
1182         "mqueue.h",
1183         "net/bpf.h",
1184         "net/if.h",
1185         "net/if_arp.h",
1186         "net/if_dl.h",
1187         "net/route.h",
1188         "netdb.h",
1189         "netinet/in.h",
1190         "netinet/ip.h",
1191         "netinet/tcp.h",
1192         "netinet/udp.h",
1193         "poll.h",
1194         "pthread.h",
1195         "pthread_np.h",
1196         "pwd.h",
1197         "regex.h",
1198         "resolv.h",
1199         "sched.h",
1200         "semaphore.h",
1201         "signal.h",
1202         "stddef.h",
1203         "stdint.h",
1204         "stdio.h",
1205         "stdlib.h",
1206         "string.h",
1207         "sys/event.h",
1208         "sys/file.h",
1209         "sys/ioctl.h",
1210         "sys/ipc.h",
1211         "sys/ktrace.h",
1212         "sys/malloc.h",
1213         "sys/mman.h",
1214         "sys/mount.h",
1215         "sys/procctl.h",
1216         "sys/ptrace.h",
1217         "sys/resource.h",
1218         "sys/rtprio.h",
1219         "sys/sched.h",
1220         "sys/shm.h",
1221         "sys/socket.h",
1222         "sys/stat.h",
1223         "sys/statvfs.h",
1224         "sys/sysctl.h",
1225         "sys/time.h",
1226         "sys/times.h",
1227         "sys/timex.h",
1228         "sys/types.h",
1229         "sys/checkpoint.h",
1230         "sys/uio.h",
1231         "sys/un.h",
1232         "sys/utsname.h",
1233         "sys/wait.h",
1234         "syslog.h",
1235         "termios.h",
1236         "time.h",
1237         "ucontext.h",
1238         "unistd.h",
1239         "util.h",
1240         "utime.h",
1241         "utmpx.h",
1242         "vfs/ufs/quota.h",
1243         "wchar.h",
1244         "iconv.h",
1245     }
1246 
1247     cfg.type_name(move |ty, is_struct, is_union| {
1248         match ty {
1249             // Just pass all these through, no need for a "struct" prefix
1250             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr"
1251             | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr"
1252             | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(),
1253 
1254             // FIXME: OSX calls this something else
1255             "sighandler_t" => "sig_t".to_string(),
1256 
1257             t if is_union => format!("union {}", t),
1258 
1259             t if t.ends_with("_t") => t.to_string(),
1260 
1261             // sigval is a struct in Rust, but a union in C:
1262             "sigval" => format!("union sigval"),
1263 
1264             // put `struct` in front of all structs:.
1265             t if is_struct => format!("struct {}", t),
1266 
1267             t => t.to_string(),
1268         }
1269     });
1270 
1271     cfg.field_name(move |struct_, field| {
1272         match field {
1273             // Our stat *_nsec fields normally don't actually exist but are part
1274             // of a timeval struct
1275             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
1276                 s.replace("e_nsec", ".tv_nsec")
1277             }
1278             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
1279             // Field is named `type` in C but that is a Rust keyword,
1280             // so these fields are translated to `type_` in the bindings.
1281             "type_" if struct_ == "rtprio" => "type".to_string(),
1282             s => s.to_string(),
1283         }
1284     });
1285 
1286     cfg.skip_type(move |ty| {
1287         match ty {
1288             // sighandler_t is crazy across platforms
1289             "sighandler_t" => true,
1290 
1291             _ => false,
1292         }
1293     });
1294 
1295     cfg.skip_struct(move |ty| {
1296         match ty {
1297             // FIXME: These are tested as part of the linux_fcntl tests since
1298             // there are header conflicts when including them with all the other
1299             // structs.
1300             "termios2" => true,
1301 
1302             _ => false,
1303         }
1304     });
1305 
1306     cfg.skip_signededness(move |c| {
1307         match c {
1308             "LARGE_INTEGER" | "float" | "double" => true,
1309             // uuid_t is a struct, not an integer.
1310             "uuid_t" => true,
1311             n if n.starts_with("pthread") => true,
1312             // sem_t is a struct or pointer
1313             "sem_t" => true,
1314             // mqd_t is a pointer on DragonFly
1315             "mqd_t" => true,
1316 
1317             _ => false,
1318         }
1319     });
1320 
1321     cfg.skip_const(move |name| {
1322         match name {
1323             "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness
1324 
1325             // weird signed extension or something like that?
1326             "MS_NOUSER" => true,
1327             "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13
1328 
1329             // These are defined for Solaris 11, but the crate is tested on
1330             // illumos, where they are currently not defined
1331             "EADI" | "PORT_SOURCE_POSTWAIT" | "PORT_SOURCE_SIGNAL" | "PTHREAD_STACK_MIN" => true,
1332 
1333             _ => false,
1334         }
1335     });
1336 
1337     cfg.skip_fn(move |name| {
1338         // skip those that are manually verified
1339         match name {
1340             // FIXME: https://github.com/rust-lang/libc/issues/1272
1341             "execv" | "execve" | "execvp" | "fexecve" => true,
1342 
1343             "getrlimit" | "getrlimit64" |    // non-int in 1st arg
1344             "setrlimit" | "setrlimit64" |    // non-int in 1st arg
1345             "prlimit" | "prlimit64"        // non-int in 2nd arg
1346              => true,
1347 
1348             _ => false,
1349         }
1350     });
1351 
1352     cfg.skip_field_type(move |struct_, field| {
1353         // This is a weird union, don't check the type.
1354         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
1355         // sighandler_t type is super weird
1356         (struct_ == "sigaction" && field == "sa_sigaction") ||
1357         // sigval is actually a union, but we pretend it's a struct
1358         (struct_ == "sigevent" && field == "sigev_value") ||
1359         // aio_buf is "volatile void*" and Rust doesn't understand volatile
1360         (struct_ == "aiocb" && field == "aio_buf")
1361     });
1362 
1363     cfg.skip_field(move |struct_, field| {
1364         // this is actually a union on linux, so we can't represent it well and
1365         // just insert some padding.
1366         (struct_ == "siginfo_t" && field == "_pad") ||
1367         // sigev_notify_thread_id is actually part of a sigev_un union
1368         (struct_ == "sigevent" && field == "sigev_notify_thread_id")
1369     });
1370 
1371     cfg.generate("../src/lib.rs", "main.rs");
1372 }
1373 
1374 fn test_wasi(target: &str) {
1375     assert!(target.contains("wasi"));
1376 
1377     let mut cfg = ctest_cfg();
1378     cfg.define("_GNU_SOURCE", None);
1379 
1380     headers! { cfg:
1381         "ctype.h",
1382         "dirent.h",
1383         "errno.h",
1384         "fcntl.h",
1385         "limits.h",
1386         "locale.h",
1387         "malloc.h",
1388         "poll.h",
1389         "sched.h",
1390         "stdbool.h",
1391         "stddef.h",
1392         "stdint.h",
1393         "stdio.h",
1394         "stdlib.h",
1395         "string.h",
1396         "sys/resource.h",
1397         "sys/select.h",
1398         "sys/socket.h",
1399         "sys/stat.h",
1400         "sys/times.h",
1401         "sys/types.h",
1402         "sys/uio.h",
1403         "sys/utsname.h",
1404         "sys/ioctl.h",
1405         "time.h",
1406         "unistd.h",
1407         "wasi/api.h",
1408         "wasi/libc.h",
1409         "wasi/libc-find-relpath.h",
1410         "wasi/libc-nocwd.h",
1411         "wchar.h",
1412     }
1413 
1414     cfg.type_name(move |ty, is_struct, is_union| match ty {
1415         "FILE" | "fd_set" | "DIR" => ty.to_string(),
1416         t if is_union => format!("union {}", t),
1417         t if t.starts_with("__wasi") && t.ends_with("_u") => format!("union {}", t),
1418         t if t.starts_with("__wasi") && is_struct => format!("struct {}", t),
1419         t if t.ends_with("_t") => t.to_string(),
1420         t if is_struct => format!("struct {}", t),
1421         t => t.to_string(),
1422     });
1423 
1424     cfg.field_name(move |_struct, field| {
1425         match field {
1426             // deal with fields as rust keywords
1427             "type_" => "type".to_string(),
1428             s => s.to_string(),
1429         }
1430     });
1431 
1432     // Looks like LLD doesn't merge duplicate imports, so if the Rust
1433     // code imports from a module and the C code also imports from a
1434     // module we end up with two imports of function pointers which
1435     // import the same thing but have different function pointers
1436     cfg.skip_fn_ptrcheck(|f| f.starts_with("__wasi"));
1437 
1438     // d_name is declared as a flexible array in WASI libc, so it
1439     // doesn't support sizeof.
1440     cfg.skip_field(|s, field| s == "dirent" && field == "d_name");
1441 
1442     // Currently Rust/clang disagree on function argument ABI, so skip these
1443     // tests. For more info see WebAssembly/tool-conventions#88
1444     cfg.skip_roundtrip(|_| true);
1445 
1446     cfg.generate("../src/lib.rs", "main.rs");
1447 }
1448 
1449 fn test_android(target: &str) {
1450     assert!(target.contains("android"));
1451     let target_pointer_width = match target {
1452         t if t.contains("aarch64") || t.contains("x86_64") => 64,
1453         t if t.contains("i686") || t.contains("arm") => 32,
1454         t => panic!("unsupported target: {}", t),
1455     };
1456     let x86 = target.contains("i686") || target.contains("x86_64");
1457 
1458     let mut cfg = ctest_cfg();
1459     cfg.define("_GNU_SOURCE", None);
1460 
1461     headers! { cfg:
1462                "arpa/inet.h",
1463                "ctype.h",
1464                "dirent.h",
1465                "dlfcn.h",
1466                "elf.h",
1467                "errno.h",
1468                "fcntl.h",
1469                "grp.h",
1470                "ifaddrs.h",
1471                "limits.h",
1472                "link.h",
1473                "locale.h",
1474                "malloc.h",
1475                "net/ethernet.h",
1476                "net/if.h",
1477                "net/if_arp.h",
1478                "net/route.h",
1479                "netdb.h",
1480                "netinet/in.h",
1481                "netinet/ip.h",
1482                "netinet/tcp.h",
1483                "netinet/udp.h",
1484                "netpacket/packet.h",
1485                "poll.h",
1486                "pthread.h",
1487                "pty.h",
1488                "pwd.h",
1489                "regex.h",
1490                "resolv.h",
1491                "sched.h",
1492                "semaphore.h",
1493                "signal.h",
1494                "stddef.h",
1495                "stdint.h",
1496                "stdio.h",
1497                "stdlib.h",
1498                "string.h",
1499                "sys/auxv.h",
1500                "sys/epoll.h",
1501                "sys/eventfd.h",
1502                "sys/file.h",
1503                "sys/fsuid.h",
1504                "sys/inotify.h",
1505                "sys/ioctl.h",
1506                "sys/mman.h",
1507                "sys/mount.h",
1508                "sys/personality.h",
1509                "sys/prctl.h",
1510                "sys/ptrace.h",
1511                "sys/random.h",
1512                "sys/reboot.h",
1513                "sys/resource.h",
1514                "sys/sendfile.h",
1515                "sys/signalfd.h",
1516                "sys/socket.h",
1517                "sys/stat.h",
1518                "sys/statvfs.h",
1519                "sys/swap.h",
1520                "sys/syscall.h",
1521                "sys/sysinfo.h",
1522                "sys/system_properties.h",
1523                "sys/time.h",
1524                "sys/timerfd.h",
1525                "sys/times.h",
1526                "sys/types.h",
1527                "sys/ucontext.h",
1528                "sys/uio.h",
1529                "sys/un.h",
1530                "sys/utsname.h",
1531                "sys/vfs.h",
1532                "sys/xattr.h",
1533                "sys/wait.h",
1534                "syslog.h",
1535                "termios.h",
1536                "time.h",
1537                "unistd.h",
1538                "utime.h",
1539                "utmp.h",
1540                "wchar.h",
1541                "xlocale.h",
1542                // time64_t is not defined for 64-bit targets If included it will
1543                // generate the error 'Your time_t is already 64-bit'
1544                [target_pointer_width == 32]: "time64.h",
1545                [x86]: "sys/reg.h",
1546     }
1547 
1548     // Include linux headers at the end:
1549     headers! { cfg:
1550                 "asm/mman.h",
1551                 "linux/auxvec.h",
1552                 "linux/dccp.h",
1553                 "linux/elf.h",
1554                 "linux/errqueue.h",
1555                 "linux/falloc.h",
1556                 "linux/futex.h",
1557                 "linux/fs.h",
1558                 "linux/genetlink.h",
1559                 "linux/if_alg.h",
1560                 "linux/if_ether.h",
1561                 "linux/if_tun.h",
1562                 "linux/magic.h",
1563                 "linux/memfd.h",
1564                 "linux/module.h",
1565                 "linux/net_tstamp.h",
1566                 "linux/netfilter/nfnetlink.h",
1567                 "linux/netfilter/nfnetlink_log.h",
1568                 "linux/netfilter/nfnetlink_queue.h",
1569                 "linux/netfilter/nf_tables.h",
1570                 "linux/netfilter_ipv4.h",
1571                 "linux/netfilter_ipv6.h",
1572                 "linux/netfilter_ipv6/ip6_tables.h",
1573                 "linux/netlink.h",
1574                 "linux/quota.h",
1575                 "linux/reboot.h",
1576                 "linux/seccomp.h",
1577                 "linux/sched.h",
1578                 "linux/sockios.h",
1579                 "linux/vm_sockets.h",
1580                 "linux/wait.h",
1581 
1582     }
1583 
1584     // Include Android-specific headers:
1585     headers! { cfg:
1586                 "android/set_abort_message.h"
1587     }
1588 
1589     cfg.type_name(move |ty, is_struct, is_union| {
1590         match ty {
1591             // Just pass all these through, no need for a "struct" prefix
1592             "FILE" | "fd_set" | "Dl_info" | "Elf32_Phdr" | "Elf64_Phdr" => ty.to_string(),
1593 
1594             t if is_union => format!("union {}", t),
1595 
1596             t if t.ends_with("_t") => t.to_string(),
1597 
1598             // sigval is a struct in Rust, but a union in C:
1599             "sigval" => format!("union sigval"),
1600 
1601             // put `struct` in front of all structs:.
1602             t if is_struct => format!("struct {}", t),
1603 
1604             t => t.to_string(),
1605         }
1606     });
1607 
1608     cfg.field_name(move |struct_, field| {
1609         match field {
1610             // Our stat *_nsec fields normally don't actually exist but are part
1611             // of a timeval struct
1612             s if s.ends_with("_nsec") && struct_.starts_with("stat") => s.to_string(),
1613             // FIXME: appears that `epoll_event.data` is an union
1614             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
1615             s => s.to_string(),
1616         }
1617     });
1618 
1619     cfg.skip_type(move |ty| {
1620         match ty {
1621             // FIXME: `sighandler_t` type is incorrect, see:
1622             // https://github.com/rust-lang/libc/issues/1359
1623             "sighandler_t" => true,
1624             _ => false,
1625         }
1626     });
1627 
1628     cfg.skip_struct(move |ty| {
1629         if ty.starts_with("__c_anonymous_") {
1630             return true;
1631         }
1632         match ty {
1633             // These are tested as part of the linux_fcntl tests since there are
1634             // header conflicts when including them with all the other structs.
1635             "termios2" => true,
1636             // uc_sigmask and uc_sigmask64 of ucontext_t are an anonymous union
1637             "ucontext_t" => true,
1638             // 'private' type
1639             "prop_info" => true,
1640 
1641             _ => false,
1642         }
1643     });
1644 
1645     cfg.skip_const(move |name| {
1646         match name {
1647             // FIXME: deprecated: not available in any header
1648             // See: https://github.com/rust-lang/libc/issues/1356
1649             "ENOATTR" => true,
1650 
1651             // FIXME: still necessary?
1652             "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness
1653             // FIXME: deprecated - removed in glibc 2.26
1654             "SIGUNUSED" => true,
1655 
1656             // Needs a newer Android SDK for the definition
1657             "P_PIDFD" => true,
1658 
1659             // Requires Linux kernel 5.6
1660             "VMADDR_CID_LOCAL" => true,
1661 
1662             _ => false,
1663         }
1664     });
1665 
1666     cfg.skip_fn(move |name| {
1667         // skip those that are manually verified
1668         match name {
1669             // FIXME: https://github.com/rust-lang/libc/issues/1272
1670             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
1671 
1672             // There are two versions of the sterror_r function, see
1673             //
1674             // https://linux.die.net/man/3/strerror_r
1675             //
1676             // An XSI-compliant version provided if:
1677             //
1678             // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
1679             //
1680             // and a GNU specific version provided if _GNU_SOURCE is defined.
1681             //
1682             // libc provides bindings for the XSI-compliant version, which is
1683             // preferred for portable applications.
1684             //
1685             // We skip the test here since here _GNU_SOURCE is defined, and
1686             // test the XSI version below.
1687             "strerror_r" => true,
1688             "reallocarray" => true,
1689             "__system_property_wait" => true,
1690 
1691             _ => false,
1692         }
1693     });
1694 
1695     cfg.skip_field_type(move |struct_, field| {
1696         // This is a weird union, don't check the type.
1697         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
1698         // sigval is actually a union, but we pretend it's a struct
1699         (struct_ == "sigevent" && field == "sigev_value") ||
1700         // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
1701         // incorrect, see: https://github.com/rust-lang/libc/issues/1359
1702         (struct_ == "sigaction" && field == "sa_sigaction") ||
1703         // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet.
1704         (struct_ == "signalfd_siginfo" && field == "ssi_call_addr")
1705     });
1706 
1707     cfg.skip_field(move |struct_, field| {
1708         // this is actually a union on linux, so we can't represent it well and
1709         // just insert some padding.
1710         (struct_ == "siginfo_t" && field == "_pad") ||
1711         // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
1712         // incorrect, see: https://github.com/rust-lang/libc/issues/1359
1713         (struct_ == "sigaction" && field == "sa_sigaction") ||
1714         // sigev_notify_thread_id is actually part of a sigev_un union
1715         (struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
1716         // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet.
1717         (struct_ == "signalfd_siginfo" && (field == "ssi_syscall" ||
1718                                            field == "ssi_call_addr" ||
1719                                            field == "ssi_arch"))
1720     });
1721 
1722     cfg.skip_field(|struct_, field| {
1723         match (struct_, field) {
1724             // conflicting with `p_type` macro from <resolve.h>.
1725             ("Elf32_Phdr", "p_type") => true,
1726             ("Elf64_Phdr", "p_type") => true,
1727 
1728             // this is actually a union on linux, so we can't represent it well and
1729             // just insert some padding.
1730             ("siginfo_t", "_pad") => true,
1731 
1732             _ => false,
1733         }
1734     });
1735 
1736     cfg.generate("../src/lib.rs", "main.rs");
1737 
1738     test_linux_like_apis(target);
1739 }
1740 
1741 fn test_freebsd(target: &str) {
1742     assert!(target.contains("freebsd"));
1743     let mut cfg = ctest_cfg();
1744 
1745     let freebsd_ver = which_freebsd();
1746 
1747     match freebsd_ver {
1748         Some(10) => cfg.cfg("freebsd10", None),
1749         Some(11) => cfg.cfg("freebsd11", None),
1750         Some(12) => cfg.cfg("freebsd12", None),
1751         Some(13) => cfg.cfg("freebsd13", None),
1752         _ => &mut cfg,
1753     };
1754 
1755     // Required for `getline`:
1756     cfg.define("_WITH_GETLINE", None);
1757     // Required for making freebsd11_stat available in the headers
1758     match freebsd_ver {
1759         Some(10) => &mut cfg,
1760         _ => cfg.define("_WANT_FREEBSD11_STAT", None),
1761     };
1762 
1763     let freebsdlast = match freebsd_ver {
1764         Some(12) | Some(13) => true,
1765         _ => false,
1766     };
1767 
1768     headers! { cfg:
1769                 "aio.h",
1770                 "arpa/inet.h",
1771                 "ctype.h",
1772                 "dirent.h",
1773                 "dlfcn.h",
1774                 "elf.h",
1775                 "errno.h",
1776                 "execinfo.h",
1777                 "fcntl.h",
1778                 "glob.h",
1779                 "grp.h",
1780                 "iconv.h",
1781                 "ifaddrs.h",
1782                 "langinfo.h",
1783                 "libutil.h",
1784                 "limits.h",
1785                 "link.h",
1786                 "locale.h",
1787                 "machine/elf.h",
1788                 "machine/reg.h",
1789                 "malloc_np.h",
1790                 "mqueue.h",
1791                 "net/bpf.h",
1792                 "net/if.h",
1793                 "net/if_arp.h",
1794                 "net/if_dl.h",
1795                 "net/route.h",
1796                 "netdb.h",
1797                 "netinet/ip.h",
1798                 "netinet/in.h",
1799                 "netinet/tcp.h",
1800                 "netinet/udp.h",
1801                 "poll.h",
1802                 "pthread.h",
1803                 "pthread_np.h",
1804                 "pwd.h",
1805                 "regex.h",
1806                 "resolv.h",
1807                 "sched.h",
1808                 "semaphore.h",
1809                 "signal.h",
1810                 "spawn.h",
1811                 "stddef.h",
1812                 "stdint.h",
1813                 "stdio.h",
1814                 "stdlib.h",
1815                 "string.h",
1816                 "sys/capsicum.h",
1817                 [freebsdlast]:"sys/auxv.h",
1818                 "sys/cpuset.h",
1819                 [freebsdlast]:"sys/domainset.h",
1820                 "sys/event.h",
1821                 "sys/extattr.h",
1822                 "sys/file.h",
1823                 "sys/ioctl.h",
1824                 "sys/ipc.h",
1825                 "sys/jail.h",
1826                 "sys/mman.h",
1827                 "sys/mount.h",
1828                 "sys/msg.h",
1829                 "sys/procctl.h",
1830                 "sys/procdesc.h",
1831                 "sys/ptrace.h",
1832                 "sys/queue.h",
1833                 "sys/random.h",
1834                 "sys/resource.h",
1835                 "sys/rtprio.h",
1836                 "sys/shm.h",
1837                 "sys/socket.h",
1838                 "sys/stat.h",
1839                 "sys/statvfs.h",
1840                 "sys/sysctl.h",
1841                 "sys/thr.h",
1842                 "sys/time.h",
1843                 "sys/times.h",
1844                 "sys/timex.h",
1845                 "sys/types.h",
1846                 "kvm.h", // must be after "sys/types.h"
1847                 "sys/ucontext.h",
1848                 "sys/uio.h",
1849                 "sys/ktrace.h",
1850                 "sys/un.h",
1851                 "sys/user.h",
1852                 "sys/utsname.h",
1853                 "sys/uuid.h",
1854                 "sys/wait.h",
1855                 "libprocstat.h",
1856                 "syslog.h",
1857                 "termios.h",
1858                 "time.h",
1859                 "ufs/ufs/quota.h",
1860                 "unistd.h",
1861                 "utime.h",
1862                 "utmpx.h",
1863                 "wchar.h",
1864     }
1865 
1866     cfg.type_name(move |ty, is_struct, is_union| {
1867         match ty {
1868             // Just pass all these through, no need for a "struct" prefix
1869             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr"
1870             | "Elf32_Auxinfo" | "Elf64_Auxinfo" => ty.to_string(),
1871 
1872             // FIXME: https://github.com/rust-lang/libc/issues/1273
1873             "sighandler_t" => "sig_t".to_string(),
1874 
1875             t if is_union => format!("union {}", t),
1876 
1877             t if t.ends_with("_t") => t.to_string(),
1878 
1879             // sigval is a struct in Rust, but a union in C:
1880             "sigval" => format!("union sigval"),
1881 
1882             // put `struct` in front of all structs:.
1883             t if is_struct => format!("struct {}", t),
1884 
1885             t => t.to_string(),
1886         }
1887     });
1888 
1889     cfg.field_name(move |struct_, field| {
1890         match field {
1891             // Our stat *_nsec fields normally don't actually exist but are part
1892             // of a timeval struct
1893             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
1894                 s.replace("e_nsec", ".tv_nsec")
1895             }
1896             // Field is named `type` in C but that is a Rust keyword,
1897             // so these fields are translated to `type_` in the bindings.
1898             "type_" if struct_ == "rtprio" => "type".to_string(),
1899             s => s.to_string(),
1900         }
1901     });
1902 
1903     cfg.skip_const(move |name| {
1904         match name {
1905             // These constants were introduced in FreeBSD 13:
1906             "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW"
1907             | "F_SEAL_WRITE"
1908                 if Some(13) > freebsd_ver =>
1909             {
1910                 true
1911             }
1912 
1913             // These constants were introduced in FreeBSD 12:
1914             "SF_USER_READAHEAD"
1915             | "EVFILT_EMPTY"
1916             | "SO_REUSEPORT_LB"
1917             | "IP_ORIGDSTADDR"
1918             | "IP_RECVORIGDSTADDR"
1919             | "IPV6_ORIGDSTADDR"
1920             | "IPV6_RECVORIGDSTADDR"
1921             | "NI_NUMERICSCOPE"
1922             | "SO_DOMAIN"
1923                 if Some(11) == freebsd_ver =>
1924             {
1925                 true
1926             }
1927 
1928             // These constants were introduced in FreeBSD 11:
1929             "SF_USER_READAHEAD"
1930             | "SF_NOCACHE"
1931             | "RLIMIT_KQUEUES"
1932             | "RLIMIT_UMTXP"
1933             | "EVFILT_PROCDESC"
1934             | "EVFILT_SENDFILE"
1935             | "EVFILT_EMPTY"
1936             | "SO_REUSEPORT_LB"
1937             | "TCP_CCALGOOPT"
1938             | "TCP_PCAP_OUT"
1939             | "TCP_PCAP_IN"
1940             | "IP_BINDMULTI"
1941             | "IP_ORIGDSTADDR"
1942             | "IP_RECVORIGDSTADDR"
1943             | "IPV6_ORIGDSTADDR"
1944             | "IPV6_RECVORIGDSTADDR"
1945             | "PD_CLOEXEC"
1946             | "PD_ALLOWED_AT_FORK"
1947             | "IP_RSS_LISTEN_BUCKET"
1948             | "NI_NUMERICSCOPE"
1949                 if Some(10) == freebsd_ver =>
1950             {
1951                 true
1952             }
1953 
1954             // FIXME: This constant has a different value in FreeBSD 10:
1955             "RLIM_NLIMITS" if Some(10) == freebsd_ver => true,
1956 
1957             // FIXME: There are deprecated - remove in a couple of releases.
1958             // These constants were removed in FreeBSD 11 (svn r273250) but will
1959             // still be accepted and ignored at runtime.
1960             "MAP_RENAME" | "MAP_NORESERVE" if Some(10) != freebsd_ver => true,
1961 
1962             // FIXME: There are deprecated - remove in a couple of releases.
1963             // These constants were removed in FreeBSD 11 (svn r262489),
1964             // and they've never had any legitimate use outside of the
1965             // base system anyway.
1966             "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "USER_MAXID" => true,
1967 
1968             // This constant was removed in FreeBSD 13 (svn r363622), and never
1969             // had any legitimate use outside of the base system anyway.
1970             "CTL_P1003_1B_MAXID" => true,
1971 
1972             // This was renamed in FreeBSD 12.2 and 13 (r352486).
1973             "CTL_UNSPEC" | "CTL_SYSCTL" => true,
1974 
1975             // These were added in FreeBSD 12.2 and 13 (r352486),
1976             // but they are just names for magic numbers that existed for ages.
1977             "CTL_SYSCTL_DEBUG"
1978             | "CTL_SYSCTL_NAME"
1979             | "CTL_SYSCTL_NEXT"
1980             | "CTL_SYSCTL_NAME2OID"
1981             | "CTL_SYSCTL_OIDFMT"
1982             | "CTL_SYSCTL_OIDDESCR"
1983             | "CTL_SYSCTL_OIDLABEL" => true,
1984 
1985             // This was renamed in FreeBSD 12.2 and 13 (r350749).
1986             "IPPROTO_SEP" | "IPPROTO_DCCP" => true,
1987 
1988             // This was changed to 96(0x60) in FreeBSD 13:
1989             // https://github.com/freebsd/freebsd/
1990             // commit/06b00ceaa914a3907e4e27bad924f44612bae1d7
1991             "MINCORE_SUPER" if Some(13) == freebsd_ver => true,
1992 
1993             // Added in FreeBSD 12.0
1994             "EINTEGRITY" if Some(11) == freebsd_ver => true,
1995 
1996             // This was increased to 97 in FreeBSD 12.2 and 13.
1997             // https://github.com/freebsd/freebsd/
1998             // commit/72a21ba0f62da5e86a1c0b462aeb3f5ff849a1b7
1999             "ELAST" if Some(12) == freebsd_ver => true,
2000 
2001             // Added in FreeBSD 12.0 (r331279)
2002             "GRND_NONBLOCK" | "GRND_RANDOM" if Some(11) == freebsd_ver => true,
2003             // Added in FreeBSD 13.0 (r356667)
2004             "GRND_INSECURE" if Some(13) > freebsd_ver => true,
2005 
2006             // Added in FreeBSD 12.1 (r343964 and r345228)
2007             "PROC_ASLR_CTL" | "PROC_ASLR_STATUS" | "PROC_PROCCTL_MD_MIN"
2008                 if Some(11) == freebsd_ver =>
2009             {
2010                 true
2011             }
2012 
2013             // Added in FreeBSD 13.0 (r349609)
2014             "PROC_PROTMAX_CTL" | "PROC_PROTMAX_STATUS" if Some(13) > freebsd_ver => true,
2015 
2016             // Added in in FreeBSD 13.0 (r367776 and r367287)
2017             "SCM_CREDS2" | "LOCAL_CREDS_PERSISTENT" if Some(13) > freebsd_ver => true,
2018 
2019             _ => false,
2020         }
2021     });
2022 
2023     cfg.skip_type(move |ty| {
2024         match ty {
2025             // the struct "__kvm" is quite tricky to bind so since we only use a pointer to it
2026             // for now, it doesn't matter too much...
2027             "kvm_t" => true,
2028 
2029             _ => false,
2030         }
2031     });
2032 
2033     cfg.skip_struct(move |ty| {
2034         if ty.starts_with("__c_anonymous_") {
2035             return true;
2036         }
2037         match ty {
2038             // `mmsghdr` is not available in FreeBSD 10
2039             "mmsghdr" if Some(10) == freebsd_ver => true,
2040 
2041             // `max_align_t` is not available in FreeBSD 10
2042             "max_align_t" if Some(10) == freebsd_ver => true,
2043 
2044             // `procstat` is a private struct
2045             "procstat" => true,
2046 
2047             _ => false,
2048         }
2049     });
2050 
2051     cfg.skip_fn(move |name| {
2052         // skip those that are manually verified
2053         match name {
2054             // FIXME: https://github.com/rust-lang/libc/issues/1272
2055             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
2056 
2057             // These functions were added in FreeBSD 11:
2058             "fdatasync" | "mq_getfd_np" | "sendmmsg" | "recvmmsg" if Some(10) == freebsd_ver => {
2059                 true
2060             }
2061 
2062             // This function changed its return type from `int` in FreeBSD10 to
2063             // `ssize_t` in FreeBSD11:
2064             "aio_waitcomplete" if Some(10) == freebsd_ver => true,
2065 
2066             // The `uname` function in the `utsname.h` FreeBSD header is a C
2067             // inline function (has no symbol) that calls the `__xuname` symbol.
2068             // Therefore the function pointer comparison does not make sense for it.
2069             "uname" => true,
2070 
2071             // FIXME: Our API is unsound. The Rust API allows aliasing
2072             // pointers, but the C API requires pointers not to alias.
2073             // We should probably be at least using `&`/`&mut` here, see:
2074             // https://github.com/gnzlbg/ctest/issues/68
2075             "lio_listio" => true,
2076 
2077             _ => false,
2078         }
2079     });
2080 
2081     cfg.skip_signededness(move |c| {
2082         match c {
2083             // FIXME: has a different sign in FreeBSD10
2084             "blksize_t" if Some(10) == freebsd_ver => true,
2085             _ => false,
2086         }
2087     });
2088 
2089     cfg.volatile_item(|i| {
2090         use ctest::VolatileItemKind::*;
2091         match i {
2092             // aio_buf is a volatile void** but since we cannot express that in
2093             // Rust types, we have to explicitly tell the checker about it here:
2094             StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
2095             _ => false,
2096         }
2097     });
2098 
2099     cfg.skip_field(move |struct_, field| {
2100         match (struct_, field) {
2101             // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
2102             // incorrect, see: https://github.com/rust-lang/libc/issues/1359
2103             ("sigaction", "sa_sigaction") => true,
2104 
2105             // FIXME: in FreeBSD10 this field has type `char*` instead of
2106             // `void*`:
2107             ("stack_t", "ss_sp") if Some(10) == freebsd_ver => true,
2108 
2109             // conflicting with `p_type` macro from <resolve.h>.
2110             ("Elf32_Phdr", "p_type") => true,
2111             ("Elf64_Phdr", "p_type") => true,
2112 
2113             // not available until FreeBSD 12, and is an anonymous union there.
2114             ("xucred", "cr_pid__c_anonymous_union") => true,
2115 
2116             // m_owner field is a volatile __lwpid_t
2117             ("umutex", "m_owner") => true,
2118             // c_has_waiters field is a volatile int32_t
2119             ("ucond", "c_has_waiters") => true,
2120             // is PATH_MAX long but tests can't accept multi array as equivalent.
2121             ("kinfo_vmentry", "kve_path") => true,
2122 
2123             // a_un field is a union
2124             ("Elf32_Auxinfo", "a_un") => true,
2125             ("Elf64_Auxinfo", "a_un") => true,
2126 
2127             // FIXME: structs too complicated to bind for now...
2128             ("kinfo_proc", "ki_paddr") => true,
2129             ("kinfo_proc", "ki_addr") => true,
2130             ("kinfo_proc", "ki_tracep") => true,
2131             ("kinfo_proc", "ki_textvp") => true,
2132             ("kinfo_proc", "ki_fd") => true,
2133             ("kinfo_proc", "ki_vmspace") => true,
2134             ("kinfo_proc", "ki_pcb") => true,
2135             ("kinfo_proc", "ki_tdaddr") => true,
2136             ("kinfo_proc", "ki_pd") => true,
2137 
2138             // We ignore this field because we needed to use a hack in order to make rust 1.19
2139             // happy...
2140             ("kinfo_proc", "ki_sparestrings") => true,
2141             _ => false,
2142         }
2143     });
2144 
2145     cfg.generate("../src/lib.rs", "main.rs");
2146 }
2147 
2148 fn test_emscripten(target: &str) {
2149     assert!(target.contains("emscripten"));
2150 
2151     let mut cfg = ctest_cfg();
2152     cfg.define("_GNU_SOURCE", None); // FIXME: ??
2153 
2154     headers! { cfg:
2155                "aio.h",
2156                "ctype.h",
2157                "dirent.h",
2158                "dlfcn.h",
2159                "errno.h",
2160                "fcntl.h",
2161                "glob.h",
2162                "grp.h",
2163                "ifaddrs.h",
2164                "langinfo.h",
2165                "limits.h",
2166                "locale.h",
2167                "malloc.h",
2168                "mntent.h",
2169                "mqueue.h",
2170                "net/ethernet.h",
2171                "net/if.h",
2172                "net/if_arp.h",
2173                "net/route.h",
2174                "netdb.h",
2175                "netinet/in.h",
2176                "netinet/ip.h",
2177                "netinet/tcp.h",
2178                "netinet/udp.h",
2179                "netpacket/packet.h",
2180                "poll.h",
2181                "pthread.h",
2182                "pty.h",
2183                "pwd.h",
2184                "resolv.h",
2185                "sched.h",
2186                "sched.h",
2187                "semaphore.h",
2188                "shadow.h",
2189                "signal.h",
2190                "stddef.h",
2191                "stdint.h",
2192                "stdio.h",
2193                "stdlib.h",
2194                "string.h",
2195                "sys/epoll.h",
2196                "sys/eventfd.h",
2197                "sys/file.h",
2198                "sys/ioctl.h",
2199                "sys/ipc.h",
2200                "sys/mman.h",
2201                "sys/mount.h",
2202                "sys/msg.h",
2203                "sys/personality.h",
2204                "sys/prctl.h",
2205                "sys/ptrace.h",
2206                "sys/quota.h",
2207                "sys/reboot.h",
2208                "sys/resource.h",
2209                "sys/sem.h",
2210                "sys/sendfile.h",
2211                "sys/shm.h",
2212                "sys/signalfd.h",
2213                "sys/socket.h",
2214                "sys/stat.h",
2215                "sys/statvfs.h",
2216                "sys/swap.h",
2217                "sys/syscall.h",
2218                "sys/sysctl.h",
2219                "sys/sysinfo.h",
2220                "sys/time.h",
2221                "sys/timerfd.h",
2222                "sys/times.h",
2223                "sys/types.h",
2224                "sys/uio.h",
2225                "sys/un.h",
2226                "sys/user.h",
2227                "sys/utsname.h",
2228                "sys/vfs.h",
2229                "sys/wait.h",
2230                "sys/xattr.h",
2231                "syslog.h",
2232                "termios.h",
2233                "time.h",
2234                "ucontext.h",
2235                "unistd.h",
2236                "utime.h",
2237                "utmp.h",
2238                "utmpx.h",
2239                "wchar.h",
2240     }
2241 
2242     cfg.type_name(move |ty, is_struct, is_union| {
2243         match ty {
2244             // Just pass all these through, no need for a "struct" prefix
2245             "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(),
2246 
2247             t if is_union => format!("union {}", t),
2248 
2249             t if t.ends_with("_t") => t.to_string(),
2250 
2251             // put `struct` in front of all structs:.
2252             t if is_struct => format!("struct {}", t),
2253 
2254             t => t.to_string(),
2255         }
2256     });
2257 
2258     cfg.field_name(move |struct_, field| {
2259         match field {
2260             // Our stat *_nsec fields normally don't actually exist but are part
2261             // of a timeval struct
2262             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
2263                 s.replace("e_nsec", ".tv_nsec")
2264             }
2265             // FIXME: appears that `epoll_event.data` is an union
2266             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
2267             s => s.to_string(),
2268         }
2269     });
2270 
2271     cfg.skip_type(move |ty| {
2272         match ty {
2273             // sighandler_t is crazy across platforms
2274             // FIXME: is this necessary?
2275             "sighandler_t" => true,
2276 
2277             _ => false,
2278         }
2279     });
2280 
2281     cfg.skip_struct(move |ty| {
2282         match ty {
2283             // This is actually a union, not a struct
2284             // FIXME: is this necessary?
2285             "sigval" => true,
2286 
2287             // FIXME: It was removed in
2288             // emscripten-core/emscripten@953e414
2289             "pthread_mutexattr_t" => true,
2290 
2291             // FIXME: Investigate why the test fails.
2292             // Skip for now to unblock CI.
2293             "pthread_condattr_t" => true,
2294 
2295             _ => false,
2296         }
2297     });
2298 
2299     cfg.skip_fn(move |name| {
2300         match name {
2301             // FIXME: https://github.com/rust-lang/libc/issues/1272
2302             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
2303 
2304             // FIXME: Investigate why CI is missing it.
2305             "clearenv" => true,
2306 
2307             _ => false,
2308         }
2309     });
2310 
2311     cfg.skip_const(move |name| {
2312         match name {
2313             // FIXME: deprecated - SIGNUNUSED was removed in glibc 2.26
2314             // users should use SIGSYS instead
2315             "SIGUNUSED" => true,
2316 
2317             // FIXME: emscripten uses different constants to constructs these
2318             n if n.contains("__SIZEOF_PTHREAD") => true,
2319 
2320             // FIXME: `SYS_gettid` was removed in
2321             // emscripten-core/emscripten@6d6474e
2322             "SYS_gettid" => true,
2323 
2324             _ => false,
2325         }
2326     });
2327 
2328     cfg.skip_field_type(move |struct_, field| {
2329         // This is a weird union, don't check the type.
2330         // FIXME: is this necessary?
2331         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
2332         // sighandler_t type is super weird
2333         // FIXME: is this necessary?
2334         (struct_ == "sigaction" && field == "sa_sigaction") ||
2335         // sigval is actually a union, but we pretend it's a struct
2336         // FIXME: is this necessary?
2337         (struct_ == "sigevent" && field == "sigev_value") ||
2338         // aio_buf is "volatile void*" and Rust doesn't understand volatile
2339         // FIXME: is this necessary?
2340         (struct_ == "aiocb" && field == "aio_buf")
2341     });
2342 
2343     cfg.skip_field(move |struct_, field| {
2344         // this is actually a union on linux, so we can't represent it well and
2345         // just insert some padding.
2346         // FIXME: is this necessary?
2347         (struct_ == "siginfo_t" && field == "_pad") ||
2348         // musl names this __dummy1 but it's still there
2349         // FIXME: is this necessary?
2350         (struct_ == "glob_t" && field == "gl_flags") ||
2351         // musl seems to define this as an *anonymous* bitfield
2352         // FIXME: is this necessary?
2353         (struct_ == "statvfs" && field == "__f_unused") ||
2354         // sigev_notify_thread_id is actually part of a sigev_un union
2355         (struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
2356         // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet.
2357         (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" ||
2358                                            field == "_pad2" ||
2359                                            field == "ssi_syscall" ||
2360                                            field == "ssi_call_addr" ||
2361                                            field == "ssi_arch"))
2362     });
2363 
2364     // FIXME: test linux like
2365     cfg.generate("../src/lib.rs", "main.rs");
2366 }
2367 
2368 fn test_vxworks(target: &str) {
2369     assert!(target.contains("vxworks"));
2370 
2371     let mut cfg = ctest::TestGenerator::new();
2372     headers! { cfg:
2373                "vxWorks.h",
2374                "yvals.h",
2375                "nfs/nfsCommon.h",
2376                "rtpLibCommon.h",
2377                "randomNumGen.h",
2378                "taskLib.h",
2379                "sysLib.h",
2380                "ioLib.h",
2381                "inetLib.h",
2382                "socket.h",
2383                "errnoLib.h",
2384                "ctype.h",
2385                "dirent.h",
2386                "dlfcn.h",
2387                "elf.h",
2388                "fcntl.h",
2389                "grp.h",
2390                "sys/poll.h",
2391                "ifaddrs.h",
2392                "langinfo.h",
2393                "limits.h",
2394                "link.h",
2395                "locale.h",
2396                "sys/stat.h",
2397                "netdb.h",
2398                "pthread.h",
2399                "pwd.h",
2400                "sched.h",
2401                "semaphore.h",
2402                "signal.h",
2403                "stddef.h",
2404                "stdint.h",
2405                "stdio.h",
2406                "stdlib.h",
2407                "string.h",
2408                "sys/file.h",
2409                "sys/ioctl.h",
2410                "sys/socket.h",
2411                "sys/time.h",
2412                "sys/times.h",
2413                "sys/types.h",
2414                "sys/uio.h",
2415                "sys/un.h",
2416                "sys/utsname.h",
2417                "sys/wait.h",
2418                "netinet/tcp.h",
2419                "syslog.h",
2420                "termios.h",
2421                "time.h",
2422                "ucontext.h",
2423                "unistd.h",
2424                "utime.h",
2425                "wchar.h",
2426                "errno.h",
2427                "sys/mman.h",
2428                "pathLib.h",
2429                "mqueue.h",
2430     }
2431     // FIXME
2432     cfg.skip_const(move |name| match name {
2433         // sighandler_t weirdness
2434         "SIG_DFL" | "SIG_ERR" | "SIG_IGN"
2435         // This is not defined in vxWorks
2436         | "RTLD_DEFAULT"   => true,
2437         _ => false,
2438     });
2439     // FIXME
2440     cfg.skip_type(move |ty| match ty {
2441         "stat64" | "sighandler_t" | "off64_t" => true,
2442         _ => false,
2443     });
2444 
2445     cfg.skip_field_type(move |struct_, field| match (struct_, field) {
2446         ("siginfo_t", "si_value") | ("stat", "st_size") | ("sigaction", "sa_u") => true,
2447         _ => false,
2448     });
2449 
2450     cfg.skip_roundtrip(move |s| match s {
2451         _ => false,
2452     });
2453 
2454     cfg.type_name(move |ty, is_struct, is_union| match ty {
2455         "DIR" | "FILE" | "Dl_info" | "RTP_DESC" => ty.to_string(),
2456         t if is_union => format!("union {}", t),
2457         t if t.ends_with("_t") => t.to_string(),
2458         t if is_struct => format!("struct {}", t),
2459         t => t.to_string(),
2460     });
2461 
2462     // FIXME
2463     cfg.skip_fn(move |name| match name {
2464         // sigval
2465         "sigqueue" | "_sigqueue"
2466         // sighandler_t
2467         | "signal"
2468         // not used in static linking by default
2469         | "dlerror" => true,
2470         _ => false,
2471     });
2472 
2473     cfg.generate("../src/lib.rs", "main.rs");
2474 }
2475 
2476 fn test_linux(target: &str) {
2477     assert!(target.contains("linux"));
2478 
2479     // target_env
2480     let gnu = target.contains("gnu");
2481     let musl = target.contains("musl");
2482     let uclibc = target.contains("uclibc");
2483 
2484     match (gnu, musl, uclibc) {
2485         (true, false, false) => (),
2486         (false, true, false) => (),
2487         (false, false, true) => (),
2488         (_, _, _) => panic!(
2489             "linux target lib is gnu: {}, musl: {}, uclibc: {}",
2490             gnu, musl, uclibc
2491         ),
2492     }
2493 
2494     let arm = target.contains("arm");
2495     let i686 = target.contains("i686");
2496     let mips = target.contains("mips");
2497     let mips32 = mips && !target.contains("64");
2498     let mips64 = mips && target.contains("64");
2499     let ppc64 = target.contains("powerpc64");
2500     let s390x = target.contains("s390x");
2501     let sparc64 = target.contains("sparc64");
2502     let x32 = target.contains("x32");
2503     let x86_32 = target.contains("i686");
2504     let x86_64 = target.contains("x86_64");
2505     let aarch64_musl = target.contains("aarch64") && musl;
2506     let gnuabihf = target.contains("gnueabihf");
2507     let x86_64_gnux32 = target.contains("gnux32") && x86_64;
2508     let riscv64 = target.contains("riscv64");
2509     let uclibc = target.contains("uclibc");
2510 
2511     let mut cfg = ctest_cfg();
2512     cfg.define("_GNU_SOURCE", None);
2513     // This macro re-deifnes fscanf,scanf,sscanf to link to the symbols that are
2514     // deprecated since glibc >= 2.29. This allows Rust binaries to link against
2515     // glibc versions older than 2.29.
2516     cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None);
2517 
2518     headers! { cfg:
2519                "ctype.h",
2520                "dirent.h",
2521                "dlfcn.h",
2522                "elf.h",
2523                "fcntl.h",
2524                "glob.h",
2525                "grp.h",
2526                "iconv.h",
2527                "ifaddrs.h",
2528                "langinfo.h",
2529                "limits.h",
2530                "link.h",
2531                "locale.h",
2532                "malloc.h",
2533                "mntent.h",
2534                "mqueue.h",
2535                "net/ethernet.h",
2536                "net/if.h",
2537                "net/if_arp.h",
2538                "net/route.h",
2539                "netdb.h",
2540                "netinet/in.h",
2541                "netinet/ip.h",
2542                "netinet/tcp.h",
2543                "netinet/udp.h",
2544                "netpacket/packet.h",
2545                "poll.h",
2546                "pthread.h",
2547                "pty.h",
2548                "pwd.h",
2549                "regex.h",
2550                "resolv.h",
2551                "sched.h",
2552                "semaphore.h",
2553                "shadow.h",
2554                "signal.h",
2555                "spawn.h",
2556                "stddef.h",
2557                "stdint.h",
2558                "stdio.h",
2559                "stdlib.h",
2560                "string.h",
2561                "sys/epoll.h",
2562                "sys/eventfd.h",
2563                "sys/file.h",
2564                "sys/fsuid.h",
2565                "sys/inotify.h",
2566                "sys/ioctl.h",
2567                "sys/ipc.h",
2568                "sys/mman.h",
2569                "sys/mount.h",
2570                "sys/msg.h",
2571                "sys/personality.h",
2572                "sys/prctl.h",
2573                "sys/ptrace.h",
2574                "sys/quota.h",
2575                "sys/random.h",
2576                "sys/reboot.h",
2577                "sys/resource.h",
2578                "sys/sem.h",
2579                "sys/sendfile.h",
2580                "sys/shm.h",
2581                "sys/signalfd.h",
2582                "sys/socket.h",
2583                "sys/stat.h",
2584                "sys/statvfs.h",
2585                "sys/swap.h",
2586                "sys/syscall.h",
2587                "sys/time.h",
2588                "sys/timerfd.h",
2589                "sys/times.h",
2590                "sys/timex.h",
2591                "sys/types.h",
2592                "sys/uio.h",
2593                "sys/un.h",
2594                "sys/user.h",
2595                "sys/utsname.h",
2596                "sys/vfs.h",
2597                "sys/wait.h",
2598                "syslog.h",
2599                "termios.h",
2600                "time.h",
2601                "ucontext.h",
2602                "unistd.h",
2603                "utime.h",
2604                "utmp.h",
2605                "utmpx.h",
2606                "wchar.h",
2607                "errno.h",
2608                // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit
2609                // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162
2610                // Also unavailable on gnuabihf with glibc 2.30.
2611                // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6b33f373c7b9199e00ba5fbafd94ac9bfb4337b1
2612                [(x86_64 || x86_32 || arm) && !gnuabihf]: "sys/io.h",
2613                // `sys/reg.h` is only available on x86 and x86_64
2614                [x86_64 || x86_32]: "sys/reg.h",
2615                // sysctl system call is deprecated and not available on musl
2616                // It is also unsupported in x32, deprecated since glibc 2.30:
2617                [!(x32 || musl || gnu)]: "sys/sysctl.h",
2618                // <execinfo.h> is not supported by musl:
2619                // https://www.openwall.com/lists/musl/2015/04/09/3
2620                // <execinfo.h> is not present on uclibc.
2621                [!(musl || uclibc)]: "execinfo.h",
2622     }
2623 
2624     // Include linux headers at the end:
2625     headers! {
2626         cfg:
2627         "asm/mman.h",
2628         "linux/can.h",
2629         "linux/can/raw.h",
2630         "linux/dccp.h",
2631         "linux/errqueue.h",
2632         "linux/falloc.h",
2633         "linux/fs.h",
2634         "linux/futex.h",
2635         "linux/genetlink.h",
2636         "linux/if.h",
2637         "linux/if_addr.h",
2638         "linux/if_alg.h",
2639         "linux/if_ether.h",
2640         "linux/if_tun.h",
2641         "linux/input.h",
2642         "linux/keyctl.h",
2643         "linux/magic.h",
2644         "linux/memfd.h",
2645         "linux/mman.h",
2646         "linux/module.h",
2647         "linux/net_tstamp.h",
2648         "linux/netfilter/nfnetlink.h",
2649         "linux/netfilter/nfnetlink_log.h",
2650         "linux/netfilter/nfnetlink_queue.h",
2651         "linux/netfilter/nf_tables.h",
2652         "linux/netfilter_ipv4.h",
2653         "linux/netfilter_ipv6.h",
2654         "linux/netfilter_ipv6/ip6_tables.h",
2655         "linux/netlink.h",
2656         "linux/quota.h",
2657         "linux/random.h",
2658         "linux/reboot.h",
2659         "linux/rtnetlink.h",
2660         "linux/sched.h",
2661         "linux/seccomp.h",
2662         "linux/sockios.h",
2663         "linux/uinput.h",
2664         "linux/vm_sockets.h",
2665         "linux/wait.h",
2666         "sys/fanotify.h",
2667         // <sys/auxv.h> is not present on uclibc
2668         [!uclibc]: "sys/auxv.h",
2669     }
2670 
2671     // note: aio.h must be included before sys/mount.h
2672     headers! {
2673         cfg:
2674         "sys/xattr.h",
2675         "sys/sysinfo.h",
2676         // AIO is not supported by uclibc:
2677         [!uclibc]: "aio.h",
2678     }
2679 
2680     cfg.type_name(move |ty, is_struct, is_union| {
2681         match ty {
2682             // Just pass all these through, no need for a "struct" prefix
2683             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr"
2684             | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr"
2685             | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(),
2686 
2687             t if is_union => format!("union {}", t),
2688 
2689             t if t.ends_with("_t") => t.to_string(),
2690 
2691             // In MUSL `flock64` is a typedef to `flock`.
2692             "flock64" if musl => format!("struct {}", ty),
2693 
2694             // put `struct` in front of all structs:.
2695             t if is_struct => format!("struct {}", t),
2696 
2697             t => t.to_string(),
2698         }
2699     });
2700 
2701     cfg.field_name(move |struct_, field| {
2702         match field {
2703             // Our stat *_nsec fields normally don't actually exist but are part
2704             // of a timeval struct
2705             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
2706                 s.replace("e_nsec", ".tv_nsec")
2707             }
2708             // FIXME: epoll_event.data is actually a union in C, but in Rust
2709             // it is only a u64 because we only expose one field
2710             // http://man7.org/linux/man-pages/man2/epoll_wait.2.html
2711             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
2712             // The following structs have a field called `type` in C,
2713             // but `type` is a Rust keyword, so these fields are translated
2714             // to `type_` in Rust.
2715             "type_"
2716                 if struct_ == "input_event"
2717                     || struct_ == "input_mask"
2718                     || struct_ == "ff_effect" =>
2719             {
2720                 "type".to_string()
2721             }
2722 
2723             s => s.to_string(),
2724         }
2725     });
2726 
2727     cfg.skip_type(move |ty| {
2728         match ty {
2729             // FIXME: `sighandler_t` type is incorrect, see:
2730             // https://github.com/rust-lang/libc/issues/1359
2731             "sighandler_t" => true,
2732 
2733             // These cannot be tested when "resolv.h" is included and are tested
2734             // in the `linux_elf.rs` file.
2735             "Elf64_Phdr" | "Elf32_Phdr" => true,
2736 
2737             // This type is private on Linux. It is implemented as a C `enum`
2738             // (`c_uint`) and this clashes with the type of the `rlimit` APIs
2739             // which expect a `c_int` even though both are ABI compatible.
2740             "__rlimit_resource_t" => true,
2741             // on Linux, this is a volatile int
2742             "pthread_spinlock_t" => true,
2743 
2744             _ => false,
2745         }
2746     });
2747 
2748     cfg.skip_struct(move |ty| {
2749         if ty.starts_with("__c_anonymous_") {
2750             return true;
2751         }
2752         // FIXME: musl CI has old headers
2753         if (musl || sparc64) && ty.starts_with("uinput_") {
2754             return true;
2755         }
2756         match ty {
2757             // These cannot be tested when "resolv.h" is included and are tested
2758             // in the `linux_elf.rs` file.
2759             "Elf64_Phdr" | "Elf32_Phdr" => true,
2760 
2761             // On Linux, the type of `ut_tv` field of `struct utmpx`
2762             // can be an anonymous struct, so an extra struct,
2763             // which is absent in glibc, has to be defined.
2764             "__timeval" => true,
2765 
2766             // FIXME: This is actually a union, not a struct
2767             "sigval" => true,
2768 
2769             // This type is tested in the `linux_termios.rs` file since there
2770             // are header conflicts when including them with all the other
2771             // structs.
2772             "termios2" => true,
2773 
2774             // FIXME: remove once we set minimum supported glibc version.
2775             // ucontext_t added a new field as of glibc 2.28; our struct definition is
2776             // conservative and omits the field, but that means the size doesn't match for newer
2777             // glibcs (see https://github.com/rust-lang/libc/issues/1410)
2778             "ucontext_t" if gnu => true,
2779 
2780             // FIXME: Somehow we cannot include headers correctly in glibc 2.30.
2781             // So let's ignore for now and re-visit later.
2782             // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085
2783             "statx" => true,
2784             "statx_timestamp" => true,
2785 
2786             // On Linux, the type of `ut_exit` field of struct `utmpx`
2787             // can be an anonymous struct, so an extra struct,
2788             // which is absent in musl, has to be defined.
2789             "__exit_status" if musl => true,
2790 
2791             // FIXME: CI's kernel header version is old.
2792             "sockaddr_can" => true,
2793 
2794             // Requires glibc 2.33 or newer.
2795             "mallinfo2" => true,
2796 
2797             _ => false,
2798         }
2799     });
2800 
2801     cfg.skip_const(move |name| {
2802         if !gnu {
2803             // Skip definitions from the kernel on non-glibc Linux targets.
2804             // They're libc-independent, so we only need to check them on one
2805             // libc. We don't want to break CI if musl or another libc doesn't
2806             // have the definitions yet. (We do still want to check them on
2807             // every glibc target, though, as some of them can vary by
2808             // architecture.)
2809             //
2810             // This is not an exhaustive list of kernel constants, just a list
2811             // of prefixes of all those that have appeared here or that get
2812             // updated regularly and seem likely to cause breakage.
2813             if name.starts_with("AF_")
2814                 || name.starts_with("ARPHRD_")
2815                 || name.starts_with("EPOLL")
2816                 || name.starts_with("F_")
2817                 || name.starts_with("FALLOC_FL_")
2818                 || name.starts_with("IFLA_")
2819                 || name.starts_with("MS_")
2820                 || name.starts_with("MSG_")
2821                 || name.starts_with("P_")
2822                 || name.starts_with("PF_")
2823                 || name.starts_with("RLIMIT_")
2824                 || name.starts_with("SOL_")
2825                 || name.starts_with("STATX_")
2826                 || name.starts_with("SW_")
2827                 || name.starts_with("SYS_")
2828                 || name.starts_with("TCP_")
2829                 || name.starts_with("UINPUT_")
2830                 || name.starts_with("VMADDR_")
2831             {
2832                 return true;
2833             }
2834         }
2835         match name {
2836             // These constants are not available if gnu headers have been included
2837             // and can therefore not be tested here
2838             //
2839             // The IPV6 constants are tested in the `linux_ipv6.rs` tests:
2840             | "IPV6_FLOWINFO"
2841             | "IPV6_FLOWLABEL_MGR"
2842             | "IPV6_FLOWINFO_SEND"
2843             | "IPV6_FLOWINFO_FLOWLABEL"
2844             | "IPV6_FLOWINFO_PRIORITY"
2845             // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests:
2846             | "F_CANCELLK"
2847             | "F_ADD_SEALS"
2848             | "F_GET_SEALS"
2849             | "F_SEAL_SEAL"
2850             | "F_SEAL_SHRINK"
2851             | "F_SEAL_GROW"
2852             | "F_SEAL_WRITE" => true,
2853             // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests
2854             // because including `linux/if_arp.h` causes some conflicts:
2855             "ARPHRD_CAN" => true,
2856 
2857             // Require Linux kernel 5.1:
2858             "F_SEAL_FUTURE_WRITE" => true,
2859 
2860             // FIXME: deprecated: not available in any header
2861             // See: https://github.com/rust-lang/libc/issues/1356
2862             "ENOATTR" => true,
2863 
2864             // FIXME: SIGUNUSED was removed in glibc 2.26
2865             // Users should use SIGSYS instead.
2866             "SIGUNUSED" => true,
2867 
2868             // FIXME: conflicts with glibc headers and is tested in
2869             // `linux_termios.rs` below:
2870             "BOTHER" => true,
2871 
2872             // FIXME: on musl the pthread types are defined a little differently
2873             // - these constants are used by the glibc implementation.
2874             n if musl && n.contains("__SIZEOF_PTHREAD") => true,
2875 
2876             // FIXME: It was extended to 4096 since glibc 2.31 (Linux 5.4).
2877             // We should do so after a while.
2878             "SOMAXCONN" if gnu => true,
2879 
2880             // deprecated: not available from Linux kernel 5.6:
2881             "VMADDR_CID_RESERVED" => true,
2882 
2883             // Require Linux kernel 5.6:
2884             "VMADDR_CID_LOCAL" => true,
2885 
2886             // Requires Linux kernel 5.7:
2887             "MREMAP_DONTUNMAP" => true,
2888 
2889             // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP:
2890             | "IPPROTO_MAX"
2891             | "IPPROTO_MPTCP" => true,
2892 
2893             // FIXME: Not currently available in headers
2894             "P_PIDFD" if mips => true,
2895             "SYS_pidfd_open" if mips => true,
2896 
2897             // FIXME: Not currently available in headers on MIPS
2898             // Not yet implemented on sparc64
2899             "SYS_clone3" if mips | sparc64 => true,
2900 
2901             // FIXME: these syscalls were added in Linux 5.9 or later
2902             // and are currently not included in the glibc headers.
2903             | "SYS_close_range"
2904             | "SYS_openat2"
2905             | "SYS_pidfd_getfd"
2906             | "SYS_faccessat2"
2907             | "SYS_process_madvise"
2908             | "SYS_epoll_pwait2"
2909             | "SYS_mount_setattr" => true,
2910 
2911             // Requires more recent kernel headers:
2912             | "IFLA_PROP_LIST"
2913             | "IFLA_ALT_IFNAME"
2914             | "IFLA_PERM_ADDRESS"
2915             | "IFLA_PROTO_DOWN_REASON" => true,
2916 
2917             // FIXME: They require recent kernel header:
2918             | "CAN_J1939"
2919             | "CAN_RAW_FILTER_MAX"
2920             | "CAN_NPROTO" => true,
2921 
2922             // FIXME: Requires recent kernel headers (5.8):
2923             "STATX_MNT_ID" => true,
2924 
2925             // FIXME: requires more recent kernel headers on CI
2926             | "UINPUT_VERSION"
2927             | "SW_MAX"
2928             | "SW_CNT"
2929                 if mips || ppc64 || riscv64 || sparc64 => true,
2930 
2931             // FIXME: Requires more recent kernel headers (5.9 / 5.11):
2932             | "CLOSE_RANGE_UNSHARE"
2933             | "CLOSE_RANGE_CLOEXEC" => true,
2934 
2935             // FIXME: Not currently available in headers on ARM, MIPS and musl.
2936             "NETLINK_GET_STRICT_CHK" if arm || mips || musl => true,
2937 
2938             // kernel constants not available in uclibc 1.0.34
2939             | "ADDR_COMPAT_LAYOUT"
2940             | "ADDR_LIMIT_3GB"
2941             | "ADDR_NO_RANDOMIZE"
2942             | "CLONE_NEWCGROUP"
2943             | "EXTPROC"
2944             | "FAN_MARK_FILESYSTEM"
2945             | "FAN_MARK_INODE"
2946             | "IPPROTO_BEETPH"
2947             | "IPPROTO_MPLS"
2948             | "IPV6_HDRINCL"
2949             | "IPV6_MULTICAST_ALL"
2950             | "IPV6_PMTUDISC_INTERFACE"
2951             | "IPV6_PMTUDISC_OMIT"
2952             | "IPV6_ROUTER_ALERT_ISOLATE"
2953             | "O_TMPFILE"
2954             | "PACKET_MR_UNICAST"
2955             | "PTRACE_EVENT_STOP"
2956             | "PTRACE_O_EXITKILL"
2957             | "PTRACE_O_SUSPEND_SECCOMP"
2958             | "PTRACE_PEEKSIGINFO"
2959             | "READ_IMPLIES_EXEC"
2960             | "RUSAGE_THREAD"
2961             | "SHM_EXEC"
2962             | "UDP_GRO"
2963             | "UDP_SEGMENT"
2964                 if uclibc => true,
2965 
2966             _ => false,
2967         }
2968     });
2969 
2970     cfg.skip_fn(move |name| {
2971         // skip those that are manually verified
2972         match name {
2973             // FIXME: https://github.com/rust-lang/libc/issues/1272
2974             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
2975 
2976             // There are two versions of the sterror_r function, see
2977             //
2978             // https://linux.die.net/man/3/strerror_r
2979             //
2980             // An XSI-compliant version provided if:
2981             //
2982             // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
2983             //  && ! _GNU_SOURCE
2984             //
2985             // and a GNU specific version provided if _GNU_SOURCE is defined.
2986             //
2987             // libc provides bindings for the XSI-compliant version, which is
2988             // preferred for portable applications.
2989             //
2990             // We skip the test here since here _GNU_SOURCE is defined, and
2991             // test the XSI version below.
2992             "strerror_r" => true,
2993 
2994             // FIXME: Our API is unsound. The Rust API allows aliasing
2995             // pointers, but the C API requires pointers not to alias.
2996             // We should probably be at least using `&`/`&mut` here, see:
2997             // https://github.com/gnzlbg/ctest/issues/68
2998             "lio_listio" if musl => true,
2999 
3000             // FIXME: the glibc version used by the Sparc64 build jobs
3001             // which use Debian 10.0 is too old.
3002             "statx" if sparc64 => true,
3003 
3004             // FIXME: Deprecated since glibc 2.30. Remove fn once upstream does.
3005             "sysctl" if gnu => true,
3006 
3007             // FIXME: It now takes c_void instead of timezone since glibc 2.31.
3008             "gettimeofday" if gnu => true,
3009 
3010             // These are all implemented as static inline functions in uclibc, so
3011             // they cannot be linked against.
3012             // If implementations are required, they might need to be implemented
3013             // in this crate.
3014             "posix_spawnattr_init" if uclibc => true,
3015             "posix_spawnattr_destroy" if uclibc => true,
3016             "posix_spawnattr_getsigdefault" if uclibc => true,
3017             "posix_spawnattr_setsigdefault" if uclibc => true,
3018             "posix_spawnattr_getsigmask" if uclibc => true,
3019             "posix_spawnattr_setsigmask" if uclibc => true,
3020             "posix_spawnattr_getflags" if uclibc => true,
3021             "posix_spawnattr_setflags" if uclibc => true,
3022             "posix_spawnattr_getpgroup" if uclibc => true,
3023             "posix_spawnattr_setpgroup" if uclibc => true,
3024             "posix_spawnattr_getschedpolicy" if uclibc => true,
3025             "posix_spawnattr_setschedpolicy" if uclibc => true,
3026             "posix_spawnattr_getschedparam" if uclibc => true,
3027             "posix_spawnattr_setschedparam" if uclibc => true,
3028             "posix_spawn_file_actions_init" if uclibc => true,
3029             "posix_spawn_file_actions_destroy" if uclibc => true,
3030 
3031             // uclibc defines the flags type as a uint, but dependent crates
3032             // assume it's a int instead.
3033             "getnameinfo" if uclibc => true,
3034 
3035             // FIXME: This needs musl 1.2.2 or later.
3036             "gettid" if musl => true,
3037 
3038             // Needs glibc 2.33 or later.
3039             "mallinfo2" => true,
3040 
3041             "reallocarray" if musl => true,
3042 
3043             // Not defined in uclibc as of 1.0.34
3044             "gettid" if uclibc => true,
3045 
3046             _ => false,
3047         }
3048     });
3049 
3050     cfg.skip_field_type(move |struct_, field| {
3051         // This is a weird union, don't check the type.
3052         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
3053         // sighandler_t type is super weird
3054         (struct_ == "sigaction" && field == "sa_sigaction") ||
3055         // __timeval type is a patch which doesn't exist in glibc
3056         (struct_ == "utmpx" && field == "ut_tv") ||
3057         // sigval is actually a union, but we pretend it's a struct
3058         (struct_ == "sigevent" && field == "sigev_value") ||
3059         // this one is an anonymous union
3060         (struct_ == "ff_effect" && field == "u") ||
3061         // `__exit_status` type is a patch which is absent in musl
3062         (struct_ == "utmpx" && field == "ut_exit" && musl) ||
3063         // `can_addr` is an anonymous union
3064         (struct_ == "sockaddr_can" && field == "can_addr")
3065     });
3066 
3067     cfg.volatile_item(|i| {
3068         use ctest::VolatileItemKind::*;
3069         match i {
3070             // aio_buf is a volatile void** but since we cannot express that in
3071             // Rust types, we have to explicitly tell the checker about it here:
3072             StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
3073             _ => false,
3074         }
3075     });
3076 
3077     cfg.skip_field(move |struct_, field| {
3078         // this is actually a union on linux, so we can't represent it well and
3079         // just insert some padding.
3080         (struct_ == "siginfo_t" && field == "_pad") ||
3081         // musl names this __dummy1 but it's still there
3082         (musl && struct_ == "glob_t" && field == "gl_flags") ||
3083         // musl seems to define this as an *anonymous* bitfield
3084         (musl && struct_ == "statvfs" && field == "__f_unused") ||
3085         // sigev_notify_thread_id is actually part of a sigev_un union
3086         (struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
3087         // signalfd had SIGSYS fields added in Linux 4.18, but no libc release
3088         // has them yet.
3089         (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" ||
3090                                            field == "_pad2" ||
3091                                            field == "ssi_syscall" ||
3092                                            field == "ssi_call_addr" ||
3093                                            field == "ssi_arch")) ||
3094         // FIXME: After musl 1.1.24, it have only one field `sched_priority`,
3095         // while other fields become reserved.
3096         (struct_ == "sched_param" && [
3097             "sched_ss_low_priority",
3098             "sched_ss_repl_period",
3099             "sched_ss_init_budget",
3100             "sched_ss_max_repl",
3101         ].contains(&field) && musl) ||
3102         // FIXME: After musl 1.1.24, the type becomes `int` instead of `unsigned short`.
3103         (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) ||
3104         // glibc uses unnamed fields here and Rust doesn't support that yet
3105         (struct_ == "timex" && field.starts_with("__unused")) ||
3106         // FIXME: It now takes mode_t since glibc 2.31 on some targets.
3107         (struct_ == "ipc_perm" && field == "mode"
3108             && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32)
3109         )
3110     });
3111 
3112     cfg.skip_roundtrip(move |s| match s {
3113         // FIXME:
3114         "utsname" if mips32 || mips64 => true,
3115         // FIXME:
3116         "mcontext_t" if s390x => true,
3117         // FIXME: This is actually a union.
3118         "fpreg_t" if s390x => true,
3119 
3120         "sockaddr_un" | "sembuf" | "ff_constant_effect" if mips32 && (gnu || musl) => true,
3121         "ipv6_mreq"
3122         | "ip_mreq_source"
3123         | "sockaddr_in6"
3124         | "sockaddr_ll"
3125         | "in_pktinfo"
3126         | "arpreq"
3127         | "arpreq_old"
3128         | "sockaddr_un"
3129         | "ff_constant_effect"
3130         | "ff_ramp_effect"
3131         | "ff_condition_effect"
3132         | "Elf32_Ehdr"
3133         | "Elf32_Chdr"
3134         | "ucred"
3135         | "in6_pktinfo"
3136         | "sockaddr_nl"
3137         | "termios"
3138         | "nlmsgerr"
3139             if (mips64 || sparc64) && gnu =>
3140         {
3141             true
3142         }
3143 
3144         // FIXME: the call ABI of max_align_t is incorrect on these platforms:
3145         "max_align_t" if i686 || mips64 || ppc64 => true,
3146 
3147         _ => false,
3148     });
3149 
3150     cfg.generate("../src/lib.rs", "main.rs");
3151 
3152     test_linux_like_apis(target);
3153 }
3154 
3155 // This function tests APIs that are incompatible to test when other APIs
3156 // are included (e.g. because including both sets of headers clashes)
3157 fn test_linux_like_apis(target: &str) {
3158     let musl = target.contains("musl");
3159     let linux = target.contains("linux");
3160     let emscripten = target.contains("emscripten");
3161     let android = target.contains("android");
3162     assert!(linux || android || emscripten);
3163 
3164     if linux || android || emscripten {
3165         // test strerror_r from the `string.h` header
3166         let mut cfg = ctest_cfg();
3167         cfg.skip_type(|_| true).skip_static(|_| true);
3168 
3169         headers! { cfg: "string.h" }
3170         cfg.skip_fn(|f| match f {
3171             "strerror_r" => false,
3172             _ => true,
3173         })
3174         .skip_const(|_| true)
3175         .skip_struct(|_| true);
3176         cfg.generate("../src/lib.rs", "linux_strerror_r.rs");
3177     }
3178 
3179     if linux || android || emscripten {
3180         // test fcntl - see:
3181         // http://man7.org/linux/man-pages/man2/fcntl.2.html
3182         let mut cfg = ctest_cfg();
3183 
3184         if musl {
3185             cfg.header("fcntl.h");
3186         } else {
3187             cfg.header("linux/fcntl.h");
3188         }
3189 
3190         cfg.skip_type(|_| true)
3191             .skip_static(|_| true)
3192             .skip_struct(|_| true)
3193             .skip_fn(|_| true)
3194             .skip_const(move |name| match name {
3195                 // test fcntl constants:
3196                 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK"
3197                 | "F_SEAL_GROW" | "F_SEAL_WRITE" => false,
3198                 _ => true,
3199             })
3200             .type_name(move |ty, is_struct, is_union| match ty {
3201                 t if is_struct => format!("struct {}", t),
3202                 t if is_union => format!("union {}", t),
3203                 t => t.to_string(),
3204             });
3205 
3206         cfg.generate("../src/lib.rs", "linux_fcntl.rs");
3207     }
3208 
3209     if linux || android {
3210         // test termios
3211         let mut cfg = ctest_cfg();
3212         cfg.header("asm/termbits.h");
3213         cfg.skip_type(|_| true)
3214             .skip_static(|_| true)
3215             .skip_fn(|_| true)
3216             .skip_const(|c| c != "BOTHER")
3217             .skip_struct(|s| s != "termios2")
3218             .type_name(move |ty, is_struct, is_union| match ty {
3219                 t if is_struct => format!("struct {}", t),
3220                 t if is_union => format!("union {}", t),
3221                 t => t.to_string(),
3222             });
3223         cfg.generate("../src/lib.rs", "linux_termios.rs");
3224     }
3225 
3226     if linux || android {
3227         // test IPV6_ constants:
3228         let mut cfg = ctest_cfg();
3229         headers! {
3230             cfg:
3231             "linux/in6.h"
3232         }
3233         cfg.skip_type(|_| true)
3234             .skip_static(|_| true)
3235             .skip_fn(|_| true)
3236             .skip_const(|_| true)
3237             .skip_struct(|_| true)
3238             .skip_const(move |name| match name {
3239                 "IPV6_FLOWINFO"
3240                 | "IPV6_FLOWLABEL_MGR"
3241                 | "IPV6_FLOWINFO_SEND"
3242                 | "IPV6_FLOWINFO_FLOWLABEL"
3243                 | "IPV6_FLOWINFO_PRIORITY" => false,
3244                 _ => true,
3245             })
3246             .type_name(move |ty, is_struct, is_union| match ty {
3247                 t if is_struct => format!("struct {}", t),
3248                 t if is_union => format!("union {}", t),
3249                 t => t.to_string(),
3250             });
3251         cfg.generate("../src/lib.rs", "linux_ipv6.rs");
3252     }
3253 
3254     if linux || android {
3255         // Test Elf64_Phdr and Elf32_Phdr
3256         // These types have a field called `p_type`, but including
3257         // "resolve.h" defines a `p_type` macro that expands to `__p_type`
3258         // making the tests for these fails when both are included.
3259         let mut cfg = ctest_cfg();
3260         cfg.header("elf.h");
3261         cfg.skip_fn(|_| true)
3262             .skip_static(|_| true)
3263             .skip_const(|_| true)
3264             .type_name(move |ty, _is_struct, _is_union| ty.to_string())
3265             .skip_struct(move |ty| match ty {
3266                 "Elf64_Phdr" | "Elf32_Phdr" => false,
3267                 _ => true,
3268             })
3269             .skip_type(move |ty| match ty {
3270                 "Elf64_Phdr" | "Elf32_Phdr" => false,
3271                 _ => true,
3272             });
3273         cfg.generate("../src/lib.rs", "linux_elf.rs");
3274     }
3275 
3276     if linux || android {
3277         // Test `ARPHRD_CAN`.
3278         let mut cfg = ctest_cfg();
3279         cfg.header("linux/if_arp.h");
3280         cfg.skip_fn(|_| true)
3281             .skip_static(|_| true)
3282             .skip_const(move |name| match name {
3283                 "ARPHRD_CAN" => false,
3284                 _ => true,
3285             })
3286             .skip_struct(|_| true)
3287             .skip_type(|_| true);
3288         cfg.generate("../src/lib.rs", "linux_if_arp.rs");
3289     }
3290 }
3291 
3292 fn which_freebsd() -> Option<i32> {
3293     let output = std::process::Command::new("freebsd-version")
3294         .output()
3295         .ok()?;
3296     if !output.status.success() {
3297         return None;
3298     }
3299 
3300     let stdout = String::from_utf8(output.stdout).ok()?;
3301 
3302     match &stdout {
3303         s if s.starts_with("10") => Some(10),
3304         s if s.starts_with("11") => Some(11),
3305         s if s.starts_with("12") => Some(12),
3306         s if s.starts_with("13") => Some(13),
3307         _ => None,
3308     }
3309 }
3310 
3311 fn test_haiku(target: &str) {
3312     assert!(target.contains("haiku"));
3313 
3314     let mut cfg = ctest_cfg();
3315     cfg.flag("-Wno-deprecated-declarations");
3316     cfg.define("__USE_GNU", Some("1"));
3317 
3318     // POSIX API
3319     headers! { cfg:
3320                "alloca.h",
3321                "arpa/inet.h",
3322                "arpa/nameser.h",
3323                "arpa/nameser_compat.h",
3324                "assert.h",
3325                "bsd_mem.h",
3326                "complex.h",
3327                "ctype.h",
3328                "dirent.h",
3329                "div_t.h",
3330                "dlfcn.h",
3331                "endian.h",
3332                "errno.h",
3333                "fcntl.h",
3334                "fenv.h",
3335                "fnmatch.h",
3336                "fts.h",
3337                "ftw.h",
3338                "getopt.h",
3339                "glob.h",
3340                "grp.h",
3341                "inttypes.h",
3342                "iovec.h",
3343                "langinfo.h",
3344                "libgen.h",
3345                "libio.h",
3346                "limits.h",
3347                "locale.h",
3348                "malloc.h",
3349                "malloc_debug.h",
3350                "math.h",
3351                "memory.h",
3352                "monetary.h",
3353                "net/if.h",
3354                "net/if_dl.h",
3355                "net/if_media.h",
3356                "net/if_tun.h",
3357                "net/if_types.h",
3358                "net/route.h",
3359                "netdb.h",
3360                "netinet/icmp6.h",
3361                "netinet/in.h",
3362                "netinet/ip.h",
3363                "netinet/ip6.h",
3364                "netinet/ip_icmp.h",
3365                "netinet/ip_var.h",
3366                "netinet/tcp.h",
3367                "netinet/udp.h",
3368                "netinet6/in6.h",
3369                "nl_types.h",
3370                "null.h",
3371                "poll.h",
3372                "pthread.h",
3373                "pwd.h",
3374                "regex.h",
3375                "resolv.h",
3376                "sched.h",
3377                "search.h",
3378                "semaphore.h",
3379                "setjmp.h",
3380                "shadow.h",
3381                "signal.h",
3382                "size_t.h",
3383                "spawn.h",
3384                "stdint.h",
3385                "stdio.h",
3386                "stdlib.h",
3387                "string.h",
3388                "strings.h",
3389                "sys/cdefs.h",
3390                "sys/file.h",
3391                "sys/ioctl.h",
3392                "sys/ipc.h",
3393                "sys/mman.h",
3394                "sys/msg.h",
3395                "sys/param.h",
3396                "sys/poll.h",
3397                "sys/resource.h",
3398                "sys/select.h",
3399                "sys/sem.h",
3400                "sys/socket.h",
3401                "sys/sockio.h",
3402                "sys/stat.h",
3403                "sys/statvfs.h",
3404                "sys/time.h",
3405                "sys/timeb.h",
3406                "sys/times.h",
3407                "sys/types.h",
3408                "sys/uio.h",
3409                "sys/un.h",
3410                "sys/utsname.h",
3411                "sys/wait.h",
3412                "syslog.h",
3413                "tar.h",
3414                "termios.h",
3415                "time.h",
3416                "uchar.h",
3417                "unistd.h",
3418                "utime.h",
3419                "wchar.h",
3420                "wchar_t.h",
3421                "wctype.h"
3422     }
3423 
3424     // BSD Extensions
3425     headers! { cfg:
3426                "pty.h",
3427     }
3428 
3429     // Native API
3430     headers! { cfg:
3431                "kernel/OS.h",
3432                "kernel/fs_attr.h",
3433                "kernel/fs_index.h",
3434                "kernel/fs_info.h",
3435                "kernel/fs_query.h",
3436                "kernel/fs_volume.h",
3437                "kernel/image.h",
3438                "kernel/scheduler.h",
3439                "storage/FindDirectory.h",
3440                "storage/StorageDefs.h",
3441                "support/Errors.h",
3442                "support/SupportDefs.h",
3443                "support/TypeConstants.h"
3444     }
3445 
3446     cfg.skip_struct(move |ty| {
3447         if ty.starts_with("__c_anonymous_") {
3448             return true;
3449         }
3450         match ty {
3451             // FIXME: actually a union
3452             "sigval" => true,
3453             // FIXME: locale_t does not exist on Haiku
3454             "locale_t" => true,
3455             // FIXME: rusage has a different layout on Haiku
3456             "rusage" => true,
3457             // FIXME?: complains that rust aligns on 4 byte boundary, but
3458             //         Haiku does not align it at all.
3459             "in6_addr" => true,
3460             // The d_name attribute is an array of 1 on Haiku, with the
3461             // intention that the developer allocates a larger or smaller
3462             // piece of memory depending on the expected/actual size of the name.
3463             // Other platforms have sensible defaults. In Rust, the d_name field
3464             // is sized as the _POSIX_MAX_PATH, so that path names will fit in
3465             // newly allocated dirent objects. This breaks the automated tests.
3466             "dirent" => true,
3467             // The following structs contain function pointers, which cannot be initialized
3468             // with mem::zeroed(), so skip the automated test
3469             "image_info" | "thread_info" => true,
3470 
3471             _ => false,
3472         }
3473     });
3474 
3475     cfg.skip_type(move |ty| {
3476         match ty {
3477             // FIXME: locale_t does not exist on Haiku
3478             "locale_t" => true,
3479             // These cause errors, to be reviewed in the future
3480             "sighandler_t" => true,
3481             "pthread_t" => true,
3482             "pthread_condattr_t" => true,
3483             "pthread_mutexattr_t" => true,
3484             "pthread_rwlockattr_t" => true,
3485             _ => false,
3486         }
3487     });
3488 
3489     cfg.skip_fn(move |name| {
3490         // skip those that are manually verified
3491         match name {
3492             // FIXME: https://github.com/rust-lang/libc/issues/1272
3493             "execv" | "execve" | "execvp" | "execvpe" => true,
3494             // FIXME: does not exist on haiku
3495             "open_wmemstream" => true,
3496             "mlockall" | "munlockall" => true,
3497             "tcgetsid" => true,
3498             "cfsetspeed" => true,
3499             // ignore for now, will be part of Haiku R1 beta 3
3500             "mlock" | "munlock" => true,
3501             // returns const char * on Haiku
3502             "strsignal" => true,
3503             // uses an enum as a parameter argument, which is incorrectly
3504             // translated into a struct argument
3505             "find_path" => true,
3506 
3507             _ => false,
3508         }
3509     });
3510 
3511     cfg.skip_const(move |name| {
3512         match name {
3513             // FIXME: these constants do not exist on Haiku
3514             "DT_UNKNOWN" | "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK"
3515             | "DT_SOCK" => true,
3516             "USRQUOTA" | "GRPQUOTA" => true,
3517             "SIGIOT" => true,
3518             "ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM" | "ATF_PUBL"
3519             | "ATF_USETRAILERS" => true,
3520             // Haiku does not have MAP_FILE, but rustc requires it
3521             "MAP_FILE" => true,
3522             // The following does not exist on Haiku but is required by
3523             // several crates
3524             "FIOCLEX" => true,
3525             // just skip this one, it is not defined on Haiku beta 2 but
3526             // since it is meant as a mask and not a parameter it can exist
3527             // here
3528             "LOG_PRIMASK" => true,
3529             // not defined on Haiku, but [get|set]priority is, so they are
3530             // useful
3531             "PRIO_MIN" | "PRIO_MAX" => true,
3532             //
3533             _ => false,
3534         }
3535     });
3536 
3537     cfg.skip_field(move |struct_, field| {
3538         match (struct_, field) {
3539             // FIXME: the stat struct actually has timespec members, whereas
3540             //        the current representation has these unpacked.
3541             ("stat", "st_atime") => true,
3542             ("stat", "st_atime_nsec") => true,
3543             ("stat", "st_mtime") => true,
3544             ("stat", "st_mtime_nsec") => true,
3545             ("stat", "st_ctime") => true,
3546             ("stat", "st_ctime_nsec") => true,
3547             ("stat", "st_crtime") => true,
3548             ("stat", "st_crtime_nsec") => true,
3549 
3550             // these are actually unions, but we cannot represent it well
3551             ("siginfo_t", "sigval") => true,
3552             ("sem_t", "named_sem_id") => true,
3553             ("sigaction", "sa_sigaction") => true,
3554             ("sigevent", "sigev_value") => true,
3555             ("fpu_state", "_fpreg") => true,
3556             // these fields have a simplified data definition in libc
3557             ("fpu_state", "_xmm") => true,
3558             ("savefpu", "_fp_ymm") => true,
3559 
3560             // skip these enum-type fields
3561             ("thread_info", "state") => true,
3562             ("image_info", "image_type") => true,
3563             _ => false,
3564         }
3565     });
3566 
3567     cfg.skip_roundtrip(move |s| match s {
3568         // FIXME: for some reason the roundtrip check fails for cpu_info
3569         "cpu_info" => true,
3570         _ => false,
3571     });
3572 
3573     cfg.type_name(move |ty, is_struct, is_union| {
3574         match ty {
3575             // Just pass all these through, no need for a "struct" prefix
3576             "area_info" | "port_info" | "port_message_info" | "team_info" | "sem_info"
3577             | "team_usage_info" | "thread_info" | "cpu_info" | "system_info"
3578             | "object_wait_info" | "image_info" | "attr_info" | "index_info" | "fs_info"
3579             | "FILE" | "DIR" | "Dl_info" => ty.to_string(),
3580 
3581             // is actually a union
3582             "sigval" => format!("union sigval"),
3583             t if is_union => format!("union {}", t),
3584             t if t.ends_with("_t") => t.to_string(),
3585             t if is_struct => format!("struct {}", t),
3586             t => t.to_string(),
3587         }
3588     });
3589 
3590     cfg.field_name(move |struct_, field| {
3591         match field {
3592             // Field is named `type` in C but that is a Rust keyword,
3593             // so these fields are translated to `type_` in the bindings.
3594             "type_" if struct_ == "object_wait_info" => "type".to_string(),
3595             "type_" if struct_ == "sem_t" => "type".to_string(),
3596             "type_" if struct_ == "attr_info" => "type".to_string(),
3597             "type_" if struct_ == "index_info" => "type".to_string(),
3598             "image_type" if struct_ == "image_info" => "type".to_string(),
3599             s => s.to_string(),
3600         }
3601     });
3602     cfg.generate("../src/lib.rs", "main.rs");
3603 }
3604