]>
Commit | Line | Data |
---|---|---|
92a42be0 SL |
1 | #![deny(warnings)] |
2 | ||
3 | extern crate ctest; | |
4 | ||
5 | use std::env; | |
6 | ||
7 | fn main() { | |
8 | let target = env::var("TARGET").unwrap(); | |
9cc50fc6 | 9 | let x86_64 = target.contains("x86_64"); |
92a42be0 SL |
10 | let windows = target.contains("windows"); |
11 | let mingw = target.contains("windows-gnu"); | |
12 | let linux = target.contains("unknown-linux"); | |
13 | let android = target.contains("android"); | |
14 | let apple = target.contains("apple"); | |
15 | let musl = target.contains("musl"); | |
16 | let freebsd = target.contains("freebsd"); | |
54a0048b | 17 | let dragonfly = target.contains("dragonfly"); |
9cc50fc6 SL |
18 | let mips = target.contains("mips"); |
19 | let netbsd = target.contains("netbsd"); | |
20 | let openbsd = target.contains("openbsd"); | |
21 | let rumprun = target.contains("rumprun"); | |
54a0048b | 22 | let bsdlike = freebsd || apple || netbsd || openbsd || dragonfly; |
92a42be0 SL |
23 | let mut cfg = ctest::TestGenerator::new(); |
24 | ||
25 | // Pull in extra goodies on linux/mingw | |
9cc50fc6 | 26 | if linux || android { |
92a42be0 SL |
27 | cfg.define("_GNU_SOURCE", None); |
28 | } else if windows { | |
29 | cfg.define("_WIN32_WINNT", Some("0x8000")); | |
30 | } | |
31 | ||
32 | // Android doesn't actually have in_port_t but it's much easier if we | |
33 | // provide one for us to test against | |
34 | if android { | |
35 | cfg.define("in_port_t", Some("uint16_t")); | |
36 | } | |
37 | ||
38 | cfg.header("errno.h") | |
39 | .header("fcntl.h") | |
40 | .header("limits.h") | |
54a0048b | 41 | .header("locale.h") |
92a42be0 SL |
42 | .header("stddef.h") |
43 | .header("stdint.h") | |
44 | .header("stdio.h") | |
45 | .header("stdlib.h") | |
46 | .header("sys/stat.h") | |
47 | .header("sys/types.h") | |
48 | .header("time.h") | |
49 | .header("wchar.h"); | |
50 | ||
51 | if windows { | |
52 | cfg.header("winsock2.h"); // must be before windows.h | |
53 | ||
54 | cfg.header("direct.h"); | |
55 | cfg.header("io.h"); | |
56 | cfg.header("sys/utime.h"); | |
57 | cfg.header("windows.h"); | |
58 | cfg.header("process.h"); | |
59 | cfg.header("ws2ipdef.h"); | |
60 | ||
61 | if target.contains("gnu") { | |
62 | cfg.header("ws2tcpip.h"); | |
63 | } | |
64 | } else { | |
65 | cfg.header("ctype.h"); | |
66 | cfg.header("dirent.h"); | |
9cc50fc6 SL |
67 | if openbsd { |
68 | cfg.header("sys/socket.h"); | |
69 | } | |
92a42be0 SL |
70 | cfg.header("net/if.h"); |
71 | cfg.header("netdb.h"); | |
72 | cfg.header("netinet/in.h"); | |
73 | cfg.header("netinet/ip.h"); | |
74 | cfg.header("netinet/tcp.h"); | |
75 | cfg.header("pthread.h"); | |
76 | cfg.header("dlfcn.h"); | |
77 | cfg.header("signal.h"); | |
78 | cfg.header("string.h"); | |
79 | cfg.header("sys/file.h"); | |
80 | cfg.header("sys/ioctl.h"); | |
81 | cfg.header("sys/mman.h"); | |
82 | cfg.header("sys/resource.h"); | |
83 | cfg.header("sys/socket.h"); | |
84 | cfg.header("sys/time.h"); | |
85 | cfg.header("sys/un.h"); | |
86 | cfg.header("sys/wait.h"); | |
87 | cfg.header("unistd.h"); | |
88 | cfg.header("utime.h"); | |
89 | cfg.header("pwd.h"); | |
90 | cfg.header("grp.h"); | |
9cc50fc6 SL |
91 | cfg.header("sys/utsname.h"); |
92 | cfg.header("sys/ptrace.h"); | |
93 | cfg.header("sys/mount.h"); | |
94 | cfg.header("sys/uio.h"); | |
95 | cfg.header("sched.h"); | |
96 | cfg.header("termios.h"); | |
97 | cfg.header("poll.h"); | |
92a42be0 SL |
98 | } |
99 | ||
100 | if android { | |
101 | cfg.header("arpa/inet.h"); | |
102 | cfg.header("time64.h"); | |
103 | } else if !windows { | |
104 | cfg.header("glob.h"); | |
105 | cfg.header("ifaddrs.h"); | |
7453a54e SL |
106 | cfg.header("sys/statvfs.h"); |
107 | ||
54a0048b | 108 | if !openbsd && !freebsd && !dragonfly { |
9cc50fc6 SL |
109 | cfg.header("sys/quota.h"); |
110 | } | |
92a42be0 SL |
111 | |
112 | if !musl { | |
92a42be0 | 113 | cfg.header("sys/sysctl.h"); |
9cc50fc6 SL |
114 | |
115 | if !netbsd && !openbsd { | |
116 | cfg.header("execinfo.h"); | |
117 | } | |
92a42be0 SL |
118 | } |
119 | } | |
120 | ||
121 | if apple { | |
122 | cfg.header("mach-o/dyld.h"); | |
123 | cfg.header("mach/mach_time.h"); | |
124 | cfg.header("malloc/malloc.h"); | |
54a0048b | 125 | cfg.header("util.h"); |
92a42be0 SL |
126 | if target.starts_with("x86") { |
127 | cfg.header("crt_externs.h"); | |
128 | } | |
129 | } | |
130 | ||
9cc50fc6 SL |
131 | if bsdlike { |
132 | cfg.header("sys/event.h"); | |
54a0048b SL |
133 | |
134 | if freebsd { | |
135 | cfg.header("libutil.h"); | |
136 | } else { | |
137 | cfg.header("util.h"); | |
138 | } | |
9cc50fc6 SL |
139 | } |
140 | ||
141 | if linux { | |
142 | cfg.header("mqueue.h"); | |
54a0048b | 143 | cfg.header("ucontext.h"); |
9cc50fc6 SL |
144 | cfg.header("sys/signalfd.h"); |
145 | cfg.header("sys/xattr.h"); | |
146 | cfg.header("sys/ipc.h"); | |
147 | cfg.header("sys/shm.h"); | |
54a0048b | 148 | cfg.header("pty.h"); |
9cc50fc6 SL |
149 | } |
150 | ||
92a42be0 | 151 | if linux || android { |
92a42be0 | 152 | cfg.header("malloc.h"); |
9cc50fc6 SL |
153 | cfg.header("net/ethernet.h"); |
154 | cfg.header("netpacket/packet.h"); | |
155 | cfg.header("sched.h"); | |
156 | cfg.header("sys/epoll.h"); | |
157 | cfg.header("sys/eventfd.h"); | |
92a42be0 | 158 | cfg.header("sys/prctl.h"); |
7453a54e | 159 | cfg.header("sys/sendfile.h"); |
9cc50fc6 SL |
160 | cfg.header("sys/vfs.h"); |
161 | cfg.header("sys/syscall.h"); | |
92a42be0 SL |
162 | if !musl { |
163 | cfg.header("linux/netlink.h"); | |
9cc50fc6 SL |
164 | cfg.header("linux/magic.h"); |
165 | ||
166 | if !mips { | |
167 | cfg.header("linux/quota.h"); | |
168 | } | |
92a42be0 SL |
169 | } |
170 | } | |
171 | ||
172 | if freebsd { | |
173 | cfg.header("pthread_np.h"); | |
9cc50fc6 | 174 | cfg.header("sched.h"); |
7453a54e | 175 | cfg.header("ufs/ufs/quota.h"); |
9cc50fc6 SL |
176 | } |
177 | ||
178 | if netbsd { | |
179 | cfg.header("ufs/ufs/quota.h"); | |
180 | cfg.header("ufs/ufs/quota1.h"); | |
181 | cfg.header("sys/ioctl_compat.h"); | |
182 | } | |
183 | ||
184 | if openbsd { | |
185 | cfg.header("ufs/ufs/quota.h"); | |
186 | cfg.header("rpcsvc/rex.h"); | |
187 | cfg.header("pthread_np.h"); | |
188 | cfg.header("sys/syscall.h"); | |
92a42be0 SL |
189 | } |
190 | ||
54a0048b SL |
191 | if dragonfly { |
192 | cfg.header("ufs/ufs/quota.h"); | |
193 | cfg.header("pthread_np.h"); | |
194 | cfg.header("sys/ioctl_compat.h"); | |
195 | } | |
196 | ||
92a42be0 SL |
197 | cfg.type_name(move |ty, is_struct| { |
198 | match ty { | |
199 | // Just pass all these through, no need for a "struct" prefix | |
200 | "FILE" | | |
201 | "fd_set" | | |
202 | "Dl_info" | | |
203 | "DIR" => ty.to_string(), | |
204 | ||
205 | // Fixup a few types on windows that don't actually exist. | |
206 | "time64_t" if windows => "__time64_t".to_string(), | |
207 | "ssize_t" if windows => "SSIZE_T".to_string(), | |
208 | ||
209 | // OSX calls this something else | |
210 | "sighandler_t" if bsdlike => "sig_t".to_string(), | |
211 | ||
212 | t if t.ends_with("_t") => t.to_string(), | |
213 | ||
214 | // Windows uppercase structs don't have `struct` in front, there's a | |
215 | // few special cases for windows, and then otherwise put `struct` in | |
216 | // front of everything. | |
217 | t if is_struct => { | |
218 | if windows && ty.chars().next().unwrap().is_uppercase() { | |
219 | t.to_string() | |
220 | } else if windows && t == "stat" { | |
221 | "struct __stat64".to_string() | |
222 | } else if windows && t == "utimbuf" { | |
223 | "struct __utimbuf64".to_string() | |
224 | } else { | |
225 | format!("struct {}", t) | |
226 | } | |
227 | } | |
228 | ||
229 | t => t.to_string(), | |
230 | } | |
231 | }); | |
232 | ||
233 | let target2 = target.clone(); | |
234 | cfg.field_name(move |struct_, field| { | |
235 | match field { | |
9cc50fc6 SL |
236 | "st_birthtime" if openbsd && struct_ == "stat" => "__st_birthtime".to_string(), |
237 | "st_birthtime_nsec" if openbsd && struct_ == "stat" => "__st_birthtimensec".to_string(), | |
92a42be0 SL |
238 | // Our stat *_nsec fields normally don't actually exist but are part |
239 | // of a timeval struct | |
240 | s if s.ends_with("_nsec") && struct_.starts_with("stat") => { | |
241 | if target2.contains("apple") { | |
242 | s.replace("_nsec", "spec.tv_nsec") | |
243 | } else if target2.contains("android") { | |
244 | s.to_string() | |
245 | } else { | |
246 | s.replace("e_nsec", ".tv_nsec") | |
247 | } | |
248 | } | |
9cc50fc6 | 249 | "u64" if struct_ == "epoll_event" => "data.u64".to_string(), |
92a42be0 SL |
250 | s => s.to_string(), |
251 | } | |
252 | }); | |
253 | ||
254 | cfg.skip_type(move |ty| { | |
255 | match ty { | |
256 | // sighandler_t is crazy across platforms | |
257 | "sighandler_t" => true, | |
258 | ||
259 | _ => false | |
260 | } | |
261 | }); | |
262 | ||
263 | cfg.skip_struct(move |ty| { | |
264 | match ty { | |
265 | "sockaddr_nl" => musl, | |
9cc50fc6 SL |
266 | |
267 | // The alignment of this is 4 on 64-bit OSX... | |
268 | "kevent" if apple && x86_64 => true, | |
269 | ||
92a42be0 SL |
270 | _ => false |
271 | } | |
272 | }); | |
273 | ||
54a0048b | 274 | cfg.skip_signededness(move |c| { |
92a42be0 SL |
275 | match c { |
276 | "LARGE_INTEGER" | | |
277 | "mach_timebase_info_data_t" | | |
278 | "float" | | |
279 | "double" => true, | |
54a0048b SL |
280 | // uuid_t is a struct, not an integer. |
281 | "uuid_t" if dragonfly => true, | |
92a42be0 SL |
282 | n if n.starts_with("pthread") => true, |
283 | ||
284 | // windows-isms | |
285 | n if n.starts_with("P") => true, | |
286 | n if n.starts_with("H") => true, | |
287 | n if n.starts_with("LP") => true, | |
288 | _ => false, | |
289 | } | |
290 | }); | |
291 | ||
292 | cfg.skip_const(move |name| { | |
293 | match name { | |
294 | // Apparently these don't exist in mingw headers? | |
295 | "MEM_RESET_UNDO" | | |
296 | "FILE_ATTRIBUTE_NO_SCRUB_DATA" | | |
297 | "FILE_ATTRIBUTE_INTEGRITY_STREAM" | | |
298 | "ERROR_NOTHING_TO_TERMINATE" if mingw => true, | |
299 | ||
300 | "SIG_IGN" => true, // sighandler_t weirdness | |
301 | ||
302 | // types on musl are defined a little differently | |
303 | n if musl && n.contains("__SIZEOF_PTHREAD") => true, | |
304 | ||
305 | // Skip constants not defined in MUSL but just passed down to the | |
306 | // kernel regardless | |
307 | "RLIMIT_NLIMITS" | | |
308 | "TCP_COOKIE_TRANSACTIONS" | | |
309 | "RLIMIT_RTTIME" if musl => true, | |
9cc50fc6 SL |
310 | // work around super old mips toolchain |
311 | "SCHED_IDLE" | "SHM_NORESERVE" => mips, | |
312 | ||
313 | // weird signed extension or something like that? | |
314 | "MS_NOUSER" => true, | |
54a0048b | 315 | "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 |
9cc50fc6 SL |
316 | |
317 | // These OSX constants are flagged as deprecated | |
318 | "NOTE_EXIT_REPARENTED" | | |
319 | "NOTE_REAP" if apple => true, | |
320 | ||
321 | // The linux/quota.h header file which defines these can't be | |
322 | // included with sys/quota.h currently on MIPS, so we don't include | |
323 | // it and just ignore these constants | |
324 | "QFMT_VFS_OLD" | | |
325 | "QFMT_VFS_V0" if mips && linux => true, | |
92a42be0 SL |
326 | |
327 | _ => false, | |
328 | } | |
329 | }); | |
330 | ||
331 | cfg.skip_fn(move |name| { | |
9cc50fc6 | 332 | // skip those that are manually verified |
92a42be0 SL |
333 | match name { |
334 | "execv" | // crazy stuff with const/mut | |
335 | "execve" | | |
336 | "execvp" | | |
337 | "execvpe" => true, | |
338 | ||
339 | "getrlimit" | "getrlimit64" | // non-int in 1st arg | |
340 | "setrlimit" | "setrlimit64" | // non-int in 1st arg | |
341 | "strerror_r" if linux => true, // actually xpg-something-or-other | |
342 | ||
343 | // typed 2nd arg on linux and android | |
54a0048b | 344 | "gettimeofday" if linux || android || freebsd || openbsd || dragonfly => true, |
9cc50fc6 SL |
345 | |
346 | // not declared in newer android toolchains | |
347 | "getdtablesize" if android => true, | |
92a42be0 SL |
348 | |
349 | "dlerror" if android => true, // const-ness is added | |
350 | "dladdr" if musl => true, // const-ness only added recently | |
351 | ||
352 | // OSX has 'struct tm *const' which we can't actually represent in | |
353 | // Rust, but is close enough to *mut | |
354 | "timegm" if apple => true, | |
355 | ||
9cc50fc6 SL |
356 | // OSX's daemon is deprecated in 10.5 so we'll get a warning (which |
357 | // we turn into an error) so just ignore it. | |
358 | "daemon" if apple => true, | |
359 | ||
360 | // These functions presumably exist on netbsd but don't look like | |
361 | // they're implemented on rumprun yet, just let them slide for now. | |
362 | // Some of them look like they have headers but then don't have | |
363 | // corresponding actual definitions either... | |
9cc50fc6 SL |
364 | "shm_open" | |
365 | "shm_unlink" | | |
366 | "syscall" | | |
367 | "ptrace" | | |
368 | "sigaltstack" if rumprun => true, | |
369 | ||
370 | // There seems to be a small error in EGLIBC's eventfd.h header. The | |
371 | // [underlying system call][1] always takes its first `count` | |
372 | // argument as an `unsigned int`, but [EGLIBC's <sys/eventfd.h> | |
373 | // header][2] declares it to take an `int`. [GLIBC's header][3] | |
374 | // matches the kernel. | |
375 | // | |
376 | // EGLIBC is no longer actively developed, and Debian, the largest | |
377 | // distribution that had been using it, switched back to GLIBC in | |
378 | // April 2015. So effectively all Linux <sys/eventfd.h> headers will | |
379 | // be using `unsigned int` soon. | |
380 | // | |
381 | // [1]: https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/fs/eventfd.c?id=refs/tags/v3.12.51#n397 | |
382 | // [2]: http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/trusty/eglibc/trusty/view/head:/sysdeps/unix/sysv/linux/sys/eventfd.h | |
383 | // [3]: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/sys/eventfd.h;h=6295f32e937e779e74318eb9d3bdbe76aef8a8f3;hb=4e42b5b8f89f0e288e68be7ad70f9525aebc2cff#l34 | |
384 | "eventfd" if linux => true, | |
385 | ||
7453a54e SL |
386 | // The `uname` funcion in freebsd is now an inline wrapper that |
387 | // delegates to another, but the symbol still exists, so don't check | |
388 | // the symbol. | |
389 | "uname" if freebsd => true, | |
390 | ||
92a42be0 SL |
391 | _ => false, |
392 | } | |
393 | }); | |
394 | ||
9cc50fc6 SL |
395 | cfg.skip_fn_ptrcheck(move |name| { |
396 | match name { | |
397 | // This used to be called bsd_signal in rev 18 of the android | |
398 | // platform and is now just called signal, the old `bsd_signal` | |
399 | // symbol, however, still remains, just gives a different function | |
400 | // pointer. | |
401 | "signal" if android => true, | |
402 | ||
403 | // dllimport weirdness? | |
404 | _ if windows => true, | |
405 | ||
406 | _ => false, | |
407 | } | |
408 | }); | |
92a42be0 SL |
409 | |
410 | cfg.skip_field_type(move |struct_, field| { | |
411 | // This is a weird union, don't check the type. | |
412 | (struct_ == "ifaddrs" && field == "ifa_ifu") || | |
413 | // sighandler_t type is super weird | |
414 | (struct_ == "sigaction" && field == "sa_sigaction") | |
415 | }); | |
416 | ||
417 | cfg.skip_field(move |struct_, field| { | |
418 | // this is actually a union on linux, so we can't represent it well and | |
419 | // just insert some padding. | |
420 | (struct_ == "siginfo_t" && field == "_pad") || | |
421 | // musl names this __dummy1 but it's still there | |
7453a54e SL |
422 | (musl && struct_ == "glob_t" && field == "gl_flags") || |
423 | // musl seems to define this as an *anonymous* bitfield | |
424 | (musl && struct_ == "statvfs" && field == "__f_unused") | |
92a42be0 SL |
425 | }); |
426 | ||
9cc50fc6 SL |
427 | cfg.fn_cname(move |name, cname| { |
428 | if windows { | |
429 | cname.unwrap_or(name).to_string() | |
430 | } else { | |
431 | name.to_string() | |
432 | } | |
433 | }); | |
434 | ||
7453a54e SL |
435 | if env::var("SKIP_COMPILE").is_ok() { |
436 | cfg.generate_files("../src/lib.rs", "all.rs"); | |
437 | } else { | |
438 | cfg.generate("../src/lib.rs", "all.rs"); | |
439 | } | |
92a42be0 | 440 | } |