xref: /rust-libc-0.2.174/libc-test/build.rs (revision afc6eb54)
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             "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => true,
1667 
1668             _ => false,
1669         }
1670     });
1671 
1672     cfg.skip_fn(move |name| {
1673         // skip those that are manually verified
1674         match name {
1675             // FIXME: https://github.com/rust-lang/libc/issues/1272
1676             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
1677 
1678             // There are two versions of the sterror_r function, see
1679             //
1680             // https://linux.die.net/man/3/strerror_r
1681             //
1682             // An XSI-compliant version provided if:
1683             //
1684             // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
1685             //
1686             // and a GNU specific version provided if _GNU_SOURCE is defined.
1687             //
1688             // libc provides bindings for the XSI-compliant version, which is
1689             // preferred for portable applications.
1690             //
1691             // We skip the test here since here _GNU_SOURCE is defined, and
1692             // test the XSI version below.
1693             "strerror_r" => true,
1694             "reallocarray" => true,
1695             "__system_property_wait" => true,
1696 
1697             _ => false,
1698         }
1699     });
1700 
1701     cfg.skip_field_type(move |struct_, field| {
1702         // This is a weird union, don't check the type.
1703         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
1704         // sigval is actually a union, but we pretend it's a struct
1705         (struct_ == "sigevent" && field == "sigev_value") ||
1706         // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
1707         // incorrect, see: https://github.com/rust-lang/libc/issues/1359
1708         (struct_ == "sigaction" && field == "sa_sigaction") ||
1709         // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet.
1710         (struct_ == "signalfd_siginfo" && field == "ssi_call_addr")
1711     });
1712 
1713     cfg.skip_field(move |struct_, field| {
1714         // this is actually a union on linux, so we can't represent it well and
1715         // just insert some padding.
1716         (struct_ == "siginfo_t" && field == "_pad") ||
1717         // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
1718         // incorrect, see: https://github.com/rust-lang/libc/issues/1359
1719         (struct_ == "sigaction" && field == "sa_sigaction") ||
1720         // sigev_notify_thread_id is actually part of a sigev_un union
1721         (struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
1722         // signalfd had SIGSYS fields added in Android 4.19, but CI does not have that version yet.
1723         (struct_ == "signalfd_siginfo" && (field == "ssi_syscall" ||
1724                                            field == "ssi_call_addr" ||
1725                                            field == "ssi_arch"))
1726     });
1727 
1728     cfg.skip_field(|struct_, field| {
1729         match (struct_, field) {
1730             // conflicting with `p_type` macro from <resolve.h>.
1731             ("Elf32_Phdr", "p_type") => true,
1732             ("Elf64_Phdr", "p_type") => true,
1733 
1734             // this is actually a union on linux, so we can't represent it well and
1735             // just insert some padding.
1736             ("siginfo_t", "_pad") => true,
1737 
1738             _ => false,
1739         }
1740     });
1741 
1742     cfg.generate("../src/lib.rs", "main.rs");
1743 
1744     test_linux_like_apis(target);
1745 }
1746 
1747 fn test_freebsd(target: &str) {
1748     assert!(target.contains("freebsd"));
1749     let mut cfg = ctest_cfg();
1750 
1751     let freebsd_ver = which_freebsd();
1752 
1753     match freebsd_ver {
1754         Some(10) => cfg.cfg("freebsd10", None),
1755         Some(11) => cfg.cfg("freebsd11", None),
1756         Some(12) => cfg.cfg("freebsd12", None),
1757         Some(13) => cfg.cfg("freebsd13", None),
1758         _ => &mut cfg,
1759     };
1760 
1761     // Required for `getline`:
1762     cfg.define("_WITH_GETLINE", None);
1763     // Required for making freebsd11_stat available in the headers
1764     match freebsd_ver {
1765         Some(10) => &mut cfg,
1766         _ => cfg.define("_WANT_FREEBSD11_STAT", None),
1767     };
1768 
1769     let freebsd12 = match freebsd_ver {
1770         Some(n) if n >= 12 => true,
1771         _ => false,
1772     };
1773 
1774     let freebsd13 = match freebsd_ver {
1775         Some(n) if n >= 13 => true,
1776         _ => false,
1777     };
1778 
1779     headers! { cfg:
1780                 "aio.h",
1781                 "arpa/inet.h",
1782                 "ctype.h",
1783                 "dirent.h",
1784                 "dlfcn.h",
1785                 "elf.h",
1786                 "errno.h",
1787                 "execinfo.h",
1788                 "fcntl.h",
1789                 "glob.h",
1790                 "grp.h",
1791                 "iconv.h",
1792                 "ifaddrs.h",
1793                 "langinfo.h",
1794                 "libutil.h",
1795                 "limits.h",
1796                 "link.h",
1797                 "locale.h",
1798                 "machine/elf.h",
1799                 "machine/reg.h",
1800                 "malloc_np.h",
1801                 "mqueue.h",
1802                 "net/bpf.h",
1803                 "net/if.h",
1804                 "net/if_arp.h",
1805                 "net/if_dl.h",
1806                 "net/route.h",
1807                 "netdb.h",
1808                 "netinet/ip.h",
1809                 "netinet/in.h",
1810                 "netinet/tcp.h",
1811                 "netinet/udp.h",
1812                 "poll.h",
1813                 "pthread.h",
1814                 "pthread_np.h",
1815                 "pwd.h",
1816                 "regex.h",
1817                 "resolv.h",
1818                 "sched.h",
1819                 "semaphore.h",
1820                 "signal.h",
1821                 "spawn.h",
1822                 "stddef.h",
1823                 "stdint.h",
1824                 "stdio.h",
1825                 "stdlib.h",
1826                 "string.h",
1827                 "sys/capsicum.h",
1828                 [freebsd12]:"sys/auxv.h",
1829                 "sys/cpuset.h",
1830                 [freebsd12]:"sys/domainset.h",
1831                 "sys/event.h",
1832                 [freebsd13]:"sys/eventfd.h",
1833                 "sys/extattr.h",
1834                 "sys/file.h",
1835                 "sys/ioctl.h",
1836                 "sys/ipc.h",
1837                 "sys/jail.h",
1838                 "sys/mman.h",
1839                 "sys/mount.h",
1840                 "sys/msg.h",
1841                 "sys/procctl.h",
1842                 "sys/procdesc.h",
1843                 "sys/ptrace.h",
1844                 "sys/queue.h",
1845                 "sys/random.h",
1846                 "sys/resource.h",
1847                 "sys/rtprio.h",
1848                 "sys/sem.h",
1849                 "sys/shm.h",
1850                 "sys/socket.h",
1851                 "sys/stat.h",
1852                 "sys/statvfs.h",
1853                 "sys/sysctl.h",
1854                 "sys/thr.h",
1855                 "sys/time.h",
1856                 "sys/times.h",
1857                 "sys/timex.h",
1858                 "sys/types.h",
1859                 "kvm.h", // must be after "sys/types.h"
1860                 "sys/ucontext.h",
1861                 "sys/uio.h",
1862                 "sys/ktrace.h",
1863                 "sys/un.h",
1864                 "sys/user.h",
1865                 "sys/utsname.h",
1866                 "sys/uuid.h",
1867                 "sys/wait.h",
1868                 "libprocstat.h",
1869                 "syslog.h",
1870                 "termios.h",
1871                 "time.h",
1872                 "ufs/ufs/quota.h",
1873                 "unistd.h",
1874                 "utime.h",
1875                 "utmpx.h",
1876                 "wchar.h",
1877     }
1878 
1879     cfg.type_name(move |ty, is_struct, is_union| {
1880         match ty {
1881             // Just pass all these through, no need for a "struct" prefix
1882             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr"
1883             | "Elf32_Auxinfo" | "Elf64_Auxinfo" => ty.to_string(),
1884 
1885             // FIXME: https://github.com/rust-lang/libc/issues/1273
1886             "sighandler_t" => "sig_t".to_string(),
1887 
1888             t if is_union => format!("union {}", t),
1889 
1890             t if t.ends_with("_t") => t.to_string(),
1891 
1892             // sigval is a struct in Rust, but a union in C:
1893             "sigval" => format!("union sigval"),
1894 
1895             // put `struct` in front of all structs:.
1896             t if is_struct => format!("struct {}", t),
1897 
1898             t => t.to_string(),
1899         }
1900     });
1901 
1902     cfg.field_name(move |struct_, field| {
1903         match field {
1904             // Our stat *_nsec fields normally don't actually exist but are part
1905             // of a timeval struct
1906             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
1907                 s.replace("e_nsec", ".tv_nsec")
1908             }
1909             // Field is named `type` in C but that is a Rust keyword,
1910             // so these fields are translated to `type_` in the bindings.
1911             "type_" if struct_ == "rtprio" => "type".to_string(),
1912             s => s.to_string(),
1913         }
1914     });
1915 
1916     cfg.skip_const(move |name| {
1917         match name {
1918             // These constants were introduced in FreeBSD 13:
1919             "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW"
1920             | "F_SEAL_WRITE"
1921                 if Some(13) > freebsd_ver =>
1922             {
1923                 true
1924             }
1925 
1926             // These constants were introduced in FreeBSD 13:
1927             "EFD_CLOEXEC" | "EFD_NONBLOCK" | "EFD_SEMAPHORE" if Some(13) > freebsd_ver => true,
1928 
1929             // These constants were introduced in FreeBSD 12:
1930             "SF_USER_READAHEAD"
1931             | "EVFILT_EMPTY"
1932             | "SO_REUSEPORT_LB"
1933             | "IP_ORIGDSTADDR"
1934             | "IP_RECVORIGDSTADDR"
1935             | "IPV6_ORIGDSTADDR"
1936             | "IPV6_RECVORIGDSTADDR"
1937             | "NI_NUMERICSCOPE"
1938             | "SO_DOMAIN"
1939                 if Some(11) == freebsd_ver =>
1940             {
1941                 true
1942             }
1943 
1944             // These constants were introduced in FreeBSD 11:
1945             "SF_USER_READAHEAD"
1946             | "SF_NOCACHE"
1947             | "RLIMIT_KQUEUES"
1948             | "RLIMIT_UMTXP"
1949             | "EVFILT_PROCDESC"
1950             | "EVFILT_SENDFILE"
1951             | "EVFILT_EMPTY"
1952             | "SO_REUSEPORT_LB"
1953             | "TCP_CCALGOOPT"
1954             | "TCP_PCAP_OUT"
1955             | "TCP_PCAP_IN"
1956             | "IP_BINDMULTI"
1957             | "IP_ORIGDSTADDR"
1958             | "IP_RECVORIGDSTADDR"
1959             | "IPV6_ORIGDSTADDR"
1960             | "IPV6_RECVORIGDSTADDR"
1961             | "PD_CLOEXEC"
1962             | "PD_ALLOWED_AT_FORK"
1963             | "IP_RSS_LISTEN_BUCKET"
1964             | "NI_NUMERICSCOPE"
1965                 if Some(10) == freebsd_ver =>
1966             {
1967                 true
1968             }
1969 
1970             // FIXME: This constant has a different value in FreeBSD 10:
1971             "RLIM_NLIMITS" if Some(10) == freebsd_ver => true,
1972 
1973             // FIXME: There are deprecated - remove in a couple of releases.
1974             // These constants were removed in FreeBSD 11 (svn r273250) but will
1975             // still be accepted and ignored at runtime.
1976             "MAP_RENAME" | "MAP_NORESERVE" if Some(10) != freebsd_ver => true,
1977 
1978             // FIXME: There are deprecated - remove in a couple of releases.
1979             // These constants were removed in FreeBSD 11 (svn r262489),
1980             // and they've never had any legitimate use outside of the
1981             // base system anyway.
1982             "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "USER_MAXID" => true,
1983 
1984             // This constant was removed in FreeBSD 13 (svn r363622), and never
1985             // had any legitimate use outside of the base system anyway.
1986             "CTL_P1003_1B_MAXID" => true,
1987 
1988             // This was renamed in FreeBSD 12.2 and 13 (r352486).
1989             "CTL_UNSPEC" | "CTL_SYSCTL" => true,
1990 
1991             // These were added in FreeBSD 12.2 and 13 (r352486),
1992             // but they are just names for magic numbers that existed for ages.
1993             "CTL_SYSCTL_DEBUG"
1994             | "CTL_SYSCTL_NAME"
1995             | "CTL_SYSCTL_NEXT"
1996             | "CTL_SYSCTL_NAME2OID"
1997             | "CTL_SYSCTL_OIDFMT"
1998             | "CTL_SYSCTL_OIDDESCR"
1999             | "CTL_SYSCTL_OIDLABEL" => true,
2000 
2001             // This was renamed in FreeBSD 12.2 and 13 (r350749).
2002             "IPPROTO_SEP" | "IPPROTO_DCCP" => true,
2003 
2004             // This was changed to 96(0x60) in FreeBSD 13:
2005             // https://github.com/freebsd/freebsd/
2006             // commit/06b00ceaa914a3907e4e27bad924f44612bae1d7
2007             "MINCORE_SUPER" if Some(13) == freebsd_ver => true,
2008 
2009             // Added in FreeBSD 12.0
2010             "EINTEGRITY" if Some(11) == freebsd_ver => true,
2011 
2012             // This was increased to 97 in FreeBSD 12.2 and 13.
2013             // https://github.com/freebsd/freebsd/
2014             // commit/72a21ba0f62da5e86a1c0b462aeb3f5ff849a1b7
2015             "ELAST" if Some(12) == freebsd_ver => true,
2016 
2017             // Added in FreeBSD 12.0 (r331279)
2018             "GRND_NONBLOCK" | "GRND_RANDOM" if Some(11) == freebsd_ver => true,
2019             // Added in FreeBSD 13.0 (r356667)
2020             "GRND_INSECURE" if Some(13) > freebsd_ver => true,
2021 
2022             // Added in FreeBSD 12.1 (r343964)
2023             "PROC_ASLR_CTL"
2024             | "PROC_ASLR_STATUS"
2025             | "PROC_ASLR_FORCE_ENABLE"
2026             | "PROC_ASLR_FORCE_DISABLE"
2027             | "PROC_ASLR_NOFORCE"
2028             | "PROC_ASLR_ACTIVE"
2029                 if Some(11) == freebsd_ver =>
2030             {
2031                 true
2032             }
2033 
2034             // Added in FreeBSD 12.1 (r345228)
2035             "PROC_PROCCTL_MD_MIN" if Some(11) == freebsd_ver => true,
2036 
2037             // Added in FreeBSD 13.0 (r349609)
2038             "PROC_PROTMAX_CTL"
2039             | "PROC_PROTMAX_STATUS"
2040             | "PROC_PROTMAX_FORCE_ENABLE"
2041             | "PROC_PROTMAX_FORCE_DISABLE"
2042             | "PROC_PROTMAX_NOFORCE"
2043             | "PROC_PROTMAX_ACTIVE"
2044                 if Some(13) > freebsd_ver =>
2045             {
2046                 true
2047             }
2048 
2049             // Added in FreeBSD 12.1
2050             "PT_GET_SC_RET" | "PT_GET_SC_ARGS" if Some(11) == freebsd_ver => true,
2051 
2052             // Added in in FreeBSD 13.0 (r367776 and r367287)
2053             "SCM_CREDS2" | "LOCAL_CREDS_PERSISTENT" if Some(13) > freebsd_ver => true,
2054 
2055             _ => false,
2056         }
2057     });
2058 
2059     cfg.skip_type(move |ty| {
2060         match ty {
2061             // the struct "__kvm" is quite tricky to bind so since we only use a pointer to it
2062             // for now, it doesn't matter too much...
2063             "kvm_t" => true,
2064 
2065             _ => false,
2066         }
2067     });
2068 
2069     cfg.skip_struct(move |ty| {
2070         if ty.starts_with("__c_anonymous_") {
2071             return true;
2072         }
2073         match ty {
2074             // `mmsghdr` is not available in FreeBSD 10
2075             "mmsghdr" if Some(10) == freebsd_ver => true,
2076 
2077             // `max_align_t` is not available in FreeBSD 10
2078             "max_align_t" if Some(10) == freebsd_ver => true,
2079 
2080             // `procstat` is a private struct
2081             "procstat" => true,
2082 
2083             // `ptrace_sc_ret` is not available in FreeBSD 11
2084             "ptrace_sc_ret" if Some(11) == freebsd_ver => true,
2085 
2086             _ => false,
2087         }
2088     });
2089 
2090     cfg.skip_fn(move |name| {
2091         // skip those that are manually verified
2092         match name {
2093             // FIXME: https://github.com/rust-lang/libc/issues/1272
2094             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
2095 
2096             // These functions were added in FreeBSD 11:
2097             "fdatasync" | "mq_getfd_np" | "sendmmsg" | "recvmmsg" if Some(10) == freebsd_ver => {
2098                 true
2099             }
2100 
2101             // This function changed its return type from `int` in FreeBSD10 to
2102             // `ssize_t` in FreeBSD11:
2103             "aio_waitcomplete" if Some(10) == freebsd_ver => true,
2104 
2105             // The `uname` function in the `utsname.h` FreeBSD header is a C
2106             // inline function (has no symbol) that calls the `__xuname` symbol.
2107             // Therefore the function pointer comparison does not make sense for it.
2108             "uname" => true,
2109 
2110             // FIXME: Our API is unsound. The Rust API allows aliasing
2111             // pointers, but the C API requires pointers not to alias.
2112             // We should probably be at least using `&`/`&mut` here, see:
2113             // https://github.com/gnzlbg/ctest/issues/68
2114             "lio_listio" => true,
2115 
2116             _ => false,
2117         }
2118     });
2119 
2120     cfg.skip_signededness(move |c| {
2121         match c {
2122             // FIXME: has a different sign in FreeBSD10
2123             "blksize_t" if Some(10) == freebsd_ver => true,
2124             _ => false,
2125         }
2126     });
2127 
2128     cfg.volatile_item(|i| {
2129         use ctest::VolatileItemKind::*;
2130         match i {
2131             // aio_buf is a volatile void** but since we cannot express that in
2132             // Rust types, we have to explicitly tell the checker about it here:
2133             StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
2134             _ => false,
2135         }
2136     });
2137 
2138     cfg.skip_field(move |struct_, field| {
2139         match (struct_, field) {
2140             // FIXME: `sa_sigaction` has type `sighandler_t` but that type is
2141             // incorrect, see: https://github.com/rust-lang/libc/issues/1359
2142             ("sigaction", "sa_sigaction") => true,
2143 
2144             // FIXME: in FreeBSD10 this field has type `char*` instead of
2145             // `void*`:
2146             ("stack_t", "ss_sp") if Some(10) == freebsd_ver => true,
2147 
2148             // conflicting with `p_type` macro from <resolve.h>.
2149             ("Elf32_Phdr", "p_type") => true,
2150             ("Elf64_Phdr", "p_type") => true,
2151 
2152             // not available until FreeBSD 12, and is an anonymous union there.
2153             ("xucred", "cr_pid__c_anonymous_union") => true,
2154 
2155             // m_owner field is a volatile __lwpid_t
2156             ("umutex", "m_owner") => true,
2157             // c_has_waiters field is a volatile int32_t
2158             ("ucond", "c_has_waiters") => true,
2159             // is PATH_MAX long but tests can't accept multi array as equivalent.
2160             ("kinfo_vmentry", "kve_path") => true,
2161 
2162             // a_un field is a union
2163             ("Elf32_Auxinfo", "a_un") => true,
2164             ("Elf64_Auxinfo", "a_un") => true,
2165 
2166             // FIXME: structs too complicated to bind for now...
2167             ("kinfo_proc", "ki_paddr") => true,
2168             ("kinfo_proc", "ki_addr") => true,
2169             ("kinfo_proc", "ki_tracep") => true,
2170             ("kinfo_proc", "ki_textvp") => true,
2171             ("kinfo_proc", "ki_fd") => true,
2172             ("kinfo_proc", "ki_vmspace") => true,
2173             ("kinfo_proc", "ki_pcb") => true,
2174             ("kinfo_proc", "ki_tdaddr") => true,
2175             ("kinfo_proc", "ki_pd") => true,
2176 
2177             // We ignore this field because we needed to use a hack in order to make rust 1.19
2178             // happy...
2179             ("kinfo_proc", "ki_sparestrings") => true,
2180 
2181             // `__sem_base` is a private struct field
2182             ("semid_ds", "__sem_base") => true,
2183             _ => false,
2184         }
2185     });
2186 
2187     cfg.generate("../src/lib.rs", "main.rs");
2188 }
2189 
2190 fn test_emscripten(target: &str) {
2191     assert!(target.contains("emscripten"));
2192 
2193     let mut cfg = ctest_cfg();
2194     cfg.define("_GNU_SOURCE", None); // FIXME: ??
2195 
2196     headers! { cfg:
2197                "aio.h",
2198                "ctype.h",
2199                "dirent.h",
2200                "dlfcn.h",
2201                "errno.h",
2202                "fcntl.h",
2203                "glob.h",
2204                "grp.h",
2205                "ifaddrs.h",
2206                "langinfo.h",
2207                "limits.h",
2208                "locale.h",
2209                "malloc.h",
2210                "mntent.h",
2211                "mqueue.h",
2212                "net/ethernet.h",
2213                "net/if.h",
2214                "net/if_arp.h",
2215                "net/route.h",
2216                "netdb.h",
2217                "netinet/in.h",
2218                "netinet/ip.h",
2219                "netinet/tcp.h",
2220                "netinet/udp.h",
2221                "netpacket/packet.h",
2222                "poll.h",
2223                "pthread.h",
2224                "pty.h",
2225                "pwd.h",
2226                "resolv.h",
2227                "sched.h",
2228                "sched.h",
2229                "semaphore.h",
2230                "shadow.h",
2231                "signal.h",
2232                "stddef.h",
2233                "stdint.h",
2234                "stdio.h",
2235                "stdlib.h",
2236                "string.h",
2237                "sys/epoll.h",
2238                "sys/eventfd.h",
2239                "sys/file.h",
2240                "sys/ioctl.h",
2241                "sys/ipc.h",
2242                "sys/mman.h",
2243                "sys/mount.h",
2244                "sys/msg.h",
2245                "sys/personality.h",
2246                "sys/prctl.h",
2247                "sys/ptrace.h",
2248                "sys/quota.h",
2249                "sys/reboot.h",
2250                "sys/resource.h",
2251                "sys/sem.h",
2252                "sys/sendfile.h",
2253                "sys/shm.h",
2254                "sys/signalfd.h",
2255                "sys/socket.h",
2256                "sys/stat.h",
2257                "sys/statvfs.h",
2258                "sys/swap.h",
2259                "sys/syscall.h",
2260                "sys/sysctl.h",
2261                "sys/sysinfo.h",
2262                "sys/time.h",
2263                "sys/timerfd.h",
2264                "sys/times.h",
2265                "sys/types.h",
2266                "sys/uio.h",
2267                "sys/un.h",
2268                "sys/user.h",
2269                "sys/utsname.h",
2270                "sys/vfs.h",
2271                "sys/wait.h",
2272                "sys/xattr.h",
2273                "syslog.h",
2274                "termios.h",
2275                "time.h",
2276                "ucontext.h",
2277                "unistd.h",
2278                "utime.h",
2279                "utmp.h",
2280                "utmpx.h",
2281                "wchar.h",
2282     }
2283 
2284     cfg.type_name(move |ty, is_struct, is_union| {
2285         match ty {
2286             // Just pass all these through, no need for a "struct" prefix
2287             "FILE" | "fd_set" | "Dl_info" | "DIR" => ty.to_string(),
2288 
2289             t if is_union => format!("union {}", t),
2290 
2291             t if t.ends_with("_t") => t.to_string(),
2292 
2293             // put `struct` in front of all structs:.
2294             t if is_struct => format!("struct {}", t),
2295 
2296             t => t.to_string(),
2297         }
2298     });
2299 
2300     cfg.field_name(move |struct_, field| {
2301         match field {
2302             // Our stat *_nsec fields normally don't actually exist but are part
2303             // of a timeval struct
2304             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
2305                 s.replace("e_nsec", ".tv_nsec")
2306             }
2307             // FIXME: appears that `epoll_event.data` is an union
2308             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
2309             s => s.to_string(),
2310         }
2311     });
2312 
2313     cfg.skip_type(move |ty| {
2314         match ty {
2315             // sighandler_t is crazy across platforms
2316             // FIXME: is this necessary?
2317             "sighandler_t" => true,
2318 
2319             _ => false,
2320         }
2321     });
2322 
2323     cfg.skip_struct(move |ty| {
2324         match ty {
2325             // This is actually a union, not a struct
2326             // FIXME: is this necessary?
2327             "sigval" => true,
2328 
2329             // FIXME: It was removed in
2330             // emscripten-core/emscripten@953e414
2331             "pthread_mutexattr_t" => true,
2332 
2333             // FIXME: Investigate why the test fails.
2334             // Skip for now to unblock CI.
2335             "pthread_condattr_t" => true,
2336 
2337             _ => false,
2338         }
2339     });
2340 
2341     cfg.skip_fn(move |name| {
2342         match name {
2343             // FIXME: https://github.com/rust-lang/libc/issues/1272
2344             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
2345 
2346             // FIXME: Investigate why CI is missing it.
2347             "clearenv" => true,
2348 
2349             _ => false,
2350         }
2351     });
2352 
2353     cfg.skip_const(move |name| {
2354         match name {
2355             // FIXME: deprecated - SIGNUNUSED was removed in glibc 2.26
2356             // users should use SIGSYS instead
2357             "SIGUNUSED" => true,
2358 
2359             // FIXME: emscripten uses different constants to constructs these
2360             n if n.contains("__SIZEOF_PTHREAD") => true,
2361 
2362             // FIXME: `SYS_gettid` was removed in
2363             // emscripten-core/emscripten@6d6474e
2364             "SYS_gettid" => true,
2365 
2366             _ => false,
2367         }
2368     });
2369 
2370     cfg.skip_field_type(move |struct_, field| {
2371         // This is a weird union, don't check the type.
2372         // FIXME: is this necessary?
2373         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
2374         // sighandler_t type is super weird
2375         // FIXME: is this necessary?
2376         (struct_ == "sigaction" && field == "sa_sigaction") ||
2377         // sigval is actually a union, but we pretend it's a struct
2378         // FIXME: is this necessary?
2379         (struct_ == "sigevent" && field == "sigev_value") ||
2380         // aio_buf is "volatile void*" and Rust doesn't understand volatile
2381         // FIXME: is this necessary?
2382         (struct_ == "aiocb" && field == "aio_buf")
2383     });
2384 
2385     cfg.skip_field(move |struct_, field| {
2386         // this is actually a union on linux, so we can't represent it well and
2387         // just insert some padding.
2388         // FIXME: is this necessary?
2389         (struct_ == "siginfo_t" && field == "_pad") ||
2390         // musl names this __dummy1 but it's still there
2391         // FIXME: is this necessary?
2392         (struct_ == "glob_t" && field == "gl_flags") ||
2393         // musl seems to define this as an *anonymous* bitfield
2394         // FIXME: is this necessary?
2395         (struct_ == "statvfs" && field == "__f_unused") ||
2396         // sigev_notify_thread_id is actually part of a sigev_un union
2397         (struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
2398         // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet.
2399         (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" ||
2400                                            field == "_pad2" ||
2401                                            field == "ssi_syscall" ||
2402                                            field == "ssi_call_addr" ||
2403                                            field == "ssi_arch"))
2404     });
2405 
2406     // FIXME: test linux like
2407     cfg.generate("../src/lib.rs", "main.rs");
2408 }
2409 
2410 fn test_vxworks(target: &str) {
2411     assert!(target.contains("vxworks"));
2412 
2413     let mut cfg = ctest::TestGenerator::new();
2414     headers! { cfg:
2415                "vxWorks.h",
2416                "yvals.h",
2417                "nfs/nfsCommon.h",
2418                "rtpLibCommon.h",
2419                "randomNumGen.h",
2420                "taskLib.h",
2421                "sysLib.h",
2422                "ioLib.h",
2423                "inetLib.h",
2424                "socket.h",
2425                "errnoLib.h",
2426                "ctype.h",
2427                "dirent.h",
2428                "dlfcn.h",
2429                "elf.h",
2430                "fcntl.h",
2431                "grp.h",
2432                "sys/poll.h",
2433                "ifaddrs.h",
2434                "langinfo.h",
2435                "limits.h",
2436                "link.h",
2437                "locale.h",
2438                "sys/stat.h",
2439                "netdb.h",
2440                "pthread.h",
2441                "pwd.h",
2442                "sched.h",
2443                "semaphore.h",
2444                "signal.h",
2445                "stddef.h",
2446                "stdint.h",
2447                "stdio.h",
2448                "stdlib.h",
2449                "string.h",
2450                "sys/file.h",
2451                "sys/ioctl.h",
2452                "sys/socket.h",
2453                "sys/time.h",
2454                "sys/times.h",
2455                "sys/types.h",
2456                "sys/uio.h",
2457                "sys/un.h",
2458                "sys/utsname.h",
2459                "sys/wait.h",
2460                "netinet/tcp.h",
2461                "syslog.h",
2462                "termios.h",
2463                "time.h",
2464                "ucontext.h",
2465                "unistd.h",
2466                "utime.h",
2467                "wchar.h",
2468                "errno.h",
2469                "sys/mman.h",
2470                "pathLib.h",
2471                "mqueue.h",
2472     }
2473     // FIXME
2474     cfg.skip_const(move |name| match name {
2475         // sighandler_t weirdness
2476         "SIG_DFL" | "SIG_ERR" | "SIG_IGN"
2477         // This is not defined in vxWorks
2478         | "RTLD_DEFAULT"   => true,
2479         _ => false,
2480     });
2481     // FIXME
2482     cfg.skip_type(move |ty| match ty {
2483         "stat64" | "sighandler_t" | "off64_t" => true,
2484         _ => false,
2485     });
2486 
2487     cfg.skip_field_type(move |struct_, field| match (struct_, field) {
2488         ("siginfo_t", "si_value") | ("stat", "st_size") | ("sigaction", "sa_u") => true,
2489         _ => false,
2490     });
2491 
2492     cfg.skip_roundtrip(move |s| match s {
2493         _ => false,
2494     });
2495 
2496     cfg.type_name(move |ty, is_struct, is_union| match ty {
2497         "DIR" | "FILE" | "Dl_info" | "RTP_DESC" => ty.to_string(),
2498         t if is_union => format!("union {}", t),
2499         t if t.ends_with("_t") => t.to_string(),
2500         t if is_struct => format!("struct {}", t),
2501         t => t.to_string(),
2502     });
2503 
2504     // FIXME
2505     cfg.skip_fn(move |name| match name {
2506         // sigval
2507         "sigqueue" | "_sigqueue"
2508         // sighandler_t
2509         | "signal"
2510         // not used in static linking by default
2511         | "dlerror" => true,
2512         _ => false,
2513     });
2514 
2515     cfg.generate("../src/lib.rs", "main.rs");
2516 }
2517 
2518 fn test_linux(target: &str) {
2519     assert!(target.contains("linux"));
2520 
2521     // target_env
2522     let gnu = target.contains("gnu");
2523     let musl = target.contains("musl");
2524     let uclibc = target.contains("uclibc");
2525 
2526     match (gnu, musl, uclibc) {
2527         (true, false, false) => (),
2528         (false, true, false) => (),
2529         (false, false, true) => (),
2530         (_, _, _) => panic!(
2531             "linux target lib is gnu: {}, musl: {}, uclibc: {}",
2532             gnu, musl, uclibc
2533         ),
2534     }
2535 
2536     let arm = target.contains("arm");
2537     let i686 = target.contains("i686");
2538     let mips = target.contains("mips");
2539     let mips32 = mips && !target.contains("64");
2540     let mips64 = mips && target.contains("64");
2541     let ppc64 = target.contains("powerpc64");
2542     let s390x = target.contains("s390x");
2543     let sparc64 = target.contains("sparc64");
2544     let x32 = target.contains("x32");
2545     let x86_32 = target.contains("i686");
2546     let x86_64 = target.contains("x86_64");
2547     let aarch64_musl = target.contains("aarch64") && musl;
2548     let gnuabihf = target.contains("gnueabihf");
2549     let x86_64_gnux32 = target.contains("gnux32") && x86_64;
2550     let riscv64 = target.contains("riscv64");
2551     let uclibc = target.contains("uclibc");
2552 
2553     let mut cfg = ctest_cfg();
2554     cfg.define("_GNU_SOURCE", None);
2555     // This macro re-deifnes fscanf,scanf,sscanf to link to the symbols that are
2556     // deprecated since glibc >= 2.29. This allows Rust binaries to link against
2557     // glibc versions older than 2.29.
2558     cfg.define("__GLIBC_USE_DEPRECATED_SCANF", None);
2559 
2560     headers! { cfg:
2561                "ctype.h",
2562                "dirent.h",
2563                "dlfcn.h",
2564                "elf.h",
2565                "fcntl.h",
2566                "glob.h",
2567                "grp.h",
2568                "iconv.h",
2569                "ifaddrs.h",
2570                "langinfo.h",
2571                "limits.h",
2572                "link.h",
2573                "locale.h",
2574                "malloc.h",
2575                "mntent.h",
2576                "mqueue.h",
2577                "net/ethernet.h",
2578                "net/if.h",
2579                "net/if_arp.h",
2580                "net/route.h",
2581                "netdb.h",
2582                "netinet/in.h",
2583                "netinet/ip.h",
2584                "netinet/tcp.h",
2585                "netinet/udp.h",
2586                "netpacket/packet.h",
2587                "poll.h",
2588                "pthread.h",
2589                "pty.h",
2590                "pwd.h",
2591                "regex.h",
2592                "resolv.h",
2593                "sched.h",
2594                "semaphore.h",
2595                "shadow.h",
2596                "signal.h",
2597                "spawn.h",
2598                "stddef.h",
2599                "stdint.h",
2600                "stdio.h",
2601                "stdlib.h",
2602                "string.h",
2603                "sys/epoll.h",
2604                "sys/eventfd.h",
2605                "sys/file.h",
2606                "sys/fsuid.h",
2607                "sys/inotify.h",
2608                "sys/ioctl.h",
2609                "sys/ipc.h",
2610                "sys/mman.h",
2611                "sys/mount.h",
2612                "sys/msg.h",
2613                "sys/personality.h",
2614                "sys/prctl.h",
2615                "sys/ptrace.h",
2616                "sys/quota.h",
2617                "sys/random.h",
2618                "sys/reboot.h",
2619                "sys/resource.h",
2620                "sys/sem.h",
2621                "sys/sendfile.h",
2622                "sys/shm.h",
2623                "sys/signalfd.h",
2624                "sys/socket.h",
2625                "sys/stat.h",
2626                "sys/statvfs.h",
2627                "sys/swap.h",
2628                "sys/syscall.h",
2629                "sys/time.h",
2630                "sys/timerfd.h",
2631                "sys/times.h",
2632                "sys/timex.h",
2633                "sys/types.h",
2634                "sys/uio.h",
2635                "sys/un.h",
2636                "sys/user.h",
2637                "sys/utsname.h",
2638                "sys/vfs.h",
2639                "sys/wait.h",
2640                "syslog.h",
2641                "termios.h",
2642                "time.h",
2643                "ucontext.h",
2644                "unistd.h",
2645                "utime.h",
2646                "utmp.h",
2647                "utmpx.h",
2648                "wchar.h",
2649                "errno.h",
2650                // `sys/io.h` is only available on x86*, Alpha, IA64, and 32-bit
2651                // ARM: https://bugzilla.redhat.com/show_bug.cgi?id=1116162
2652                // Also unavailable on gnuabihf with glibc 2.30.
2653                // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=6b33f373c7b9199e00ba5fbafd94ac9bfb4337b1
2654                [(x86_64 || x86_32 || arm) && !gnuabihf]: "sys/io.h",
2655                // `sys/reg.h` is only available on x86 and x86_64
2656                [x86_64 || x86_32]: "sys/reg.h",
2657                // sysctl system call is deprecated and not available on musl
2658                // It is also unsupported in x32, deprecated since glibc 2.30:
2659                [!(x32 || musl || gnu)]: "sys/sysctl.h",
2660                // <execinfo.h> is not supported by musl:
2661                // https://www.openwall.com/lists/musl/2015/04/09/3
2662                // <execinfo.h> is not present on uclibc.
2663                [!(musl || uclibc)]: "execinfo.h",
2664     }
2665 
2666     // Include linux headers at the end:
2667     headers! {
2668         cfg:
2669         "asm/mman.h",
2670         "linux/can.h",
2671         "linux/can/raw.h",
2672         "linux/dccp.h",
2673         "linux/errqueue.h",
2674         "linux/falloc.h",
2675         "linux/fs.h",
2676         "linux/futex.h",
2677         "linux/genetlink.h",
2678         "linux/if.h",
2679         "linux/if_addr.h",
2680         "linux/if_alg.h",
2681         "linux/if_ether.h",
2682         "linux/if_tun.h",
2683         "linux/input.h",
2684         "linux/keyctl.h",
2685         "linux/magic.h",
2686         "linux/memfd.h",
2687         "linux/mman.h",
2688         "linux/module.h",
2689         "linux/net_tstamp.h",
2690         "linux/netfilter/nfnetlink.h",
2691         "linux/netfilter/nfnetlink_log.h",
2692         "linux/netfilter/nfnetlink_queue.h",
2693         "linux/netfilter/nf_tables.h",
2694         "linux/netfilter_ipv4.h",
2695         "linux/netfilter_ipv6.h",
2696         "linux/netfilter_ipv6/ip6_tables.h",
2697         "linux/netlink.h",
2698         // FIXME: requires more recent kernel headers:
2699         // "linux/openat2.h",
2700         "linux/quota.h",
2701         "linux/random.h",
2702         "linux/reboot.h",
2703         "linux/rtnetlink.h",
2704         "linux/sched.h",
2705         "linux/seccomp.h",
2706         "linux/sockios.h",
2707         "linux/uinput.h",
2708         "linux/vm_sockets.h",
2709         "linux/wait.h",
2710         "sys/fanotify.h",
2711         // <sys/auxv.h> is not present on uclibc
2712         [!uclibc]: "sys/auxv.h",
2713     }
2714 
2715     // note: aio.h must be included before sys/mount.h
2716     headers! {
2717         cfg:
2718         "sys/xattr.h",
2719         "sys/sysinfo.h",
2720         // AIO is not supported by uclibc:
2721         [!uclibc]: "aio.h",
2722     }
2723 
2724     cfg.type_name(move |ty, is_struct, is_union| {
2725         match ty {
2726             // Just pass all these through, no need for a "struct" prefix
2727             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" | "Elf64_Phdr" | "Elf32_Shdr"
2728             | "Elf64_Shdr" | "Elf32_Sym" | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr"
2729             | "Elf32_Chdr" | "Elf64_Chdr" => ty.to_string(),
2730 
2731             t if is_union => format!("union {}", t),
2732 
2733             t if t.ends_with("_t") => t.to_string(),
2734 
2735             // In MUSL `flock64` is a typedef to `flock`.
2736             "flock64" if musl => format!("struct {}", ty),
2737 
2738             // put `struct` in front of all structs:.
2739             t if is_struct => format!("struct {}", t),
2740 
2741             t => t.to_string(),
2742         }
2743     });
2744 
2745     cfg.field_name(move |struct_, field| {
2746         match field {
2747             // Our stat *_nsec fields normally don't actually exist but are part
2748             // of a timeval struct
2749             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
2750                 s.replace("e_nsec", ".tv_nsec")
2751             }
2752             // FIXME: epoll_event.data is actually a union in C, but in Rust
2753             // it is only a u64 because we only expose one field
2754             // http://man7.org/linux/man-pages/man2/epoll_wait.2.html
2755             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
2756             // The following structs have a field called `type` in C,
2757             // but `type` is a Rust keyword, so these fields are translated
2758             // to `type_` in Rust.
2759             "type_"
2760                 if struct_ == "input_event"
2761                     || struct_ == "input_mask"
2762                     || struct_ == "ff_effect" =>
2763             {
2764                 "type".to_string()
2765             }
2766 
2767             s => s.to_string(),
2768         }
2769     });
2770 
2771     cfg.skip_type(move |ty| {
2772         match ty {
2773             // FIXME: `sighandler_t` type is incorrect, see:
2774             // https://github.com/rust-lang/libc/issues/1359
2775             "sighandler_t" => true,
2776 
2777             // These cannot be tested when "resolv.h" is included and are tested
2778             // in the `linux_elf.rs` file.
2779             "Elf64_Phdr" | "Elf32_Phdr" => true,
2780 
2781             // This type is private on Linux. It is implemented as a C `enum`
2782             // (`c_uint`) and this clashes with the type of the `rlimit` APIs
2783             // which expect a `c_int` even though both are ABI compatible.
2784             "__rlimit_resource_t" => true,
2785             // on Linux, this is a volatile int
2786             "pthread_spinlock_t" => true,
2787 
2788             _ => false,
2789         }
2790     });
2791 
2792     cfg.skip_struct(move |ty| {
2793         if ty.starts_with("__c_anonymous_") {
2794             return true;
2795         }
2796         // FIXME: musl CI has old headers
2797         if (musl || sparc64) && ty.starts_with("uinput_") {
2798             return true;
2799         }
2800         match ty {
2801             // These cannot be tested when "resolv.h" is included and are tested
2802             // in the `linux_elf.rs` file.
2803             "Elf64_Phdr" | "Elf32_Phdr" => true,
2804 
2805             // On Linux, the type of `ut_tv` field of `struct utmpx`
2806             // can be an anonymous struct, so an extra struct,
2807             // which is absent in glibc, has to be defined.
2808             "__timeval" => true,
2809 
2810             // FIXME: This is actually a union, not a struct
2811             "sigval" => true,
2812 
2813             // This type is tested in the `linux_termios.rs` file since there
2814             // are header conflicts when including them with all the other
2815             // structs.
2816             "termios2" => true,
2817 
2818             // FIXME: remove once we set minimum supported glibc version.
2819             // ucontext_t added a new field as of glibc 2.28; our struct definition is
2820             // conservative and omits the field, but that means the size doesn't match for newer
2821             // glibcs (see https://github.com/rust-lang/libc/issues/1410)
2822             "ucontext_t" if gnu => true,
2823 
2824             // FIXME: Somehow we cannot include headers correctly in glibc 2.30.
2825             // So let's ignore for now and re-visit later.
2826             // Probably related: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91085
2827             "statx" => true,
2828             "statx_timestamp" => true,
2829 
2830             // On Linux, the type of `ut_exit` field of struct `utmpx`
2831             // can be an anonymous struct, so an extra struct,
2832             // which is absent in musl, has to be defined.
2833             "__exit_status" if musl => true,
2834 
2835             // FIXME: CI's kernel header version is old.
2836             "sockaddr_can" => true,
2837 
2838             // Requires glibc 2.33 or newer.
2839             "mallinfo2" => true,
2840 
2841             // Might differ between kernel versions
2842             "open_how" => true,
2843 
2844             _ => false,
2845         }
2846     });
2847 
2848     cfg.skip_const(move |name| {
2849         if !gnu {
2850             // Skip definitions from the kernel on non-glibc Linux targets.
2851             // They're libc-independent, so we only need to check them on one
2852             // libc. We don't want to break CI if musl or another libc doesn't
2853             // have the definitions yet. (We do still want to check them on
2854             // every glibc target, though, as some of them can vary by
2855             // architecture.)
2856             //
2857             // This is not an exhaustive list of kernel constants, just a list
2858             // of prefixes of all those that have appeared here or that get
2859             // updated regularly and seem likely to cause breakage.
2860             if name.starts_with("AF_")
2861                 || name.starts_with("ARPHRD_")
2862                 || name.starts_with("EPOLL")
2863                 || name.starts_with("F_")
2864                 || name.starts_with("FALLOC_FL_")
2865                 || name.starts_with("IFLA_")
2866                 || name.starts_with("MS_")
2867                 || name.starts_with("MSG_")
2868                 || name.starts_with("P_")
2869                 || name.starts_with("PF_")
2870                 || name.starts_with("RLIMIT_")
2871                 || name.starts_with("SOL_")
2872                 || name.starts_with("STATX_")
2873                 || name.starts_with("SW_")
2874                 || name.starts_with("SYS_")
2875                 || name.starts_with("TCP_")
2876                 || name.starts_with("UINPUT_")
2877                 || name.starts_with("VMADDR_")
2878             {
2879                 return true;
2880             }
2881         }
2882         match name {
2883             // These constants are not available if gnu headers have been included
2884             // and can therefore not be tested here
2885             //
2886             // The IPV6 constants are tested in the `linux_ipv6.rs` tests:
2887             | "IPV6_FLOWINFO"
2888             | "IPV6_FLOWLABEL_MGR"
2889             | "IPV6_FLOWINFO_SEND"
2890             | "IPV6_FLOWINFO_FLOWLABEL"
2891             | "IPV6_FLOWINFO_PRIORITY"
2892             // The F_ fnctl constants are tested in the `linux_fnctl.rs` tests:
2893             | "F_CANCELLK"
2894             | "F_ADD_SEALS"
2895             | "F_GET_SEALS"
2896             | "F_SEAL_SEAL"
2897             | "F_SEAL_SHRINK"
2898             | "F_SEAL_GROW"
2899             | "F_SEAL_WRITE" => true,
2900             // The `ARPHRD_CAN` is tested in the `linux_if_arp.rs` tests
2901             // because including `linux/if_arp.h` causes some conflicts:
2902             "ARPHRD_CAN" => true,
2903 
2904             // Require Linux kernel 5.1:
2905             "F_SEAL_FUTURE_WRITE" => true,
2906 
2907             // FIXME: deprecated: not available in any header
2908             // See: https://github.com/rust-lang/libc/issues/1356
2909             "ENOATTR" => true,
2910 
2911             // FIXME: SIGUNUSED was removed in glibc 2.26
2912             // Users should use SIGSYS instead.
2913             "SIGUNUSED" => true,
2914 
2915             // FIXME: conflicts with glibc headers and is tested in
2916             // `linux_termios.rs` below:
2917             | "BOTHER"
2918             | "TCGETS2"
2919             | "TCSETS2"
2920             | "TCSETSW2"
2921             | "TCSETSF2" => true,
2922 
2923             // FIXME: on musl the pthread types are defined a little differently
2924             // - these constants are used by the glibc implementation.
2925             n if musl && n.contains("__SIZEOF_PTHREAD") => true,
2926 
2927             // FIXME: It was extended to 4096 since glibc 2.31 (Linux 5.4).
2928             // We should do so after a while.
2929             "SOMAXCONN" if gnu => true,
2930 
2931             // deprecated: not available from Linux kernel 5.6:
2932             "VMADDR_CID_RESERVED" => true,
2933 
2934             // Require Linux kernel 5.6:
2935             "VMADDR_CID_LOCAL" => true,
2936 
2937             // Requires Linux kernel 5.7:
2938             "MREMAP_DONTUNMAP" => true,
2939 
2940             // IPPROTO_MAX was increased in 5.6 for IPPROTO_MPTCP:
2941             | "IPPROTO_MAX"
2942             | "IPPROTO_MPTCP" => true,
2943 
2944             // FIXME: Not currently available in headers
2945             "P_PIDFD" if mips => true,
2946             "SYS_pidfd_open" if mips => true,
2947 
2948             // FIXME: Not currently available in headers on MIPS
2949             // Not yet implemented on sparc64
2950             "SYS_clone3" if mips | sparc64 => true,
2951 
2952             // FIXME: these syscalls were added in Linux 5.9 or later
2953             // and are currently not included in the glibc headers.
2954             | "SYS_close_range"
2955             | "SYS_openat2"
2956             | "SYS_pidfd_getfd"
2957             | "SYS_faccessat2"
2958             | "SYS_process_madvise"
2959             | "SYS_epoll_pwait2"
2960             | "SYS_mount_setattr" => true,
2961 
2962             // Requires more recent kernel headers:
2963             | "IFLA_PROP_LIST"
2964             | "IFLA_ALT_IFNAME"
2965             | "IFLA_PERM_ADDRESS"
2966             | "IFLA_PROTO_DOWN_REASON" => true,
2967 
2968             // FIXME: They require recent kernel header:
2969             | "CAN_J1939"
2970             | "CAN_RAW_FILTER_MAX"
2971             | "CAN_NPROTO" => true,
2972 
2973             // FIXME: Requires recent kernel headers (5.8):
2974             "STATX_MNT_ID" => true,
2975 
2976             // FIXME: requires more recent kernel headers on CI
2977             | "UINPUT_VERSION"
2978             | "SW_MAX"
2979             | "SW_CNT"
2980                 if mips || ppc64 || riscv64 || sparc64 => true,
2981 
2982             // FIXME: Requires more recent kernel headers (5.9 / 5.11):
2983             | "CLOSE_RANGE_UNSHARE"
2984             | "CLOSE_RANGE_CLOEXEC" => true,
2985 
2986             // FIXME: requires more recent kernel headers:
2987             | "RESOLVE_BENEATH"
2988             | "RESOLVE_CACHED"
2989             | "RESOLVE_IN_ROOT"
2990             | "RESOLVE_NO_MAGICLINKS"
2991             | "RESOLVE_NO_SYMLINKS"
2992             | "RESOLVE_NO_XDEV" => true,
2993 
2994             // FIXME: Not currently available in headers on ARM, MIPS and musl.
2995             "NETLINK_GET_STRICT_CHK" if arm || mips || musl => true,
2996 
2997             // kernel constants not available in uclibc 1.0.34
2998             | "ADDR_COMPAT_LAYOUT"
2999             | "ADDR_LIMIT_3GB"
3000             | "ADDR_NO_RANDOMIZE"
3001             | "CLONE_NEWCGROUP"
3002             | "EXTPROC"
3003             | "FAN_MARK_FILESYSTEM"
3004             | "FAN_MARK_INODE"
3005             | "IPPROTO_BEETPH"
3006             | "IPPROTO_MPLS"
3007             | "IPV6_HDRINCL"
3008             | "IPV6_MULTICAST_ALL"
3009             | "IPV6_PMTUDISC_INTERFACE"
3010             | "IPV6_PMTUDISC_OMIT"
3011             | "IPV6_ROUTER_ALERT_ISOLATE"
3012             | "O_TMPFILE"
3013             | "PACKET_MR_UNICAST"
3014             | "PTRACE_EVENT_STOP"
3015             | "PTRACE_O_EXITKILL"
3016             | "PTRACE_O_SUSPEND_SECCOMP"
3017             | "PTRACE_PEEKSIGINFO"
3018             | "READ_IMPLIES_EXEC"
3019             | "RUSAGE_THREAD"
3020             | "SHM_EXEC"
3021             | "UDP_GRO"
3022             | "UDP_SEGMENT"
3023                 if uclibc => true,
3024 
3025             _ => false,
3026         }
3027     });
3028 
3029     cfg.skip_fn(move |name| {
3030         // skip those that are manually verified
3031         match name {
3032             // FIXME: https://github.com/rust-lang/libc/issues/1272
3033             "execv" | "execve" | "execvp" | "execvpe" | "fexecve" => true,
3034 
3035             // There are two versions of the sterror_r function, see
3036             //
3037             // https://linux.die.net/man/3/strerror_r
3038             //
3039             // An XSI-compliant version provided if:
3040             //
3041             // (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
3042             //  && ! _GNU_SOURCE
3043             //
3044             // and a GNU specific version provided if _GNU_SOURCE is defined.
3045             //
3046             // libc provides bindings for the XSI-compliant version, which is
3047             // preferred for portable applications.
3048             //
3049             // We skip the test here since here _GNU_SOURCE is defined, and
3050             // test the XSI version below.
3051             "strerror_r" => true,
3052 
3053             // FIXME: Our API is unsound. The Rust API allows aliasing
3054             // pointers, but the C API requires pointers not to alias.
3055             // We should probably be at least using `&`/`&mut` here, see:
3056             // https://github.com/gnzlbg/ctest/issues/68
3057             "lio_listio" if musl => true,
3058 
3059             // FIXME: the glibc version used by the Sparc64 build jobs
3060             // which use Debian 10.0 is too old.
3061             "statx" if sparc64 => true,
3062 
3063             // FIXME: Deprecated since glibc 2.30. Remove fn once upstream does.
3064             "sysctl" if gnu => true,
3065 
3066             // FIXME: It now takes c_void instead of timezone since glibc 2.31.
3067             "gettimeofday" if gnu => true,
3068 
3069             // These are all implemented as static inline functions in uclibc, so
3070             // they cannot be linked against.
3071             // If implementations are required, they might need to be implemented
3072             // in this crate.
3073             "posix_spawnattr_init" if uclibc => true,
3074             "posix_spawnattr_destroy" if uclibc => true,
3075             "posix_spawnattr_getsigdefault" if uclibc => true,
3076             "posix_spawnattr_setsigdefault" if uclibc => true,
3077             "posix_spawnattr_getsigmask" if uclibc => true,
3078             "posix_spawnattr_setsigmask" if uclibc => true,
3079             "posix_spawnattr_getflags" if uclibc => true,
3080             "posix_spawnattr_setflags" if uclibc => true,
3081             "posix_spawnattr_getpgroup" if uclibc => true,
3082             "posix_spawnattr_setpgroup" if uclibc => true,
3083             "posix_spawnattr_getschedpolicy" if uclibc => true,
3084             "posix_spawnattr_setschedpolicy" if uclibc => true,
3085             "posix_spawnattr_getschedparam" if uclibc => true,
3086             "posix_spawnattr_setschedparam" if uclibc => true,
3087             "posix_spawn_file_actions_init" if uclibc => true,
3088             "posix_spawn_file_actions_destroy" if uclibc => true,
3089 
3090             // uclibc defines the flags type as a uint, but dependent crates
3091             // assume it's a int instead.
3092             "getnameinfo" if uclibc => true,
3093 
3094             // FIXME: This needs musl 1.2.2 or later.
3095             "gettid" if musl => true,
3096 
3097             // Needs glibc 2.33 or later.
3098             "mallinfo2" => true,
3099 
3100             "reallocarray" if musl => true,
3101 
3102             // Not defined in uclibc as of 1.0.34
3103             "gettid" if uclibc => true,
3104 
3105             _ => false,
3106         }
3107     });
3108 
3109     cfg.skip_field_type(move |struct_, field| {
3110         // This is a weird union, don't check the type.
3111         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
3112         // sighandler_t type is super weird
3113         (struct_ == "sigaction" && field == "sa_sigaction") ||
3114         // __timeval type is a patch which doesn't exist in glibc
3115         (struct_ == "utmpx" && field == "ut_tv") ||
3116         // sigval is actually a union, but we pretend it's a struct
3117         (struct_ == "sigevent" && field == "sigev_value") ||
3118         // this one is an anonymous union
3119         (struct_ == "ff_effect" && field == "u") ||
3120         // `__exit_status` type is a patch which is absent in musl
3121         (struct_ == "utmpx" && field == "ut_exit" && musl) ||
3122         // `can_addr` is an anonymous union
3123         (struct_ == "sockaddr_can" && field == "can_addr")
3124     });
3125 
3126     cfg.volatile_item(|i| {
3127         use ctest::VolatileItemKind::*;
3128         match i {
3129             // aio_buf is a volatile void** but since we cannot express that in
3130             // Rust types, we have to explicitly tell the checker about it here:
3131             StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
3132             _ => false,
3133         }
3134     });
3135 
3136     cfg.skip_field(move |struct_, field| {
3137         // this is actually a union on linux, so we can't represent it well and
3138         // just insert some padding.
3139         (struct_ == "siginfo_t" && field == "_pad") ||
3140         // musl names this __dummy1 but it's still there
3141         (musl && struct_ == "glob_t" && field == "gl_flags") ||
3142         // musl seems to define this as an *anonymous* bitfield
3143         (musl && struct_ == "statvfs" && field == "__f_unused") ||
3144         // sigev_notify_thread_id is actually part of a sigev_un union
3145         (struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
3146         // signalfd had SIGSYS fields added in Linux 4.18, but no libc release
3147         // has them yet.
3148         (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" ||
3149                                            field == "_pad2" ||
3150                                            field == "ssi_syscall" ||
3151                                            field == "ssi_call_addr" ||
3152                                            field == "ssi_arch")) ||
3153         // FIXME: After musl 1.1.24, it have only one field `sched_priority`,
3154         // while other fields become reserved.
3155         (struct_ == "sched_param" && [
3156             "sched_ss_low_priority",
3157             "sched_ss_repl_period",
3158             "sched_ss_init_budget",
3159             "sched_ss_max_repl",
3160         ].contains(&field) && musl) ||
3161         // FIXME: After musl 1.1.24, the type becomes `int` instead of `unsigned short`.
3162         (struct_ == "ipc_perm" && field == "__seq" && aarch64_musl) ||
3163         // glibc uses unnamed fields here and Rust doesn't support that yet
3164         (struct_ == "timex" && field.starts_with("__unused")) ||
3165         // FIXME: It now takes mode_t since glibc 2.31 on some targets.
3166         (struct_ == "ipc_perm" && field == "mode"
3167             && ((x86_64 || i686 || arm || riscv64) && gnu || x86_64_gnux32)
3168         )
3169     });
3170 
3171     cfg.skip_roundtrip(move |s| match s {
3172         // FIXME:
3173         "utsname" if mips32 || mips64 => true,
3174         // FIXME:
3175         "mcontext_t" if s390x => true,
3176         // FIXME: This is actually a union.
3177         "fpreg_t" if s390x => true,
3178 
3179         "sockaddr_un" | "sembuf" | "ff_constant_effect" if mips32 && (gnu || musl) => true,
3180         "ipv6_mreq"
3181         | "ip_mreq_source"
3182         | "sockaddr_in6"
3183         | "sockaddr_ll"
3184         | "in_pktinfo"
3185         | "arpreq"
3186         | "arpreq_old"
3187         | "sockaddr_un"
3188         | "ff_constant_effect"
3189         | "ff_ramp_effect"
3190         | "ff_condition_effect"
3191         | "Elf32_Ehdr"
3192         | "Elf32_Chdr"
3193         | "ucred"
3194         | "in6_pktinfo"
3195         | "sockaddr_nl"
3196         | "termios"
3197         | "nlmsgerr"
3198             if (mips64 || sparc64) && gnu =>
3199         {
3200             true
3201         }
3202 
3203         // FIXME: the call ABI of max_align_t is incorrect on these platforms:
3204         "max_align_t" if i686 || mips64 || ppc64 => true,
3205 
3206         _ => false,
3207     });
3208 
3209     cfg.generate("../src/lib.rs", "main.rs");
3210 
3211     test_linux_like_apis(target);
3212 }
3213 
3214 // This function tests APIs that are incompatible to test when other APIs
3215 // are included (e.g. because including both sets of headers clashes)
3216 fn test_linux_like_apis(target: &str) {
3217     let musl = target.contains("musl");
3218     let linux = target.contains("linux");
3219     let emscripten = target.contains("emscripten");
3220     let android = target.contains("android");
3221     assert!(linux || android || emscripten);
3222 
3223     if linux || android || emscripten {
3224         // test strerror_r from the `string.h` header
3225         let mut cfg = ctest_cfg();
3226         cfg.skip_type(|_| true).skip_static(|_| true);
3227 
3228         headers! { cfg: "string.h" }
3229         cfg.skip_fn(|f| match f {
3230             "strerror_r" => false,
3231             _ => true,
3232         })
3233         .skip_const(|_| true)
3234         .skip_struct(|_| true);
3235         cfg.generate("../src/lib.rs", "linux_strerror_r.rs");
3236     }
3237 
3238     if linux || android || emscripten {
3239         // test fcntl - see:
3240         // http://man7.org/linux/man-pages/man2/fcntl.2.html
3241         let mut cfg = ctest_cfg();
3242 
3243         if musl {
3244             cfg.header("fcntl.h");
3245         } else {
3246             cfg.header("linux/fcntl.h");
3247         }
3248 
3249         cfg.skip_type(|_| true)
3250             .skip_static(|_| true)
3251             .skip_struct(|_| true)
3252             .skip_fn(|_| true)
3253             .skip_const(move |name| match name {
3254                 // test fcntl constants:
3255                 "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" | "F_SEAL_SEAL" | "F_SEAL_SHRINK"
3256                 | "F_SEAL_GROW" | "F_SEAL_WRITE" => false,
3257                 _ => true,
3258             })
3259             .type_name(move |ty, is_struct, is_union| match ty {
3260                 t if is_struct => format!("struct {}", t),
3261                 t if is_union => format!("union {}", t),
3262                 t => t.to_string(),
3263             });
3264 
3265         cfg.generate("../src/lib.rs", "linux_fcntl.rs");
3266     }
3267 
3268     if linux || android {
3269         // test termios
3270         let mut cfg = ctest_cfg();
3271         cfg.header("asm/termbits.h");
3272         cfg.header("linux/termios.h");
3273         cfg.skip_type(|_| true)
3274             .skip_static(|_| true)
3275             .skip_fn(|_| true)
3276             .skip_const(|c| match c {
3277                 "BOTHER" => false,
3278                 "TCGETS2" | "TCSETS2" | "TCSETSW2" | "TCSETSF2" => false,
3279                 _ => true,
3280             })
3281             .skip_struct(|s| s != "termios2")
3282             .type_name(move |ty, is_struct, is_union| match ty {
3283                 t if is_struct => format!("struct {}", t),
3284                 t if is_union => format!("union {}", t),
3285                 t => t.to_string(),
3286             });
3287         cfg.generate("../src/lib.rs", "linux_termios.rs");
3288     }
3289 
3290     if linux || android {
3291         // test IPV6_ constants:
3292         let mut cfg = ctest_cfg();
3293         headers! {
3294             cfg:
3295             "linux/in6.h"
3296         }
3297         cfg.skip_type(|_| true)
3298             .skip_static(|_| true)
3299             .skip_fn(|_| true)
3300             .skip_const(|_| true)
3301             .skip_struct(|_| true)
3302             .skip_const(move |name| match name {
3303                 "IPV6_FLOWINFO"
3304                 | "IPV6_FLOWLABEL_MGR"
3305                 | "IPV6_FLOWINFO_SEND"
3306                 | "IPV6_FLOWINFO_FLOWLABEL"
3307                 | "IPV6_FLOWINFO_PRIORITY" => false,
3308                 _ => true,
3309             })
3310             .type_name(move |ty, is_struct, is_union| match ty {
3311                 t if is_struct => format!("struct {}", t),
3312                 t if is_union => format!("union {}", t),
3313                 t => t.to_string(),
3314             });
3315         cfg.generate("../src/lib.rs", "linux_ipv6.rs");
3316     }
3317 
3318     if linux || android {
3319         // Test Elf64_Phdr and Elf32_Phdr
3320         // These types have a field called `p_type`, but including
3321         // "resolve.h" defines a `p_type` macro that expands to `__p_type`
3322         // making the tests for these fails when both are included.
3323         let mut cfg = ctest_cfg();
3324         cfg.header("elf.h");
3325         cfg.skip_fn(|_| true)
3326             .skip_static(|_| true)
3327             .skip_const(|_| true)
3328             .type_name(move |ty, _is_struct, _is_union| ty.to_string())
3329             .skip_struct(move |ty| match ty {
3330                 "Elf64_Phdr" | "Elf32_Phdr" => false,
3331                 _ => true,
3332             })
3333             .skip_type(move |ty| match ty {
3334                 "Elf64_Phdr" | "Elf32_Phdr" => false,
3335                 _ => true,
3336             });
3337         cfg.generate("../src/lib.rs", "linux_elf.rs");
3338     }
3339 
3340     if linux || android {
3341         // Test `ARPHRD_CAN`.
3342         let mut cfg = ctest_cfg();
3343         cfg.header("linux/if_arp.h");
3344         cfg.skip_fn(|_| true)
3345             .skip_static(|_| true)
3346             .skip_const(move |name| match name {
3347                 "ARPHRD_CAN" => false,
3348                 _ => true,
3349             })
3350             .skip_struct(|_| true)
3351             .skip_type(|_| true);
3352         cfg.generate("../src/lib.rs", "linux_if_arp.rs");
3353     }
3354 }
3355 
3356 fn which_freebsd() -> Option<i32> {
3357     let output = std::process::Command::new("freebsd-version")
3358         .output()
3359         .ok()?;
3360     if !output.status.success() {
3361         return None;
3362     }
3363 
3364     let stdout = String::from_utf8(output.stdout).ok()?;
3365 
3366     match &stdout {
3367         s if s.starts_with("10") => Some(10),
3368         s if s.starts_with("11") => Some(11),
3369         s if s.starts_with("12") => Some(12),
3370         s if s.starts_with("13") => Some(13),
3371         _ => None,
3372     }
3373 }
3374 
3375 fn test_haiku(target: &str) {
3376     assert!(target.contains("haiku"));
3377 
3378     let mut cfg = ctest_cfg();
3379     cfg.flag("-Wno-deprecated-declarations");
3380     cfg.define("__USE_GNU", Some("1"));
3381 
3382     // POSIX API
3383     headers! { cfg:
3384                "alloca.h",
3385                "arpa/inet.h",
3386                "arpa/nameser.h",
3387                "arpa/nameser_compat.h",
3388                "assert.h",
3389                "bsd_mem.h",
3390                "complex.h",
3391                "ctype.h",
3392                "dirent.h",
3393                "div_t.h",
3394                "dlfcn.h",
3395                "endian.h",
3396                "errno.h",
3397                "fcntl.h",
3398                "fenv.h",
3399                "fnmatch.h",
3400                "fts.h",
3401                "ftw.h",
3402                "getopt.h",
3403                "glob.h",
3404                "grp.h",
3405                "inttypes.h",
3406                "iovec.h",
3407                "langinfo.h",
3408                "libgen.h",
3409                "libio.h",
3410                "limits.h",
3411                "locale.h",
3412                "malloc.h",
3413                "malloc_debug.h",
3414                "math.h",
3415                "memory.h",
3416                "monetary.h",
3417                "net/if.h",
3418                "net/if_dl.h",
3419                "net/if_media.h",
3420                "net/if_tun.h",
3421                "net/if_types.h",
3422                "net/route.h",
3423                "netdb.h",
3424                "netinet/icmp6.h",
3425                "netinet/in.h",
3426                "netinet/ip.h",
3427                "netinet/ip6.h",
3428                "netinet/ip_icmp.h",
3429                "netinet/ip_var.h",
3430                "netinet/tcp.h",
3431                "netinet/udp.h",
3432                "netinet6/in6.h",
3433                "nl_types.h",
3434                "null.h",
3435                "poll.h",
3436                "pthread.h",
3437                "pwd.h",
3438                "regex.h",
3439                "resolv.h",
3440                "sched.h",
3441                "search.h",
3442                "semaphore.h",
3443                "setjmp.h",
3444                "shadow.h",
3445                "signal.h",
3446                "size_t.h",
3447                "spawn.h",
3448                "stdint.h",
3449                "stdio.h",
3450                "stdlib.h",
3451                "string.h",
3452                "strings.h",
3453                "sys/cdefs.h",
3454                "sys/file.h",
3455                "sys/ioctl.h",
3456                "sys/ipc.h",
3457                "sys/mman.h",
3458                "sys/msg.h",
3459                "sys/param.h",
3460                "sys/poll.h",
3461                "sys/resource.h",
3462                "sys/select.h",
3463                "sys/sem.h",
3464                "sys/socket.h",
3465                "sys/sockio.h",
3466                "sys/stat.h",
3467                "sys/statvfs.h",
3468                "sys/time.h",
3469                "sys/timeb.h",
3470                "sys/times.h",
3471                "sys/types.h",
3472                "sys/uio.h",
3473                "sys/un.h",
3474                "sys/utsname.h",
3475                "sys/wait.h",
3476                "syslog.h",
3477                "tar.h",
3478                "termios.h",
3479                "time.h",
3480                "uchar.h",
3481                "unistd.h",
3482                "utime.h",
3483                "wchar.h",
3484                "wchar_t.h",
3485                "wctype.h"
3486     }
3487 
3488     // BSD Extensions
3489     headers! { cfg:
3490                "pty.h",
3491     }
3492 
3493     // Native API
3494     headers! { cfg:
3495                "kernel/OS.h",
3496                "kernel/fs_attr.h",
3497                "kernel/fs_index.h",
3498                "kernel/fs_info.h",
3499                "kernel/fs_query.h",
3500                "kernel/fs_volume.h",
3501                "kernel/image.h",
3502                "kernel/scheduler.h",
3503                "storage/FindDirectory.h",
3504                "storage/StorageDefs.h",
3505                "support/Errors.h",
3506                "support/SupportDefs.h",
3507                "support/TypeConstants.h"
3508     }
3509 
3510     cfg.skip_struct(move |ty| {
3511         if ty.starts_with("__c_anonymous_") {
3512             return true;
3513         }
3514         match ty {
3515             // FIXME: actually a union
3516             "sigval" => true,
3517             // FIXME: locale_t does not exist on Haiku
3518             "locale_t" => true,
3519             // FIXME: rusage has a different layout on Haiku
3520             "rusage" => true,
3521             // FIXME?: complains that rust aligns on 4 byte boundary, but
3522             //         Haiku does not align it at all.
3523             "in6_addr" => true,
3524             // The d_name attribute is an array of 1 on Haiku, with the
3525             // intention that the developer allocates a larger or smaller
3526             // piece of memory depending on the expected/actual size of the name.
3527             // Other platforms have sensible defaults. In Rust, the d_name field
3528             // is sized as the _POSIX_MAX_PATH, so that path names will fit in
3529             // newly allocated dirent objects. This breaks the automated tests.
3530             "dirent" => true,
3531             // The following structs contain function pointers, which cannot be initialized
3532             // with mem::zeroed(), so skip the automated test
3533             "image_info" | "thread_info" => true,
3534 
3535             _ => false,
3536         }
3537     });
3538 
3539     cfg.skip_type(move |ty| {
3540         match ty {
3541             // FIXME: locale_t does not exist on Haiku
3542             "locale_t" => true,
3543             // These cause errors, to be reviewed in the future
3544             "sighandler_t" => true,
3545             "pthread_t" => true,
3546             "pthread_condattr_t" => true,
3547             "pthread_mutexattr_t" => true,
3548             "pthread_rwlockattr_t" => true,
3549             _ => false,
3550         }
3551     });
3552 
3553     cfg.skip_fn(move |name| {
3554         // skip those that are manually verified
3555         match name {
3556             // FIXME: https://github.com/rust-lang/libc/issues/1272
3557             "execv" | "execve" | "execvp" | "execvpe" => true,
3558             // FIXME: does not exist on haiku
3559             "open_wmemstream" => true,
3560             "mlockall" | "munlockall" => true,
3561             "tcgetsid" => true,
3562             "cfsetspeed" => true,
3563             // ignore for now, will be part of Haiku R1 beta 3
3564             "mlock" | "munlock" => true,
3565             // returns const char * on Haiku
3566             "strsignal" => true,
3567             // uses an enum as a parameter argument, which is incorrectly
3568             // translated into a struct argument
3569             "find_path" => true,
3570 
3571             _ => false,
3572         }
3573     });
3574 
3575     cfg.skip_const(move |name| {
3576         match name {
3577             // FIXME: these constants do not exist on Haiku
3578             "DT_UNKNOWN" | "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK"
3579             | "DT_SOCK" => true,
3580             "USRQUOTA" | "GRPQUOTA" => true,
3581             "SIGIOT" => true,
3582             "ARPOP_REQUEST" | "ARPOP_REPLY" | "ATF_COM" | "ATF_PERM" | "ATF_PUBL"
3583             | "ATF_USETRAILERS" => true,
3584             // Haiku does not have MAP_FILE, but rustc requires it
3585             "MAP_FILE" => true,
3586             // The following does not exist on Haiku but is required by
3587             // several crates
3588             "FIOCLEX" => true,
3589             // just skip this one, it is not defined on Haiku beta 2 but
3590             // since it is meant as a mask and not a parameter it can exist
3591             // here
3592             "LOG_PRIMASK" => true,
3593             // not defined on Haiku, but [get|set]priority is, so they are
3594             // useful
3595             "PRIO_MIN" | "PRIO_MAX" => true,
3596             //
3597             _ => false,
3598         }
3599     });
3600 
3601     cfg.skip_field(move |struct_, field| {
3602         match (struct_, field) {
3603             // FIXME: the stat struct actually has timespec members, whereas
3604             //        the current representation has these unpacked.
3605             ("stat", "st_atime") => true,
3606             ("stat", "st_atime_nsec") => true,
3607             ("stat", "st_mtime") => true,
3608             ("stat", "st_mtime_nsec") => true,
3609             ("stat", "st_ctime") => true,
3610             ("stat", "st_ctime_nsec") => true,
3611             ("stat", "st_crtime") => true,
3612             ("stat", "st_crtime_nsec") => true,
3613 
3614             // these are actually unions, but we cannot represent it well
3615             ("siginfo_t", "sigval") => true,
3616             ("sem_t", "named_sem_id") => true,
3617             ("sigaction", "sa_sigaction") => true,
3618             ("sigevent", "sigev_value") => true,
3619             ("fpu_state", "_fpreg") => true,
3620             // these fields have a simplified data definition in libc
3621             ("fpu_state", "_xmm") => true,
3622             ("savefpu", "_fp_ymm") => true,
3623 
3624             // skip these enum-type fields
3625             ("thread_info", "state") => true,
3626             ("image_info", "image_type") => true,
3627             _ => false,
3628         }
3629     });
3630 
3631     cfg.skip_roundtrip(move |s| match s {
3632         // FIXME: for some reason the roundtrip check fails for cpu_info
3633         "cpu_info" => true,
3634         _ => false,
3635     });
3636 
3637     cfg.type_name(move |ty, is_struct, is_union| {
3638         match ty {
3639             // Just pass all these through, no need for a "struct" prefix
3640             "area_info" | "port_info" | "port_message_info" | "team_info" | "sem_info"
3641             | "team_usage_info" | "thread_info" | "cpu_info" | "system_info"
3642             | "object_wait_info" | "image_info" | "attr_info" | "index_info" | "fs_info"
3643             | "FILE" | "DIR" | "Dl_info" => ty.to_string(),
3644 
3645             // is actually a union
3646             "sigval" => format!("union sigval"),
3647             t if is_union => format!("union {}", t),
3648             t if t.ends_with("_t") => t.to_string(),
3649             t if is_struct => format!("struct {}", t),
3650             t => t.to_string(),
3651         }
3652     });
3653 
3654     cfg.field_name(move |struct_, field| {
3655         match field {
3656             // Field is named `type` in C but that is a Rust keyword,
3657             // so these fields are translated to `type_` in the bindings.
3658             "type_" if struct_ == "object_wait_info" => "type".to_string(),
3659             "type_" if struct_ == "sem_t" => "type".to_string(),
3660             "type_" if struct_ == "attr_info" => "type".to_string(),
3661             "type_" if struct_ == "index_info" => "type".to_string(),
3662             "image_type" if struct_ == "image_info" => "type".to_string(),
3663             s => s.to_string(),
3664         }
3665     });
3666     cfg.generate("../src/lib.rs", "main.rs");
3667 }
3668