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