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