xref: /rust-libc-0.2.174/libc-test/build.rs (revision 9f1db178)
1 #![deny(warnings)]
2 
3 extern crate cc;
4 extern crate ctest;
5 
6 use std::env;
7 
8 fn do_cc() {
9     let target = env::var("TARGET").unwrap();
10     if cfg!(unix) && !target.contains("wasi") {
11         cc::Build::new().file("src/cmsg.c").compile("cmsg");
12     }
13 }
14 
15 fn do_ctest() {
16     let target = env::var("TARGET").unwrap();
17     let aarch64 = target.contains("aarch64");
18     let i686 = target.contains("i686");
19     let x86_64 = target.contains("x86_64");
20     let x32 = target.ends_with("gnux32");
21     let linux = target.contains("unknown-linux");
22     let android = target.contains("android");
23     let emscripten = target.contains("asm");
24     let musl = target.contains("musl") || emscripten;
25     let uclibc = target.contains("uclibc");
26     let freebsd = target.contains("freebsd");
27     let mips = target.contains("mips");
28     let openbsd = target.contains("openbsd");
29     let bsdlike = freebsd || openbsd;
30     let mut cfg = ctest::TestGenerator::new();
31 
32     match &target {
33         t if t.contains("apple") => return test_apple(t),
34         t if t.contains("openbsd") => return test_openbsd(t),
35         t if t.contains("windows") => return test_windows(t),
36         t if t.contains("redox") => return test_redox(t),
37         t if t.contains("cloudabi") => return test_cloudabi(t),
38         t if t.contains("solaris") => return test_solaris(t),
39         t if t.contains("netbsd") => return test_netbsd(t),
40         t if t.contains("dragonfly") => return test_dragonflybsd(t),
41         t if t.contains("wasi") => return test_wasi(t),
42         _ => (),
43     }
44 
45     // Pull in extra goodies
46     if linux || android || emscripten {
47         cfg.define("_GNU_SOURCE", None);
48     } else if freebsd {
49         cfg.define("_WITH_GETLINE", None);
50     }
51 
52     // Android doesn't actually have in_port_t but it's much easier if we
53     // provide one for us to test against
54     if android {
55         cfg.define("in_port_t", Some("uint16_t"));
56     }
57 
58     cfg.header("errno.h")
59         .header("fcntl.h")
60         .header("limits.h")
61         .header("locale.h")
62         .header("stddef.h")
63         .header("stdint.h")
64         .header("stdio.h")
65         .header("stdlib.h")
66         .header("sys/stat.h")
67         .header("sys/types.h")
68         .header("time.h")
69         .header("wchar.h");
70 
71     cfg.flag("-Wno-deprecated-declarations");
72 
73     cfg.header("ctype.h");
74     cfg.header("dirent.h");
75     cfg.header("net/if.h");
76     cfg.header("net/route.h");
77     cfg.header("net/if_arp.h");
78     if linux || android {
79         cfg.header("linux/if_alg.h");
80     }
81     cfg.header("netdb.h");
82     cfg.header("netinet/in.h");
83     cfg.header("netinet/ip.h");
84     cfg.header("netinet/tcp.h");
85     cfg.header("netinet/udp.h");
86     cfg.header("resolv.h");
87     cfg.header("pthread.h");
88     cfg.header("dlfcn.h");
89     cfg.header("signal.h");
90     cfg.header("string.h");
91     cfg.header("sys/file.h");
92     cfg.header("sys/ioctl.h");
93     cfg.header("sys/mman.h");
94     cfg.header("sys/resource.h");
95     cfg.header("sys/socket.h");
96     if linux && !musl {
97         cfg.header("linux/if.h");
98         cfg.header("sys/auxv.h");
99     }
100     cfg.header("sys/time.h");
101     cfg.header("sys/un.h");
102     cfg.header("sys/wait.h");
103     cfg.header("unistd.h");
104     cfg.header("utime.h");
105     cfg.header("pwd.h");
106     cfg.header("grp.h");
107     cfg.header("sys/utsname.h");
108     cfg.header("sys/ptrace.h");
109     cfg.header("sys/mount.h");
110     cfg.header("sys/uio.h");
111     cfg.header("sched.h");
112     cfg.header("termios.h");
113     cfg.header("poll.h");
114     cfg.header("syslog.h");
115     cfg.header("semaphore.h");
116     cfg.header("sys/statvfs.h");
117     cfg.header("sys/times.h");
118 
119     if android {
120         if !aarch64 && !x86_64 {
121             // time64_t is not define for aarch64 and x86_64
122             // If included it will generate the error 'Your time_t is already 64-bit'
123             cfg.header("time64.h");
124         }
125         cfg.header("arpa/inet.h");
126         cfg.header("xlocale.h");
127         cfg.header("ifaddrs.h");
128         if i686 || x86_64 {
129             cfg.header("sys/reg.h");
130         }
131     } else {
132         cfg.header("glob.h");
133         cfg.header("ifaddrs.h");
134         cfg.header("langinfo.h");
135 
136         if !openbsd && !freebsd {
137             cfg.header("sys/quota.h");
138         }
139 
140         if !musl && !x32 {
141             cfg.header("sys/sysctl.h");
142         }
143 
144         if !musl && !uclibc {
145             if !openbsd && !uclibc {
146                 cfg.header("execinfo.h");
147             }
148 
149             if openbsd {
150                 cfg.header("utmp.h");
151             } else {
152                 cfg.header("utmpx.h");
153             }
154         }
155     }
156 
157     if bsdlike {
158         cfg.header("sys/event.h");
159         cfg.header("net/if_dl.h");
160         if freebsd {
161             cfg.header("net/bpf.h");
162             cfg.header("libutil.h");
163         } else {
164             cfg.header("util.h");
165         }
166     }
167 
168     if linux || emscripten {
169         cfg.header("mntent.h");
170         cfg.header("mqueue.h");
171         cfg.header("ucontext.h");
172         if !uclibc {
173             // optionally included in uclibc
174             cfg.header("sys/xattr.h");
175         }
176         cfg.header("sys/ipc.h");
177         cfg.header("sys/sem.h");
178         cfg.header("sys/msg.h");
179         cfg.header("sys/shm.h");
180         cfg.header("sys/user.h");
181         cfg.header("sys/timerfd.h");
182         cfg.header("shadow.h");
183         if !emscripten {
184             cfg.header("linux/input.h");
185             cfg.header("linux/falloc.h");
186         }
187         if x86_64 {
188             cfg.header("sys/io.h");
189         }
190         if i686 || x86_64 {
191             cfg.header("sys/reg.h");
192         }
193     }
194 
195     if linux || android || emscripten {
196         cfg.header("malloc.h");
197         cfg.header("net/ethernet.h");
198         cfg.header("netpacket/packet.h");
199         cfg.header("sched.h");
200         cfg.header("sys/epoll.h");
201         cfg.header("sys/eventfd.h");
202         cfg.header("sys/prctl.h");
203         cfg.header("sys/sendfile.h");
204         cfg.header("sys/signalfd.h");
205         cfg.header("sys/vfs.h");
206         cfg.header("sys/syscall.h");
207         cfg.header("sys/personality.h");
208         cfg.header("sys/swap.h");
209         cfg.header("pty.h");
210         cfg.header("utmp.h");
211         if !uclibc {
212             cfg.header("sys/sysinfo.h");
213         }
214         cfg.header("sys/reboot.h");
215         if !emscripten {
216             cfg.header("linux/sockios.h");
217             cfg.header("linux/netlink.h");
218             cfg.header("linux/genetlink.h");
219             cfg.header("linux/netfilter_ipv4.h");
220             cfg.header("linux/netfilter_ipv6.h");
221             cfg.header("linux/fs.h");
222         }
223         if !musl {
224             cfg.header("asm/mman.h");
225             cfg.header("linux/magic.h");
226             cfg.header("linux/reboot.h");
227             cfg.header("linux/netfilter/nf_tables.h");
228 
229             if !mips {
230                 cfg.header("linux/quota.h");
231             }
232         }
233     }
234 
235     if linux || android {
236         cfg.header("sys/fsuid.h");
237         cfg.header("linux/module.h");
238         cfg.header("linux/seccomp.h");
239         cfg.header("linux/if_ether.h");
240         cfg.header("linux/if_tun.h");
241         cfg.header("linux/net_tstamp.h");
242         cfg.header("sys/inotify.h");
243 
244         // DCCP support
245         if !uclibc && !musl && !emscripten {
246             cfg.header("linux/dccp.h");
247         }
248 
249         if !musl || mips {
250             cfg.header("linux/memfd.h");
251         }
252     }
253 
254     if linux {
255         cfg.header("linux/random.h");
256         cfg.header("elf.h");
257         cfg.header("link.h");
258         cfg.header("spawn.h");
259     }
260 
261     if freebsd {
262         cfg.header("mqueue.h");
263         cfg.header("pthread_np.h");
264         cfg.header("sched.h");
265         cfg.header("ufs/ufs/quota.h");
266         cfg.header("sys/extattr.h");
267         cfg.header("sys/jail.h");
268         cfg.header("sys/ipc.h");
269         cfg.header("sys/msg.h");
270         cfg.header("sys/shm.h");
271         cfg.header("sys/procdesc.h");
272         cfg.header("sys/rtprio.h");
273         cfg.header("spawn.h");
274     }
275 
276     if openbsd {
277         cfg.header("ufs/ufs/quota.h");
278         cfg.header("pthread_np.h");
279         cfg.header("sys/syscall.h");
280     }
281 
282     if linux || freebsd || emscripten {
283         if !uclibc {
284             cfg.header("aio.h");
285         }
286     }
287 
288     cfg.type_name(move |ty, is_struct, is_union| {
289         match ty {
290             // Just pass all these through, no need for a "struct" prefix
291             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr"
292             | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym"
293             | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr"
294             | "Elf64_Chdr" => ty.to_string(),
295 
296             // OSX calls this something else
297             "sighandler_t" if bsdlike => "sig_t".to_string(),
298 
299             t if is_union => format!("union {}", t),
300 
301             t if t.ends_with("_t") => t.to_string(),
302 
303             // put `struct` in front of all structs:.
304             t if is_struct => format!("struct {}", t),
305 
306             t => t.to_string(),
307         }
308     });
309 
310     let target2 = target.clone();
311     cfg.field_name(move |struct_, field| {
312         match field {
313             "st_birthtime" if openbsd && struct_ == "stat" => {
314                 "__st_birthtime".to_string()
315             }
316             "st_birthtime_nsec" if openbsd && struct_ == "stat" => {
317                 "__st_birthtimensec".to_string()
318             }
319             // Our stat *_nsec fields normally don't actually exist but are part
320             // of a timeval struct
321             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
322                 if target2.contains("android") {
323                     s.to_string()
324                 } else {
325                     s.replace("e_nsec", ".tv_nsec")
326                 }
327             }
328             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
329             "type_"
330                 if (linux || freebsd)
331                     && (struct_ == "input_event"
332                         || struct_ == "input_mask"
333                         || struct_ == "ff_effect"
334                         || struct_ == "rtprio") =>
335             {
336                 "type".to_string()
337             }
338             s => s.to_string(),
339         }
340     });
341 
342     cfg.skip_type(move |ty| {
343         match ty {
344             // sighandler_t is crazy across platforms
345             "sighandler_t" => true,
346 
347             _ => false,
348         }
349     });
350 
351     cfg.skip_struct(move |ty| {
352         match ty {
353             "sockaddr_nl" => musl,
354 
355             // On Linux, the type of `ut_tv` field of `struct utmpx`
356             // can be an anonymous struct, so an extra struct,
357             // which is absent in glibc, has to be defined.
358             "__timeval" if linux => true,
359 
360             // This is actually a union, not a struct
361             "sigval" => true,
362 
363             // Linux kernel headers used on musl are too old to have this
364             // definition. Because it's tested on other Linux targets, skip it.
365             "input_mask" if musl => true,
366 
367             // These structs have changed since unified headers in NDK r14b.
368             // `st_atime` and `st_atime_nsec` have changed sign.
369             // FIXME: unskip it for next major release
370             "stat" | "stat64" if android => true,
371 
372             // These are tested as part of the linux_fcntl tests since there are
373             // header conflicts when including them with all the other structs.
374             "termios2" => true,
375 
376             _ => false,
377         }
378     });
379 
380     cfg.skip_signededness(move |c| {
381         match c {
382             "LARGE_INTEGER" | "float" | "double" => true,
383             n if n.starts_with("pthread") => true,
384             // sem_t is a struct or pointer
385             "sem_t" if openbsd || freebsd => true,
386             // mqd_t is a pointer on FreeBSD
387             "mqd_t" if freebsd => true,
388 
389             _ => false,
390         }
391     });
392 
393     cfg.skip_const(move |name| {
394         match name {
395             "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness
396             "SIGUNUSED" => true,                       // removed in glibc 2.26
397 
398             // types on musl are defined a little differently
399             n if musl && n.contains("__SIZEOF_PTHREAD") => true,
400 
401             // Skip constants not defined in MUSL but just passed down to the
402             // kernel regardless
403             "RLIMIT_NLIMITS"
404             | "TCP_COOKIE_TRANSACTIONS"
405             | "RLIMIT_RTTIME"
406             | "MSG_COPY"
407                 if musl =>
408             {
409                 true
410             }
411             // work around super old mips toolchain
412             "SCHED_IDLE" | "SHM_NORESERVE" => mips,
413 
414             // weird signed extension or something like that?
415             "MS_NOUSER" => true,
416             "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13
417 
418             // These constants were removed in FreeBSD 11 (svn r273250) but will
419             // still be accepted and ignored at runtime.
420             "MAP_RENAME" | "MAP_NORESERVE" if freebsd => true,
421 
422             // These constants were removed in FreeBSD 11 (svn r262489),
423             // and they've never had any legitimate use outside of the
424             // base system anyway.
425             "CTL_MAXID" | "KERN_MAXID" | "HW_MAXID" | "NET_MAXID"
426             | "USER_MAXID"
427                 if freebsd =>
428             {
429                 true
430             }
431 
432             // These constants were added in FreeBSD 11
433             "EVFILT_PROCDESC" | "EVFILT_SENDFILE" | "EVFILT_EMPTY"
434             | "PD_CLOEXEC" | "PD_ALLOWED_AT_FORK"
435                 if freebsd =>
436             {
437                 true
438             }
439 
440             // These constants were added in FreeBSD 12
441             "SF_USER_READAHEAD" | "SO_REUSEPORT_LB" if freebsd => true,
442 
443             // These constants were removed in OpenBSD 6 (https://git.io/v7gBO
444             // https://git.io/v7gBq)
445             "KERN_USERMOUNT" | "KERN_ARND" if openbsd => true,
446 
447             // These are either unimplemented or optionally built into uClibc
448             "LC_CTYPE_MASK"
449             | "LC_NUMERIC_MASK"
450             | "LC_TIME_MASK"
451             | "LC_COLLATE_MASK"
452             | "LC_MONETARY_MASK"
453             | "LC_MESSAGES_MASK"
454             | "MADV_MERGEABLE"
455             | "MADV_UNMERGEABLE"
456             | "MADV_HWPOISON"
457             | "IPV6_ADD_MEMBERSHIP"
458             | "IPV6_DROP_MEMBERSHIP"
459             | "IPV6_MULTICAST_LOOP"
460             | "IPV6_V6ONLY"
461             | "MAP_STACK"
462             | "RTLD_DEEPBIND"
463             | "SOL_IPV6"
464             | "SOL_ICMPV6"
465                 if uclibc =>
466             {
467                 true
468             }
469 
470             // Musl uses old, patched kernel headers
471             "FALLOC_FL_COLLAPSE_RANGE"
472             | "FALLOC_FL_ZERO_RANGE"
473             | "FALLOC_FL_INSERT_RANGE"
474             | "FALLOC_FL_UNSHARE_RANGE"
475             | "RENAME_NOREPLACE"
476             | "RENAME_EXCHANGE"
477             | "RENAME_WHITEOUT"
478             // ALG_SET_AEAD_* constants are available starting from kernel 3.19
479             | "ALG_SET_AEAD_ASSOCLEN"
480             | "ALG_SET_AEAD_AUTHSIZE"
481                 if musl =>
482             {
483                 true
484             }
485 
486             // Both android and musl use old kernel headers
487             // These are constants used in getrandom syscall
488             "GRND_NONBLOCK" | "GRND_RANDOM" if musl || android => true,
489 
490             // Defined by libattr not libc on linux (hard to test).
491             // See constant definition for more details.
492             "ENOATTR" if android || linux => true,
493 
494             // On mips*-unknown-linux-gnu* CMSPAR cannot be included with the set of headers we
495             // want to use here for testing. It's originally defined in asm/termbits.h, which is
496             // also included by asm/termios.h, but not the standard termios.h. There's no way to
497             // include both asm/termbits.h and termios.h and there's no way to include both
498             // asm/termios.h and ioctl.h (+ some other headers) because of redeclared types.
499             "CMSPAR" if mips && linux && !musl => true,
500 
501             // On mips Linux targets, MADV_SOFT_OFFLINE is currently missing, though it's been added but CI has too old
502             // of a Linux version. Since it exists on all other Linux targets, just ignore this for now and remove once
503             // it's been fixed in CI.
504             "MADV_SOFT_OFFLINE" if mips && linux => true,
505 
506             // These constants are tested in a separate test program generated below because there
507             // are header conflicts if we try to include the headers that define them here.
508             "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => true,
509             "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW"
510             | "F_SEAL_WRITE" => true,
511             "QFMT_VFS_OLD" | "QFMT_VFS_V0" | "QFMT_VFS_V1"
512                 if mips && linux =>
513             {
514                 true
515             } // Only on MIPS
516             "BOTHER" => true,
517 
518             "MFD_CLOEXEC" | "MFD_ALLOW_SEALING" if !mips && musl => true,
519             // MFD_HUGETLB is not available in some older libc versions on the CI builders. On the
520             // x86_64 and i686 builders it seems to be available for all targets, so at least test
521             // it there.
522             "MFD_HUGETLB"
523                 if !(x86_64 || i686) || musl || (x86_64 && android) =>
524             {
525                 true
526             }
527 
528             // These are defined for Solaris 11, but the crate is tested on
529             // illumos, where they are currently not defined
530             "EADI"
531             | "PORT_SOURCE_POSTWAIT"
532             | "PORT_SOURCE_SIGNAL"
533             | "PTHREAD_STACK_MIN" => true,
534 
535             // These change all the time from release to release of linux
536             // distros, let's just not bother trying to verify them. They
537             // shouldn't be used in code anyway...
538             "AF_MAX" | "PF_MAX" => true,
539 
540             // These are not in a glibc release yet, only in kernel headers.
541             "AF_XDP"
542             | "PF_XDP"
543             | "SOL_XDP"
544             | "IPV6_FLOWINFO"
545             | "IPV6_FLOWLABEL_MGR"
546             | "IPV6_FLOWINFO_SEND"
547             | "IPV6_FLOWINFO_FLOWLABEL"
548             | "IPV6_FLOWINFO_PRIORITY"
549                 if linux =>
550             {
551                 true
552             }
553 
554             | "IP_ORIGDSTADDR"
555             | "IP_RECVORIGDSTADDR"
556             | "IPV6_ORIGDSTADDR"
557             | "IPV6_RECVORIGDSTADDR"
558                 if freebsd =>
559             {
560                 // FreeBSD 12 required, but CI has FreeBSD 11.
561                 true
562             }
563 
564             _ => false,
565         }
566     });
567 
568     cfg.skip_fn(move |name| {
569         // skip those that are manually verified
570         match name {
571             "execv" |       // crazy stuff with const/mut
572             "execve" |
573             "execvp" |
574             "execvpe" |
575             "fexecve" => true,
576 
577             "getrlimit" | "getrlimit64" |    // non-int in 1st arg
578             "setrlimit" | "setrlimit64" |    // non-int in 1st arg
579             "prlimit" | "prlimit64" |        // non-int in 2nd arg
580             "strerror_r" if linux => true,   // actually xpg-something-or-other
581 
582             // int vs uint. Sorry musl, your prototype declarations are "correct" in the sense that
583             // they match the interface defined by Linux verbatim, but they conflict with other
584             // send*/recv* syscalls
585             "sendmmsg" | "recvmmsg" if musl => true,
586 
587             // typed 2nd arg on linux and android
588             "gettimeofday" if linux || android || freebsd || openbsd => true,
589 
590             // not declared in newer android toolchains
591             "getdtablesize" if android => true,
592 
593             "dlerror" if android => true, // const-ness is added
594             "dladdr" if musl => true, // const-ness only added recently
595 
596             // There seems to be a small error in EGLIBC's eventfd.h header. The
597             // [underlying system call][1] always takes its first `count`
598             // argument as an `unsigned int`, but [EGLIBC's <sys/eventfd.h>
599             // header][2] declares it to take an `int`. [GLIBC's header][3]
600             // matches the kernel.
601             //
602             // EGLIBC is no longer actively developed, and Debian, the largest
603             // distribution that had been using it, switched back to GLIBC in
604             // April 2015. So effectively all Linux <sys/eventfd.h> headers will
605             // be using `unsigned int` soon.
606             //
607             // [1]: https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/fs/eventfd.c?id=refs/tags/v3.12.51#n397
608             // [2]: http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/eglibc/trusty/view/head:/sysdeps/unix/sysv/linux/sys/eventfd.h
609             // [3]: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sys/eventfd.h;h=6295f32e937e779e74318eb9d3bdbe76aef8a8f3;hb=4e42b5b8f89f0e288e68be7ad70f9525aebc2cff#l34
610             "eventfd" if linux => true,
611 
612             // The `uname` function in freebsd is now an inline wrapper that
613             // delegates to another, but the symbol still exists, so don't check
614             // the symbol.
615             "uname" if freebsd => true,
616 
617             // FIXME: need to upgrade FreeBSD version; see https://github.com/rust-lang/libc/issues/938
618             "setgrent" if freebsd => true,
619 
620             // aio_waitcomplete's return type changed between FreeBSD 10 and 11.
621             "aio_waitcomplete" if freebsd => true,
622 
623             // lio_listio confuses the checker, probably because one of its
624             // arguments is an array
625             "lio_listio" if freebsd => true,
626             "lio_listio" if musl => true,
627 
628             // Apparently the NDK doesn't have this defined on android, but
629             // it's in a header file?
630             "endpwent" if android => true,
631 
632             // These are either unimplemented or optionally built into uClibc
633             // or "sysinfo", where it's defined but the structs in linux/sysinfo.h and sys/sysinfo.h
634             // clash so it can't be tested
635             "getxattr" | "lgetxattr" | "fgetxattr" | "setxattr" | "lsetxattr" | "fsetxattr" |
636             "listxattr" | "llistxattr" | "flistxattr" | "removexattr" | "lremovexattr" |
637             "fremovexattr" |
638             "backtrace" |
639             "sysinfo" | "newlocale" | "duplocale" | "freelocale" | "uselocale" |
640             "nl_langinfo_l" | "wcslen" | "wcstombs" if uclibc => true,
641 
642             // Apparently res_init exists on Android, but isn't defined in a header:
643             // https://mail.gnome.org/archives/commits-list/2013-May/msg01329.html
644             "res_init" if android => true,
645 
646             // Definition of those functions as changed since unified headers from NDK r14b
647             // These changes imply some API breaking changes but are still ABI compatible.
648             // We can wait for the next major release to be compliant with the new API.
649             // FIXME: unskip these for next major release
650             "strerror_r" | "madvise" | "msync" | "mprotect" | "recvfrom" | "getpriority" |
651             "setpriority" | "personality" if android  => true,
652             // In Android 64 bits, these functions have been fixed since unified headers.
653             // Ignore these until next major version.
654             "bind" | "writev" | "readv" | "sendmsg" | "recvmsg" if android && (aarch64 || x86_64) => true,
655 
656             // Removed in OpenBSD 6.5
657             // https://marc.info/?l=openbsd-cvs&m=154723400730318
658             "mincore" if openbsd => true,
659 
660             _ => false,
661         }
662     });
663 
664     cfg.skip_static(move |name| {
665         match name {
666             // Internal constant, not declared in any headers.
667             "__progname" if android => true,
668             _ => false,
669         }
670     });
671 
672     cfg.skip_field_type(move |struct_, field| {
673         // This is a weird union, don't check the type.
674         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
675         // sighandler_t type is super weird
676         (struct_ == "sigaction" && field == "sa_sigaction") ||
677         // __timeval type is a patch which doesn't exist in glibc
678         (linux && struct_ == "utmpx" && field == "ut_tv") ||
679         // sigval is actually a union, but we pretend it's a struct
680         (struct_ == "sigevent" && field == "sigev_value") ||
681         // aio_buf is "volatile void*" and Rust doesn't understand volatile
682         (struct_ == "aiocb" && field == "aio_buf") ||
683         // stack_t.ss_sp's type changed from FreeBSD 10 to 11 in svn r294930
684         (freebsd && struct_ == "stack_t" && field == "ss_sp") ||
685         // type siginfo_t.si_addr changed from OpenBSD 6.0 to 6.1
686         (openbsd && struct_ == "siginfo_t" && field == "si_addr") ||
687         // this one is an anonymous union
688         (linux && struct_ == "ff_effect" && field == "u")
689     });
690 
691     cfg.skip_field(move |struct_, field| {
692         // this is actually a union on linux, so we can't represent it well and
693         // just insert some padding.
694         (struct_ == "siginfo_t" && field == "_pad") ||
695         // musl names this __dummy1 but it's still there
696         (musl && struct_ == "glob_t" && field == "gl_flags") ||
697         // musl seems to define this as an *anonymous* bitfield
698         (musl && struct_ == "statvfs" && field == "__f_unused") ||
699         // sigev_notify_thread_id is actually part of a sigev_un union
700         (struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
701         // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet.
702         (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" ||
703                                            field == "_pad2" ||
704                                            field == "ssi_syscall" ||
705                                            field == "ssi_call_addr" ||
706                                            field == "ssi_arch"))
707     });
708 
709     // FIXME: remove
710     cfg.fn_cname(move |name, _cname| name.to_string());
711 
712     cfg.generate("../src/lib.rs", "main.rs");
713 
714     // On Linux or Android also generate another script for testing linux/fcntl declarations.
715     // These cannot be tested normally because including both `linux/fcntl.h` and `fcntl.h`
716     // fails on a lot of platforms.
717     let mut cfg = ctest::TestGenerator::new();
718     cfg.skip_type(|_| true)
719         .skip_fn(|_| true)
720         .skip_static(|_| true);
721     if android || linux {
722         // musl defines these directly in `fcntl.h`
723         if musl {
724             cfg.header("fcntl.h");
725         } else {
726             cfg.header("linux/fcntl.h");
727         }
728         if !musl {
729             cfg.header("net/if.h");
730             cfg.header("linux/if.h");
731         }
732         cfg.header("linux/quota.h");
733         cfg.header("asm/termbits.h");
734         cfg.skip_const(move |name| match name {
735             "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => false,
736             "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW"
737             | "F_SEAL_WRITE" => false,
738             "QFMT_VFS_OLD" | "QFMT_VFS_V0" | "QFMT_VFS_V1"
739                 if mips && linux =>
740             {
741                 false
742             }
743             "BOTHER" => false,
744             _ => true,
745         });
746         cfg.skip_struct(|s| s != "termios2");
747         cfg.type_name(move |ty, is_struct, is_union| match ty {
748             t if is_struct => format!("struct {}", t),
749             t if is_union => format!("union {}", t),
750             t => t.to_string(),
751         });
752     } else {
753         cfg.skip_const(|_| true);
754         cfg.skip_struct(|_| true);
755     }
756     cfg.generate("../src/lib.rs", "linux_fcntl.rs");
757 }
758 
759 fn main() {
760     do_cc();
761     do_ctest();
762 }
763 
764 macro_rules! headers {
765     ($cfg:ident: $header:expr) => {
766         $cfg.header($header);
767     };
768     ($cfg:ident: $($header:expr),*) => {
769         $(headers!($cfg: $header);)*
770     };
771     ($cfg:ident: $($header:expr,)*) => {
772         $(headers!($cfg: $header);)*
773     };
774 }
775 
776 fn test_apple(target: &str) {
777     assert!(target.contains("apple"));
778     let x86_64 = target.contains("x86_64");
779 
780     let mut cfg = ctest::TestGenerator::new();
781     cfg.flag("-Wno-deprecated-declarations");
782     cfg.define("__APPLE_USE_RFC_3542", None);
783 
784     headers! { cfg:
785         "aio.h",
786         "ctype.h",
787         "dirent.h",
788         "dlfcn.h",
789         "errno.h",
790         "execinfo.h",
791         "fcntl.h",
792         "glob.h",
793         "grp.h",
794         "ifaddrs.h",
795         "langinfo.h",
796         "limits.h",
797         "locale.h",
798         "mach-o/dyld.h",
799         "mach/mach_time.h",
800         "malloc/malloc.h",
801         "net/bpf.h",
802         "net/if.h",
803         "net/if_arp.h",
804         "net/if_dl.h",
805         "net/if_utun.h",
806         "net/route.h",
807         "net/route.h",
808         "netdb.h",
809         "netinet/if_ether.h",
810         "netinet/in.h",
811         "netinet/in.h",
812         "netinet/ip.h",
813         "netinet/tcp.h",
814         "netinet/udp.h",
815         "poll.h",
816         "pthread.h",
817         "pwd.h",
818         "resolv.h",
819         "sched.h",
820         "semaphore.h",
821         "signal.h",
822         "spawn.h",
823         "stddef.h",
824         "stdint.h",
825         "stdio.h",
826         "stdlib.h",
827         "string.h",
828         "sys/event.h",
829         "sys/file.h",
830         "sys/ioctl.h",
831         "sys/ipc.h",
832         "sys/kern_control.h",
833         "sys/mman.h",
834         "sys/mount.h",
835         "sys/proc_info.h",
836         "sys/ptrace.h",
837         "sys/quota.h",
838         "sys/resource.h",
839         "sys/sem.h",
840         "sys/shm.h",
841         "sys/socket.h",
842         "sys/stat.h",
843         "sys/statvfs.h",
844         "sys/sys_domain.h",
845         "sys/sysctl.h",
846         "sys/time.h",
847         "sys/times.h",
848         "sys/types.h",
849         "sys/uio.h",
850         "sys/un.h",
851         "sys/utsname.h",
852         "sys/wait.h",
853         "sys/xattr.h",
854         "syslog.h",
855         "termios.h",
856         "time.h",
857         "unistd.h",
858         "util.h",
859         "utime.h",
860         "utmpx.h",
861         "wchar.h",
862         "xlocale.h",
863     }
864 
865     if x86_64 {
866         headers! { cfg: "crt_externs.h" }
867     }
868 
869     cfg.skip_struct(move |ty| {
870         match ty {
871             // FIXME: actually a union
872             "sigval" => true,
873 
874             _ => false,
875         }
876     });
877 
878     cfg.skip_const(move |name| {
879         match name {
880             // These OSX constants are removed in Sierra.
881             // https://developer.apple.com/library/content/releasenotes/General/APIDiffsMacOS10_12/Swift/Darwin.html
882             "KERN_KDENABLE_BG_TRACE" | "KERN_KDDISABLE_BG_TRACE" => true,
883             _ => false,
884         }
885     });
886 
887     cfg.skip_fn(move |name| {
888         // skip those that are manually verified
889         match name {
890             // FIXME: https://github.com/rust-lang/libc/issues/1272
891             "execv" | "execve" | "execvp" => true,
892 
893             // close calls the close_nocancel system call
894             "close" => true,
895 
896             _ => false,
897         }
898     });
899 
900     cfg.skip_field_type(move |struct_, field| {
901         match (struct_, field) {
902             // FIXME: actually a union
903             ("sigevent", "sigev_value") => true,
904             _ => false,
905         }
906     });
907 
908     cfg.volatile_item(|i| {
909         use ctest::VolatileItemKind::*;
910         match i {
911             StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => {
912                 true
913             }
914             _ => false,
915         }
916     });
917 
918     cfg.type_name(move |ty, is_struct, is_union| {
919         match ty {
920             // Just pass all these through, no need for a "struct" prefix
921             "FILE" | "DIR" | "Dl_info" => ty.to_string(),
922 
923             // OSX calls this something else
924             "sighandler_t" => "sig_t".to_string(),
925 
926             t if is_union => format!("union {}", t),
927             t if t.ends_with("_t") => t.to_string(),
928             t if is_struct => format!("struct {}", t),
929             t => t.to_string(),
930         }
931     });
932 
933     cfg.field_name(move |struct_, field| {
934         match field {
935             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
936                 s.replace("e_nsec", "espec.tv_nsec")
937             }
938             // FIXME: sigaction actually contains a union with two variants:
939             // a sa_sigaction with type: (*)(int, struct __siginfo *, void *)
940             // a sa_handler with type sig_t
941             "sa_sigaction" if struct_ == "sigaction" => {
942                 "sa_handler".to_string()
943             }
944             s => s.to_string(),
945         }
946     });
947 
948     cfg.generate("../src/lib.rs", "main.rs");
949 }
950 
951 fn test_openbsd(target: &str) {
952     assert!(target.contains("openbsd"));
953 
954     let mut cfg = ctest::TestGenerator::new();
955     cfg.flag("-Wno-deprecated-declarations");
956 
957     headers! { cfg:
958         "errno.h",
959         "fcntl.h",
960         "limits.h",
961         "locale.h",
962         "stddef.h",
963         "stdint.h",
964         "stdio.h",
965         "stdlib.h",
966         "sys/stat.h",
967         "sys/types.h",
968         "time.h",
969         "wchar.h",
970         "ctype.h",
971         "dirent.h",
972         "sys/socket.h",
973         "net/if.h",
974         "net/route.h",
975         "net/if_arp.h",
976         "netdb.h",
977         "netinet/in.h",
978         "netinet/ip.h",
979         "netinet/tcp.h",
980         "netinet/udp.h",
981         "resolv.h",
982         "pthread.h",
983         "dlfcn.h",
984         "signal.h",
985         "string.h",
986         "sys/file.h",
987         "sys/ioctl.h",
988         "sys/mman.h",
989         "sys/resource.h",
990         "sys/socket.h",
991         "sys/time.h",
992         "sys/un.h",
993         "sys/wait.h",
994         "unistd.h",
995         "utime.h",
996         "pwd.h",
997         "grp.h",
998         "sys/utsname.h",
999         "sys/ptrace.h",
1000         "sys/mount.h",
1001         "sys/uio.h",
1002         "sched.h",
1003         "termios.h",
1004         "poll.h",
1005         "syslog.h",
1006         "semaphore.h",
1007         "sys/statvfs.h",
1008         "sys/times.h",
1009         "glob.h",
1010         "ifaddrs.h",
1011         "langinfo.h",
1012         "sys/sysctl.h",
1013         "utmp.h",
1014         "sys/event.h",
1015         "net/if_dl.h",
1016         "util.h",
1017         "ufs/ufs/quota.h",
1018         "pthread_np.h",
1019         "sys/syscall.h",
1020     }
1021 
1022     cfg.skip_struct(move |ty| {
1023         match ty {
1024             // FIXME: actually a union
1025             "sigval" => true,
1026 
1027             _ => false,
1028         }
1029     });
1030 
1031     cfg.skip_const(move |name| {
1032         match name {
1033             // Removed in OpenBSD 6.0
1034             "KERN_USERMOUNT" | "KERN_ARND" => true,
1035             _ => false,
1036         }
1037     });
1038 
1039     cfg.skip_fn(move |name| {
1040         match name {
1041             "execv" | "execve" | "execvp" | "execvpe" => true,
1042 
1043             // typed 2nd arg
1044             "gettimeofday" => true,
1045 
1046             // Removed in OpenBSD 6.5
1047             // https://marc.info/?l=openbsd-cvs&m=154723400730318
1048             "mincore" => true,
1049 
1050             _ => false,
1051         }
1052     });
1053 
1054     cfg.type_name(move |ty, is_struct, is_union| {
1055         match ty {
1056             // Just pass all these through, no need for a "struct" prefix
1057             "FILE" | "DIR" | "Dl_info" => ty.to_string(),
1058 
1059             // OSX calls this something else
1060             "sighandler_t" => "sig_t".to_string(),
1061 
1062             t if is_union => format!("union {}", t),
1063             t if t.ends_with("_t") => t.to_string(),
1064             t if is_struct => format!("struct {}", t),
1065             t => t.to_string(),
1066         }
1067     });
1068 
1069     cfg.field_name(move |struct_, field| match field {
1070         "st_birthtime" if struct_.starts_with("stat") => {
1071             "__st_birthtime".to_string()
1072         }
1073         "st_birthtime_nsec" if struct_.starts_with("stat") => {
1074             "__st_birthtimensec".to_string()
1075         }
1076         s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
1077             s.replace("e_nsec", ".tv_nsec")
1078         }
1079         "sa_sigaction" if struct_ == "sigaction" => "sa_handler".to_string(),
1080         s => s.to_string(),
1081     });
1082 
1083     cfg.skip_field_type(move |struct_, field| {
1084         // type siginfo_t.si_addr changed from OpenBSD 6.0 to 6.1
1085         (struct_ == "siginfo_t" && field == "si_addr")
1086     });
1087 
1088     cfg.generate("../src/lib.rs", "main.rs");
1089 }
1090 
1091 fn test_windows(target: &str) {
1092     assert!(target.contains("windows"));
1093     let gnu = target.contains("gnu");
1094 
1095     let mut cfg = ctest::TestGenerator::new();
1096     cfg.define("_WIN32_WINNT", Some("0x8000"));
1097 
1098     headers! { cfg:
1099         "direct.h",
1100         "errno.h",
1101         "fcntl.h",
1102         "io.h",
1103         "limits.h",
1104         "locale.h",
1105         "process.h",
1106         "signal.h",
1107         "stddef.h",
1108         "stdint.h",
1109         "stdio.h",
1110         "stdlib.h",
1111         "sys/stat.h",
1112         "sys/types.h",
1113         "sys/utime.h",
1114         "time.h",
1115         "wchar.h",
1116     }
1117 
1118     if gnu {
1119         headers! { cfg: "ws2tcpip.h" }
1120     } else {
1121         headers! { cfg: "Winsock2.h" };
1122     }
1123 
1124     cfg.type_name(move |ty, is_struct, is_union| {
1125         match ty {
1126             // Just pass all these through, no need for a "struct" prefix
1127             "FILE" | "DIR" | "Dl_info" => ty.to_string(),
1128 
1129             // FIXME: these don't exist:
1130             "time64_t" => "__time64_t".to_string(),
1131             "ssize_t" => "SSIZE_T".to_string(),
1132 
1133             "sighandler_t" if !gnu => "_crt_signal_t".to_string(),
1134             "sighandler_t" if gnu => "__p_sig_fn_t".to_string(),
1135 
1136             t if is_union => format!("union {}", t),
1137             t if t.ends_with("_t") => t.to_string(),
1138 
1139             // Windows uppercase structs don't have `struct` in front:
1140             t if is_struct => {
1141                 if ty.clone().chars().next().unwrap().is_uppercase() {
1142                     t.to_string()
1143                 } else if t == "stat" {
1144                     "struct __stat64".to_string()
1145                 } else if t == "utimbuf" {
1146                     "struct __utimbuf64".to_string()
1147                 } else {
1148                     // put `struct` in front of all structs:
1149                     format!("struct {}", t)
1150                 }
1151             }
1152             t => t.to_string(),
1153         }
1154     });
1155 
1156     cfg.fn_cname(move |name, cname| cname.unwrap_or(name).to_string());
1157 
1158     cfg.skip_type(move |name| match name {
1159         "SSIZE_T" if !gnu => true,
1160         "ssize_t" if !gnu => true,
1161         _ => false,
1162     });
1163 
1164     cfg.skip_const(move |name| {
1165         match name {
1166             // FIXME: API error:
1167             // SIG_ERR type is "void (*)(int)", not "int"
1168             "SIG_ERR" => true,
1169             _ => false,
1170         }
1171     });
1172 
1173     // FIXME: All functions point to the wrong addresses?
1174     cfg.skip_fn_ptrcheck(|_| true);
1175 
1176     cfg.skip_signededness(move |c| {
1177         match c {
1178             // windows-isms
1179             n if n.starts_with("P") => true,
1180             n if n.starts_with("H") => true,
1181             n if n.starts_with("LP") => true,
1182             "sighandler_t" if gnu => true,
1183             _ => false,
1184         }
1185     });
1186 
1187     cfg.skip_fn(move |name| {
1188         match name {
1189             // FIXME: API error:
1190             "execv" | "execve" | "execvp" | "execvpe" => true,
1191 
1192             _ => false,
1193         }
1194     });
1195 
1196     cfg.generate("../src/lib.rs", "main.rs");
1197 }
1198 
1199 fn test_redox(target: &str) {
1200     assert!(target.contains("redox"));
1201 
1202     let mut cfg = ctest::TestGenerator::new();
1203     cfg.flag("-Wno-deprecated-declarations");
1204 
1205     headers! {
1206         cfg:
1207         "ctype.h",
1208         "dirent.h",
1209         "dlfcn.h",
1210         "errno.h",
1211         "execinfo.h",
1212         "fcntl.h",
1213         "glob.h",
1214         "grp.h",
1215         "ifaddrs.h",
1216         "langinfo.h",
1217         "limits.h",
1218         "locale.h",
1219         "net/if.h",
1220         "net/if_arp.h",
1221         "net/route.h",
1222         "netdb.h",
1223         "netinet/in.h",
1224         "netinet/ip.h",
1225         "netinet/tcp.h",
1226         "netinet/udp.h",
1227         "poll.h",
1228         "pthread.h",
1229         "pwd.h",
1230         "resolv.h",
1231         "sched.h",
1232         "semaphore.h",
1233         "string.h",
1234         "strings.h",
1235         "sys/file.h",
1236         "sys/ioctl.h",
1237         "sys/mman.h",
1238         "sys/mount.h",
1239         "sys/ptrace.h",
1240         "sys/quota.h",
1241         "sys/resource.h",
1242         "sys/socket.h",
1243         "sys/stat.h",
1244         "sys/statvfs.h",
1245         "sys/sysctl.h",
1246         "sys/time.h",
1247         "sys/times.h",
1248         "sys/types.h",
1249         "sys/uio.h",
1250         "sys/un.h",
1251         "sys/utsname.h",
1252         "sys/wait.h",
1253         "syslog.h",
1254         "termios.h",
1255         "time.h",
1256         "unistd.h",
1257         "utime.h",
1258         "utmpx.h",
1259         "wchar.h",
1260     }
1261 
1262     cfg.generate("../src/lib.rs", "main.rs");
1263 }
1264 
1265 fn test_cloudabi(target: &str) {
1266     assert!(target.contains("cloudabi"));
1267 
1268     let mut cfg = ctest::TestGenerator::new();
1269     cfg.flag("-Wno-deprecated-declarations");
1270 
1271     headers! {
1272         cfg:
1273         "execinfo.h",
1274         "glob.h",
1275         "ifaddrs.h",
1276         "langinfo.h",
1277         "sys/ptrace.h",
1278         "sys/quota.h",
1279         "sys/sysctl.h",
1280         "utmpx.h",
1281         "ctype.h",
1282         "dirent.h",
1283         "dlfcn.h",
1284         "errno.h",
1285         "fcntl.h",
1286         "grp.h",
1287         "limits.h",
1288         "locale.h",
1289         "net/if.h",
1290         "net/if_arp.h",
1291         "net/route.h",
1292         "netdb.h",
1293         "netinet/in.h",
1294         "netinet/ip.h",
1295         "netinet/tcp.h",
1296         "netinet/udp.h",
1297         "poll.h",
1298         "pthread.h",
1299         "pwd.h",
1300         "resolv.h",
1301         "sched.h",
1302         "semaphore.h",
1303         "signal.h",
1304         "stddef.h",
1305         "stdint.h",
1306         "stdio.h",
1307         "stdlib.h",
1308         "string.h",
1309         "strings.h",
1310         "sys/file.h",
1311         "sys/ioctl.h",
1312         "sys/mman.h",
1313         "sys/mount.h",
1314         "sys/resource.h",
1315         "sys/socket.h",
1316         "sys/stat.h",
1317         "sys/statvfs.h",
1318         "sys/time.h",
1319         "sys/times.h",
1320         "sys/types.h",
1321         "sys/uio.h",
1322         "sys/un.h",
1323         "sys/utsname.h",
1324         "sys/wait.h",
1325         "syslog.h",
1326         "termios.h",
1327         "time.h",
1328         "unistd.h",
1329         "utime.h",
1330         "wchar.h",
1331     }
1332 
1333     cfg.generate("../src/lib.rs", "main.rs");
1334 }
1335 
1336 fn test_solaris(target: &str) {
1337     assert!(target.contains("solaris"));
1338 
1339     let mut cfg = ctest::TestGenerator::new();
1340     cfg.flag("-Wno-deprecated-declarations");
1341 
1342     cfg.define("_XOPEN_SOURCE", Some("700"));
1343     cfg.define("__EXTENSIONS__", None);
1344     cfg.define("_LCONV_C99", None);
1345 
1346     headers! {
1347         cfg:
1348         "ctype.h",
1349         "dirent.h",
1350         "dlfcn.h",
1351         "errno.h",
1352         "execinfo.h",
1353         "fcntl.h",
1354         "glob.h",
1355         "grp.h",
1356         "ifaddrs.h",
1357         "langinfo.h",
1358         "limits.h",
1359         "locale.h",
1360         "net/if.h",
1361         "net/if_arp.h",
1362         "net/route.h",
1363         "netdb.h",
1364         "netinet/in.h",
1365         "netinet/ip.h",
1366         "netinet/tcp.h",
1367         "netinet/udp.h",
1368         "poll.h",
1369         "port.h",
1370         "pthread.h",
1371         "pwd.h",
1372         "resolv.h",
1373         "sched.h",
1374         "semaphore.h",
1375         "signal.h",
1376         "stddef.h",
1377         "stdint.h",
1378         "stdio.h",
1379         "stdlib.h",
1380         "string.h",
1381         "sys/epoll.h",
1382         "sys/file.h",
1383         "sys/filio.h",
1384         "sys/ioctl.h",
1385         "sys/loadavg.h",
1386         "sys/mman.h",
1387         "sys/mount.h",
1388         "sys/resource.h",
1389         "sys/socket.h",
1390         "sys/stat.h",
1391         "sys/statvfs.h",
1392         "sys/time.h",
1393         "sys/times.h",
1394         "sys/types.h",
1395         "sys/uio.h",
1396         "sys/un.h",
1397         "sys/utsname.h",
1398         "sys/wait.h",
1399         "syslog.h",
1400         "termios.h",
1401         "time.h",
1402         "ucontext.h",
1403         "unistd.h",
1404         "utime.h",
1405         "utmpx.h",
1406         "wchar.h",
1407     }
1408 
1409     cfg.skip_const(move |name| match name {
1410         "DT_FIFO" | "DT_CHR" | "DT_DIR" | "DT_BLK" | "DT_REG" | "DT_LNK"
1411         | "DT_SOCK" | "USRQUOTA" | "GRPQUOTA" | "PRIO_MIN" | "PRIO_MAX" => {
1412             true
1413         }
1414 
1415         _ => false,
1416     });
1417 
1418     cfg.skip_fn(move |name| {
1419         // skip those that are manually verified
1420         match name {
1421             // const-ness only added recently
1422             "dladdr" => true,
1423 
1424             // Definition of those functions as changed since unified headers
1425             // from NDK r14b These changes imply some API breaking changes but
1426             // are still ABI compatible. We can wait for the next major release
1427             // to be compliant with the new API.
1428             //
1429             // FIXME: unskip these for next major release
1430             "setpriority" | "personality" => true,
1431 
1432             // signal is defined with sighandler_t, so ignore
1433             "signal" => true,
1434 
1435             "cfmakeraw" | "cfsetspeed" => true,
1436 
1437             // FIXME: mincore is defined with caddr_t on Solaris.
1438             "mincore" => true,
1439 
1440             _ => false,
1441         }
1442     });
1443 
1444     cfg.generate("../src/lib.rs", "main.rs");
1445 }
1446 
1447 fn test_netbsd(target: &str) {
1448     assert!(target.contains("netbsd"));
1449     let rumprun = target.contains("rumprun");
1450     let mut cfg = ctest::TestGenerator::new();
1451 
1452     cfg.flag("-Wno-deprecated-declarations");
1453     cfg.define("_NETBSD_SOURCE", Some("1"));
1454 
1455     headers! {
1456         cfg:
1457         "errno.h",
1458         "fcntl.h",
1459         "limits.h",
1460         "locale.h",
1461         "stddef.h",
1462         "stdint.h",
1463         "stdio.h",
1464         "stdlib.h",
1465         "sys/stat.h",
1466         "sys/types.h",
1467         "time.h",
1468         "wchar.h",
1469         "aio.h",
1470         "ctype.h",
1471         "dirent.h",
1472         "dlfcn.h",
1473         "glob.h",
1474         "grp.h",
1475         "ifaddrs.h",
1476         "langinfo.h",
1477         "net/if.h",
1478         "net/if_arp.h",
1479         "net/if_dl.h",
1480         "net/route.h",
1481         "netdb.h",
1482         "netinet/in.h",
1483         "netinet/ip.h",
1484         "netinet/tcp.h",
1485         "netinet/udp.h",
1486         "poll.h",
1487         "pthread.h",
1488         "pwd.h",
1489         "resolv.h",
1490         "sched.h",
1491         "semaphore.h",
1492         "signal.h",
1493         "string.h",
1494         "sys/extattr.h",
1495         "sys/file.h",
1496         "sys/ioctl.h",
1497         "sys/ioctl_compat.h",
1498         "sys/mman.h",
1499         "sys/mount.h",
1500         "sys/ptrace.h",
1501         "sys/resource.h",
1502         "sys/socket.h",
1503         "sys/statvfs.h",
1504         "sys/sysctl.h",
1505         "sys/time.h",
1506         "sys/times.h",
1507         "sys/uio.h",
1508         "sys/un.h",
1509         "sys/utsname.h",
1510         "sys/wait.h",
1511         "syslog.h",
1512         "termios.h",
1513         "ufs/ufs/quota.h",
1514         "ufs/ufs/quota1.h",
1515         "unistd.h",
1516         "util.h",
1517         "utime.h",
1518         "mqueue.h",
1519         "netinet/dccp.h",
1520         "sys/event.h",
1521         "sys/quota.h",
1522     }
1523 
1524     cfg.type_name(move |ty, is_struct, is_union| {
1525         match ty {
1526             // Just pass all these through, no need for a "struct" prefix
1527             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr"
1528             | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym"
1529             | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr"
1530             | "Elf64_Chdr" => ty.to_string(),
1531 
1532             // OSX calls this something else
1533             "sighandler_t" => "sig_t".to_string(),
1534 
1535             t if is_union => format!("union {}", t),
1536 
1537             t if t.ends_with("_t") => t.to_string(),
1538 
1539             // put `struct` in front of all structs:.
1540             t if is_struct => format!("struct {}", t),
1541 
1542             t => t.to_string(),
1543         }
1544     });
1545 
1546     cfg.field_name(move |struct_, field| {
1547         match field {
1548             // Our stat *_nsec fields normally don't actually exist but are part
1549             // of a timeval struct
1550             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
1551                 s.replace("e_nsec", ".tv_nsec")
1552             }
1553             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
1554             s => s.to_string(),
1555         }
1556     });
1557 
1558     cfg.skip_type(move |ty| {
1559         match ty {
1560             // FIXME: sighandler_t is crazy across platforms
1561             "sighandler_t" => true,
1562             _ => false,
1563         }
1564     });
1565 
1566     cfg.skip_struct(move |ty| {
1567         match ty {
1568             // This is actually a union, not a struct
1569             "sigval" => true,
1570             // These are tested as part of the linux_fcntl tests since there are
1571             // header conflicts when including them with all the other structs.
1572             "termios2" => true,
1573             _ => false,
1574         }
1575     });
1576 
1577     cfg.skip_signededness(move |c| {
1578         match c {
1579             "LARGE_INTEGER" | "float" | "double" => true,
1580             // uuid_t is a struct, not an integer.
1581             n if n.starts_with("pthread") => true,
1582             // sem_t is a struct or pointer
1583             "sem_t" => true,
1584             _ => false,
1585         }
1586     });
1587 
1588     cfg.skip_const(move |name| {
1589         match name {
1590             "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness
1591             "SIGUNUSED" => true,                       // removed in glibc 2.26
1592 
1593             // weird signed extension or something like that?
1594             "MS_NOUSER" => true,
1595             "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13
1596             "BOTHER" => true,
1597 
1598             _ => false,
1599         }
1600     });
1601 
1602     cfg.skip_fn(move |name| {
1603         match name {
1604             // FIXME: incorrect API
1605             "execv" |
1606             "execve" |
1607             "execvp" |
1608             "execvpe" |
1609             "fexecve" => true,
1610 
1611             "getrlimit" | "getrlimit64" |    // non-int in 1st arg
1612             "setrlimit" | "setrlimit64" |    // non-int in 1st arg
1613             "prlimit" | "prlimit64" |        // non-int in 2nd arg
1614 
1615             // These functions presumably exist on netbsd but don't look like
1616             // they're implemented on rumprun yet, just let them slide for now.
1617             // Some of them look like they have headers but then don't have
1618             // corresponding actual definitions either...
1619             "shm_open" |
1620             "shm_unlink" |
1621             "syscall" |
1622             "mq_open" |
1623             "mq_close" |
1624             "mq_getattr" |
1625             "mq_notify" |
1626             "mq_receive" |
1627             "mq_send" |
1628             "mq_setattr" |
1629             "mq_timedreceive" |
1630             "mq_timedsend" |
1631             "mq_unlink" |
1632             "ptrace" |
1633             "sigaltstack" if rumprun => true,
1634 
1635             _ => false,
1636         }
1637     });
1638 
1639     cfg.skip_field_type(move |struct_, field| {
1640         // This is a weird union, don't check the type.
1641         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
1642         // sighandler_t type is super weird
1643         (struct_ == "sigaction" && field == "sa_sigaction") ||
1644         // sigval is actually a union, but we pretend it's a struct
1645         (struct_ == "sigevent" && field == "sigev_value") ||
1646         // aio_buf is "volatile void*" and Rust doesn't understand volatile
1647         (struct_ == "aiocb" && field == "aio_buf")
1648     });
1649 
1650     cfg.generate("../src/lib.rs", "main.rs");
1651 }
1652 
1653 fn test_dragonflybsd(target: &str) {
1654     assert!(target.contains("dragonfly"));
1655     let mut cfg = ctest::TestGenerator::new();
1656     cfg.flag("-Wno-deprecated-declarations");
1657 
1658     headers! {
1659         cfg:
1660         "aio.h",
1661         "ctype.h",
1662         "dirent.h",
1663         "dlfcn.h",
1664         "errno.h",
1665         "execinfo.h",
1666         "fcntl.h",
1667         "glob.h",
1668         "grp.h",
1669         "ifaddrs.h",
1670         "langinfo.h",
1671         "limits.h",
1672         "locale.h",
1673         "mqueue.h",
1674         "net/if.h",
1675         "net/if_arp.h",
1676         "net/if_dl.h",
1677         "net/route.h",
1678         "netdb.h",
1679         "netinet/in.h",
1680         "netinet/ip.h",
1681         "netinet/tcp.h",
1682         "netinet/udp.h",
1683         "poll.h",
1684         "pthread.h",
1685         "pthread_np.h",
1686         "pwd.h",
1687         "resolv.h",
1688         "sched.h",
1689         "semaphore.h",
1690         "signal.h",
1691         "stddef.h",
1692         "stdint.h",
1693         "stdio.h",
1694         "stdlib.h",
1695         "string.h",
1696         "sys/event.h",
1697         "sys/file.h",
1698         "sys/ioctl.h",
1699         "sys/mman.h",
1700         "sys/mount.h",
1701         "sys/ptrace.h",
1702         "sys/resource.h",
1703         "sys/rtprio.h",
1704         "sys/socket.h",
1705         "sys/stat.h",
1706         "sys/statvfs.h",
1707         "sys/sysctl.h",
1708         "sys/time.h",
1709         "sys/times.h",
1710         "sys/types.h",
1711         "sys/uio.h",
1712         "sys/un.h",
1713         "sys/utsname.h",
1714         "sys/wait.h",
1715         "syslog.h",
1716         "termios.h",
1717         "time.h",
1718         "ufs/ufs/quota.h",
1719         "unistd.h",
1720         "util.h",
1721         "utime.h",
1722         "utmpx.h",
1723         "wchar.h",
1724     }
1725 
1726     cfg.type_name(move |ty, is_struct, is_union| {
1727         match ty {
1728             // Just pass all these through, no need for a "struct" prefix
1729             "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr"
1730             | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym"
1731             | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr"
1732             | "Elf64_Chdr" => ty.to_string(),
1733 
1734             // FIXME: OSX calls this something else
1735             "sighandler_t" => "sig_t".to_string(),
1736 
1737             t if is_union => format!("union {}", t),
1738 
1739             t if t.ends_with("_t") => t.to_string(),
1740 
1741             // put `struct` in front of all structs:.
1742             t if is_struct => format!("struct {}", t),
1743 
1744             t => t.to_string(),
1745         }
1746     });
1747 
1748     cfg.field_name(move |struct_, field| {
1749         match field {
1750             // Our stat *_nsec fields normally don't actually exist but are part
1751             // of a timeval struct
1752             s if s.ends_with("_nsec") && struct_.starts_with("stat") => {
1753                 s.replace("e_nsec", ".tv_nsec")
1754             }
1755             "u64" if struct_ == "epoll_event" => "data.u64".to_string(),
1756             "type_"
1757                 if struct_ == "input_event"
1758                     || struct_ == "input_mask"
1759                     || struct_ == "ff_effect"
1760                     || struct_ == "rtprio" =>
1761             {
1762                 "type".to_string()
1763             }
1764             s => s.to_string(),
1765         }
1766     });
1767 
1768     cfg.skip_type(move |ty| {
1769         match ty {
1770             // sighandler_t is crazy across platforms
1771             "sighandler_t" => true,
1772 
1773             _ => false,
1774         }
1775     });
1776 
1777     cfg.skip_struct(move |ty| {
1778         match ty {
1779             // This is actually a union, not a struct
1780             "sigval" => true,
1781 
1782             // FIXME: These are tested as part of the linux_fcntl tests since
1783             // there are header conflicts when including them with all the other
1784             // structs.
1785             "termios2" => true,
1786 
1787             _ => false,
1788         }
1789     });
1790 
1791     cfg.skip_signededness(move |c| {
1792         match c {
1793             "LARGE_INTEGER" | "float" | "double" => true,
1794             // uuid_t is a struct, not an integer.
1795             "uuid_t" => true,
1796             n if n.starts_with("pthread") => true,
1797             // sem_t is a struct or pointer
1798             "sem_t" => true,
1799             // mqd_t is a pointer on DragonFly
1800             "mqd_t" => true,
1801 
1802             _ => false,
1803         }
1804     });
1805 
1806     cfg.skip_const(move |name| {
1807         match name {
1808             "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness
1809 
1810             // weird signed extension or something like that?
1811             "MS_NOUSER" => true,
1812             "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13
1813 
1814             // These are defined for Solaris 11, but the crate is tested on
1815             // illumos, where they are currently not defined
1816             "EADI"
1817             | "PORT_SOURCE_POSTWAIT"
1818             | "PORT_SOURCE_SIGNAL"
1819             | "PTHREAD_STACK_MIN" => true,
1820 
1821             // These change all the time from release to release of linux
1822             // distros, let's just not bother trying to verify them. They
1823             // shouldn't be used in code anyway...
1824             "AF_MAX" | "PF_MAX" => true,
1825 
1826             _ => false,
1827         }
1828     });
1829 
1830     cfg.skip_fn(move |name| {
1831         // skip those that are manually verified
1832         match name {
1833             "execv" |       // crazy stuff with const/mut
1834             "execve" |
1835             "execvp" |
1836             "execvpe" |
1837             "fexecve" => true,
1838 
1839             "getrlimit" | "getrlimit64" |    // non-int in 1st arg
1840             "setrlimit" | "setrlimit64" |    // non-int in 1st arg
1841             "prlimit" | "prlimit64" |        // non-int in 2nd arg
1842             // typed 2nd arg on linux and android
1843             "gettimeofday" => true,
1844 
1845             _ => false,
1846         }
1847     });
1848 
1849     cfg.skip_field_type(move |struct_, field| {
1850         // This is a weird union, don't check the type.
1851         (struct_ == "ifaddrs" && field == "ifa_ifu") ||
1852         // sighandler_t type is super weird
1853         (struct_ == "sigaction" && field == "sa_sigaction") ||
1854         // sigval is actually a union, but we pretend it's a struct
1855         (struct_ == "sigevent" && field == "sigev_value") ||
1856         // aio_buf is "volatile void*" and Rust doesn't understand volatile
1857         (struct_ == "aiocb" && field == "aio_buf")
1858     });
1859 
1860     cfg.skip_field(move |struct_, field| {
1861         // this is actually a union on linux, so we can't represent it well and
1862         // just insert some padding.
1863         (struct_ == "siginfo_t" && field == "_pad") ||
1864         // sigev_notify_thread_id is actually part of a sigev_un union
1865         (struct_ == "sigevent" && field == "sigev_notify_thread_id")
1866     });
1867 
1868     cfg.generate("../src/lib.rs", "main.rs");
1869 }
1870 
1871 fn test_wasi(target: &str) {
1872     assert!(target.contains("wasi"));
1873 
1874     let mut cfg = ctest::TestGenerator::new();
1875     cfg.define("_GNU_SOURCE", None);
1876 
1877     headers! { cfg:
1878         "ctype.h",
1879         "dirent.h",
1880         "errno.h",
1881         "fcntl.h",
1882         "limits.h",
1883         "locale.h",
1884         "malloc.h",
1885         "poll.h",
1886         "stdbool.h",
1887         "stddef.h",
1888         "stdint.h",
1889         "stdio.h",
1890         "stdlib.h",
1891         "string.h",
1892         "sys/resource.h",
1893         "sys/select.h",
1894         "sys/socket.h",
1895         "sys/stat.h",
1896         "sys/times.h",
1897         "sys/types.h",
1898         "sys/uio.h",
1899         "sys/utsname.h",
1900         "time.h",
1901         "unistd.h",
1902         "wasi/core.h",
1903         "wasi/libc.h",
1904         "wasi/libc-find-relpath.h",
1905         "wchar.h",
1906     }
1907 
1908     cfg.type_name(move |ty, is_struct, is_union| match ty {
1909         "FILE" | "fd_set" | "DIR" => ty.to_string(),
1910         t if is_union => format!("union {}", t),
1911         t if t.starts_with("__wasi") && t.ends_with("_u") => {
1912             format!("union {}", t)
1913         }
1914         t if t.starts_with("__wasi") && is_struct => format!("struct {}", t),
1915         t if t.ends_with("_t") => t.to_string(),
1916         t if is_struct => format!("struct {}", t),
1917         t => t.to_string(),
1918     });
1919 
1920     cfg.field_name(move |_struct, field| {
1921         match field {
1922             // deal with fields as rust keywords
1923             "type_" => "type".to_string(),
1924             s => s.to_string(),
1925         }
1926     });
1927 
1928     // Looks like LLD doesn't merge duplicate imports, so if the Rust
1929     // code imports from a module and the C code also imports from a
1930     // module we end up with two imports of function pointers which
1931     // import the same thing but have different function pointers
1932     cfg.skip_fn_ptrcheck(|f| f.starts_with("__wasi"));
1933 
1934     // d_name is declared as a flexible array in WASI libc, so it
1935     // doesn't support sizeof.
1936     cfg.skip_field(|s, field| s == "dirent" && field == "d_name");
1937 
1938     cfg.generate("../src/lib.rs", "main.rs");
1939 }
1940