From 0af80cae5344dea04f841029f2aa3b2213cf3316 Mon Sep 17 00:00:00 2001 From: gnzlbg Date: Tue, 14 May 2019 10:06:23 +0200 Subject: [PATCH] Refactor Android target --- libc-test/build.rs | 476 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 387 insertions(+), 89 deletions(-) diff --git a/libc-test/build.rs b/libc-test/build.rs index aba2a305..bb025239 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -14,12 +14,10 @@ fn do_cc() { fn do_ctest() { let target = env::var("TARGET").unwrap(); - let aarch64 = target.contains("aarch64"); let i686 = target.contains("i686"); let x86_64 = target.contains("x86_64"); let x32 = target.ends_with("gnux32"); let linux = target.contains("unknown-linux"); - let android = target.contains("android"); let emscripten = target.contains("asm"); let musl = target.contains("musl") || emscripten; let uclibc = target.contains("uclibc"); @@ -39,22 +37,17 @@ fn do_ctest() { t if t.contains("netbsd") => return test_netbsd(t), t if t.contains("dragonfly") => return test_dragonflybsd(t), t if t.contains("wasi") => return test_wasi(t), + t if t.contains("android") => return test_android(t), _ => (), } // Pull in extra goodies - if linux || android || emscripten { + if linux || emscripten { cfg.define("_GNU_SOURCE", None); } else if freebsd { cfg.define("_WITH_GETLINE", None); } - // Android doesn't actually have in_port_t but it's much easier if we - // provide one for us to test against - if android { - cfg.define("in_port_t", Some("uint16_t")); - } - cfg.header("errno.h") .header("fcntl.h") .header("limits.h") @@ -75,7 +68,7 @@ fn do_ctest() { cfg.header("net/if.h"); cfg.header("net/route.h"); cfg.header("net/if_arp.h"); - if linux || android { + if linux { cfg.header("linux/if_alg.h"); } cfg.header("netdb.h"); @@ -116,41 +109,27 @@ fn do_ctest() { cfg.header("sys/statvfs.h"); cfg.header("sys/times.h"); - if android { - if !aarch64 && !x86_64 { - // time64_t is not define for aarch64 and x86_64 - // If included it will generate the error 'Your time_t is already 64-bit' - cfg.header("time64.h"); - } - cfg.header("arpa/inet.h"); - cfg.header("xlocale.h"); - cfg.header("ifaddrs.h"); - if i686 || x86_64 { - cfg.header("sys/reg.h"); - } - } else { - cfg.header("glob.h"); - cfg.header("ifaddrs.h"); - cfg.header("langinfo.h"); + cfg.header("glob.h"); + cfg.header("ifaddrs.h"); + cfg.header("langinfo.h"); - if !openbsd && !freebsd { - cfg.header("sys/quota.h"); + if !openbsd && !freebsd { + cfg.header("sys/quota.h"); + } + + if !musl && !x32 { + cfg.header("sys/sysctl.h"); + } + + if !musl && !uclibc { + if !openbsd && !uclibc { + cfg.header("execinfo.h"); } - if !musl && !x32 { - cfg.header("sys/sysctl.h"); - } - - if !musl && !uclibc { - if !openbsd && !uclibc { - cfg.header("execinfo.h"); - } - - if openbsd { - cfg.header("utmp.h"); - } else { - cfg.header("utmpx.h"); - } + if openbsd { + cfg.header("utmp.h"); + } else { + cfg.header("utmpx.h"); } } @@ -192,7 +171,7 @@ fn do_ctest() { } } - if linux || android || emscripten { + if linux || emscripten { cfg.header("malloc.h"); cfg.header("net/ethernet.h"); cfg.header("netpacket/packet.h"); @@ -232,7 +211,7 @@ fn do_ctest() { } } - if linux || android { + if linux { cfg.header("sys/fsuid.h"); cfg.header("linux/module.h"); cfg.header("linux/seccomp.h"); @@ -307,7 +286,6 @@ fn do_ctest() { } }); - let target2 = target.clone(); cfg.field_name(move |struct_, field| { match field { "st_birthtime" if openbsd && struct_ == "stat" => { @@ -319,11 +297,7 @@ fn do_ctest() { // Our stat *_nsec fields normally don't actually exist but are part // of a timeval struct s if s.ends_with("_nsec") && struct_.starts_with("stat") => { - if target2.contains("android") { - s.to_string() - } else { - s.replace("e_nsec", ".tv_nsec") - } + s.replace("e_nsec", ".tv_nsec") } "u64" if struct_ == "epoll_event" => "data.u64".to_string(), "type_" @@ -364,11 +338,6 @@ fn do_ctest() { // definition. Because it's tested on other Linux targets, skip it. "input_mask" if musl => true, - // These structs have changed since unified headers in NDK r14b. - // `st_atime` and `st_atime_nsec` have changed sign. - // FIXME: unskip it for next major release - "stat" | "stat64" if android => true, - // These are tested as part of the linux_fcntl tests since there are // header conflicts when including them with all the other structs. "termios2" => true, @@ -483,13 +452,13 @@ fn do_ctest() { true } - // Both android and musl use old kernel headers + // musl uses old kernel headers // These are constants used in getrandom syscall - "GRND_NONBLOCK" | "GRND_RANDOM" if musl || android => true, + "GRND_NONBLOCK" | "GRND_RANDOM" if musl => true, // Defined by libattr not libc on linux (hard to test). // See constant definition for more details. - "ENOATTR" if android || linux => true, + "ENOATTR" if linux => true, // On mips*-unknown-linux-gnu* CMSPAR cannot be included with the set of headers we // want to use here for testing. It's originally defined in asm/termbits.h, which is @@ -520,7 +489,7 @@ fn do_ctest() { // x86_64 and i686 builders it seems to be available for all targets, so at least test // it there. "MFD_HUGETLB" - if !(x86_64 || i686) || musl || (x86_64 && android) => + if !(x86_64 || i686) || musl => { true } @@ -584,13 +553,9 @@ fn do_ctest() { // send*/recv* syscalls "sendmmsg" | "recvmmsg" if musl => true, - // typed 2nd arg on linux and android - "gettimeofday" if linux || android || freebsd || openbsd => true, + // typed 2nd arg on linux + "gettimeofday" if linux || freebsd || openbsd => true, - // not declared in newer android toolchains - "getdtablesize" if android => true, - - "dlerror" if android => true, // const-ness is added "dladdr" if musl => true, // const-ness only added recently // There seems to be a small error in EGLIBC's eventfd.h header. The @@ -625,10 +590,6 @@ fn do_ctest() { "lio_listio" if freebsd => true, "lio_listio" if musl => true, - // Apparently the NDK doesn't have this defined on android, but - // it's in a header file? - "endpwent" if android => true, - // These are either unimplemented or optionally built into uClibc // or "sysinfo", where it's defined but the structs in linux/sysinfo.h and sys/sysinfo.h // clash so it can't be tested @@ -639,20 +600,11 @@ fn do_ctest() { "sysinfo" | "newlocale" | "duplocale" | "freelocale" | "uselocale" | "nl_langinfo_l" | "wcslen" | "wcstombs" if uclibc => true, - // Apparently res_init exists on Android, but isn't defined in a header: - // https://mail.gnome.org/archives/commits-list/2013-May/msg01329.html - "res_init" if android => true, - // Definition of those functions as changed since unified headers from NDK r14b // These changes imply some API breaking changes but are still ABI compatible. // We can wait for the next major release to be compliant with the new API. // FIXME: unskip these for next major release "strerror_r" | "madvise" | "msync" | "mprotect" | "recvfrom" | "getpriority" | - "setpriority" | "personality" if android => true, - // In Android 64 bits, these functions have been fixed since unified headers. - // Ignore these until next major version. - "bind" | "writev" | "readv" | "sendmsg" | "recvmsg" if android && (aarch64 || x86_64) => true, - // Removed in OpenBSD 6.5 // https://marc.info/?l=openbsd-cvs&m=154723400730318 "mincore" if openbsd => true, @@ -661,14 +613,6 @@ fn do_ctest() { } }); - cfg.skip_static(move |name| { - match name { - // Internal constant, not declared in any headers. - "__progname" if android => true, - _ => false, - } - }); - cfg.skip_field_type(move |struct_, field| { // This is a weird union, don't check the type. (struct_ == "ifaddrs" && field == "ifa_ifu") || @@ -711,14 +655,14 @@ fn do_ctest() { cfg.generate("../src/lib.rs", "main.rs"); - // On Linux or Android also generate another script for testing linux/fcntl declarations. + // On Linux also generate another script for testing linux/fcntl declarations. // These cannot be tested normally because including both `linux/fcntl.h` and `fcntl.h` // fails on a lot of platforms. let mut cfg = ctest::TestGenerator::new(); cfg.skip_type(|_| true) .skip_fn(|_| true) .skip_static(|_| true); - if android || linux { + if linux { // musl defines these directly in `fcntl.h` if musl { cfg.header("fcntl.h"); @@ -1839,7 +1783,7 @@ fn test_dragonflybsd(target: &str) { "getrlimit" | "getrlimit64" | // non-int in 1st arg "setrlimit" | "setrlimit64" | // non-int in 1st arg "prlimit" | "prlimit64" | // non-int in 2nd arg - // typed 2nd arg on linux and android + // typed 2nd arg on linux "gettimeofday" => true, _ => false, @@ -1937,3 +1881,357 @@ fn test_wasi(target: &str) { cfg.generate("../src/lib.rs", "main.rs"); } + +fn test_android(target: &str) { + assert!(target.contains("android")); + let target_pointer_width = match target { + t if t.contains("aarch64") || t.contains("x86_64") => 64, + t if t.contains("i686") || t.contains("arm") => 32, + t => panic!("unsupported target: {}", t), + }; + let x86 = target.contains("i686") || target.contains("x86_64"); + + let mut cfg = ctest::TestGenerator::new(); + cfg.define("_GNU_SOURCE", None); + + // FIXME: still necessary? + cfg.flag("-Wno-deprecated-declarations"); + + // Android doesn't actually have in_port_t but it's much easier if we + // provide one for us to test against + // FIXME: still necessary? + cfg.define("in_port_t", Some("uint16_t")); + + headers! { cfg: + "arpa/inet.h", + "asm/mman.h", + "ctype.h", + "dirent.h", + "dlfcn.h", + "errno.h", + "fcntl.h", + "grp.h", + "ifaddrs.h", + "limits.h", + "linux/dccp.h", + "linux/fs.h", + "linux/genetlink.h", + "linux/if_alg.h", + "linux/if_ether.h", + "linux/if_tun.h", + "linux/magic.h", + "linux/memfd.h", + "linux/module.h", + "linux/net_tstamp.h", + "linux/netfilter/nf_tables.h", + "linux/netfilter_ipv4.h", + "linux/netfilter_ipv6.h", + "linux/netlink.h", + "linux/quota.h", + "linux/reboot.h", + "linux/seccomp.h", + "linux/sockios.h", + "locale.h", + "malloc.h", + "net/ethernet.h", + "net/if.h", + "net/if_arp.h", + "net/route.h", + "netdb.h", + "netinet/in.h", + "netinet/ip.h", + "netinet/tcp.h", + "netinet/udp.h", + "netpacket/packet.h", + "poll.h", + "pthread.h", + "pty.h", + "pwd.h", + "resolv.h", + "sched.h", + "semaphore.h", + "signal.h", + "stddef.h", + "stdint.h", + "stdio.h", + "stdlib.h", + "string.h", + "sys/epoll.h", + "sys/eventfd.h", + "sys/file.h", + "sys/fsuid.h", + "sys/inotify.h", + "sys/ioctl.h", + "sys/mman.h", + "sys/mount.h", + "sys/personality.h", + "sys/prctl.h", + "sys/ptrace.h", + "sys/reboot.h", + "sys/resource.h", + "sys/sendfile.h", + "sys/signalfd.h", + "sys/socket.h", + "sys/stat.h", + "sys/statvfs.h", + "sys/swap.h", + "sys/syscall.h", + "sys/sysinfo.h", + "sys/time.h", + "sys/times.h", + "sys/types.h", + "sys/uio.h", + "sys/un.h", + "sys/utsname.h", + "sys/vfs.h", + "sys/wait.h", + "syslog.h", + "termios.h", + "time.h", + "unistd.h", + "utime.h", + "utmp.h", + "wchar.h", + "xlocale.h", + } + + if target_pointer_width == 32 { + // time64_t is not defined for 64-bit targets If included it will + // generate the error 'Your time_t is already 64-bit' + cfg.header("time64.h"); + } + if x86 { + cfg.header("sys/reg.h"); + } + + cfg.type_name(move |ty, is_struct, is_union| { + match ty { + // Just pass all these through, no need for a "struct" prefix + // FIXME: still required ? + "FILE" | "fd_set" | "Dl_info" | "DIR" | "Elf32_Phdr" + | "Elf64_Phdr" | "Elf32_Shdr" | "Elf64_Shdr" | "Elf32_Sym" + | "Elf64_Sym" | "Elf32_Ehdr" | "Elf64_Ehdr" | "Elf32_Chdr" + | "Elf64_Chdr" => ty.to_string(), + + t if is_union => format!("union {}", t), + + t if t.ends_with("_t") => t.to_string(), + + // put `struct` in front of all structs:. + t if is_struct => format!("struct {}", t), + + t => t.to_string(), + } + }); + + cfg.field_name(move |struct_, field| { + match field { + // Our stat *_nsec fields normally don't actually exist but are part + // of a timeval struct + s if s.ends_with("_nsec") && struct_.starts_with("stat") => { + s.to_string() + } + // FIXME: still necessary? + "u64" if struct_ == "epoll_event" => "data.u64".to_string(), + s => s.to_string(), + } + }); + + cfg.skip_type(move |ty| { + match ty { + // sighandler_t is crazy across platforms + // FIXME: still necessary? + "sighandler_t" => true, + _ => false, + } + }); + + cfg.skip_struct(move |ty| { + match ty { + // This is actually a union, not a struct + // FIXME: still necessary + "sigval" => true, + + // These structs have changed since unified headers in NDK r14b. + // `st_atime` and `st_atime_nsec` have changed sign. + // FIXME: unskip it for next major release + "stat" | "stat64" => true, + + // These are tested as part of the linux_fcntl tests since there are + // header conflicts when including them with all the other structs. + // FIXME: still necessary + "termios2" => true, + + _ => false, + } + }); + + cfg.skip_signededness(move |c| { + match c { + // FIXME: still necessary? + "LARGE_INTEGER" | "float" | "double" => true, + // FIXME: still necessary? + n if n.starts_with("pthread") => true, + _ => false, + } + }); + + cfg.skip_const(move |name| { + match name { + // FIXME: still necessary? + "SIG_DFL" | "SIG_ERR" | "SIG_IGN" => true, // sighandler_t weirdness + // FIXME: still necessary? + "SIGUNUSED" => true, // removed in glibc 2.26 + + // weird signed extension or something like that? + // FIXME: still necessary? + "MS_NOUSER" => true, + // FIXME: still necessary? + "MS_RMT_MASK" => true, // updated in glibc 2.22 and musl 1.1.13 + + // Android uses old kernel headers + // These are constants used in getrandom syscall + // FIXME: still necessary? + "GRND_NONBLOCK" | "GRND_RANDOM" => true, + + // Defined by libattr not libc on linux (hard to test). + // See constant definition for more details. + // FIXME: still necessary? + "ENOATTR" => true, + + // FIXME: still necessary? + "BOTHER" => true, + + // MFD_HUGETLB is not available in some older libc versions on the CI builders. On the + // x86_64 and i686 builders it seems to be available for all targets, so at least test + // it there. + // FIXME: still necessary? + "MFD_HUGETLB" => true, + + // These change all the time from release to release of linux + // distros, let's just not bother trying to verify them. They + // shouldn't be used in code anyway... + // FIXME: still necessary? + "AF_MAX" | "PF_MAX" => true, + + _ => false, + } + }); + + cfg.skip_fn(move |name| { + // skip those that are manually verified + match name { + // FIXME: still necessary? + "execv" | // crazy stuff with const/mut + "execve" | + "execvp" | + "execvpe" | + "fexecve" => true, + + // typed 2nd arg on android + // FIXME: still necessary? + "gettimeofday" => true, + + // not declared in newer android toolchains + // FIXME: still necessary? + "getdtablesize" => true, + + // FIXME: still necessary? + "dlerror" => true, // const-ness is added + + // Apparently the NDK doesn't have this defined on android, but + // it's in a header file? + // FIXME: still necessary? + "endpwent" => true, + + // Apparently res_init exists on Android, but isn't defined in a header: + // https://mail.gnome.org/archives/commits-list/2013-May/msg01329.html + // FIXME: still necessary? + "res_init" => true, + + // Definition of those functions as changed since unified headers from NDK r14b + // These changes imply some API breaking changes but are still ABI compatible. + // We can wait for the next major release to be compliant with the new API. + // FIXME: unskip these for next major release + "strerror_r" | "madvise" | "msync" | "mprotect" | "recvfrom" | "getpriority" | + "setpriority" | "personality" => true, + // In Android 64 bits, these functions have been fixed since unified headers. + // Ignore these until next major version. + "bind" | "writev" | "readv" | "sendmsg" | "recvmsg" + if target_pointer_width == 64 => true, + + _ => false, + } + }); + + cfg.skip_static(move |name| { + match name { + // Internal constant, not declared in any headers. + // FIXME: still necessary + "__progname" => true, + _ => false, + } + }); + + // FIXME: still necessary? + cfg.skip_field_type(move |struct_, field| { + // This is a weird union, don't check the type. + (struct_ == "ifaddrs" && field == "ifa_ifu") || + // sighandler_t type is super weird + (struct_ == "sigaction" && field == "sa_sigaction") || + // sigval is actually a union, but we pretend it's a struct + (struct_ == "sigevent" && field == "sigev_value") || + // aio_buf is "volatile void*" and Rust doesn't understand volatile + (struct_ == "aiocb" && field == "aio_buf") + }); + + // FIXME: still necessary? + cfg.skip_field(move |struct_, field| { + // this is actually a union on linux, so we can't represent it well and + // just insert some padding. + (struct_ == "siginfo_t" && field == "_pad") || + // sigev_notify_thread_id is actually part of a sigev_un union + (struct_ == "sigevent" && field == "sigev_notify_thread_id") || + // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet. + (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || + field == "_pad2" || + field == "ssi_syscall" || + field == "ssi_call_addr" || + field == "ssi_arch")) + }); + + // FIXME: remove + cfg.fn_cname(move |name, _cname| name.to_string()); + + cfg.generate("../src/lib.rs", "main.rs"); + + // On Android also generate another script for testing linux/fcntl + // declarations. These cannot be tested normally because including both + // `linux/fcntl.h` and `fcntl.h` fails. + // + // FIXME: is still necessary? + let mut cfg = ctest::TestGenerator::new(); + cfg.skip_type(|_| true) + .skip_fn(|_| true) + .skip_static(|_| true); + cfg.header("linux/fcntl.h"); + cfg.header("net/if.h"); + cfg.header("linux/if.h"); + cfg.header("linux/quota.h"); + cfg.header("asm/termbits.h"); + cfg.skip_const(move |name| match name { + "F_CANCELLK" | "F_ADD_SEALS" | "F_GET_SEALS" => false, + "F_SEAL_SEAL" | "F_SEAL_SHRINK" | "F_SEAL_GROW" | "F_SEAL_WRITE" => { + false + } + "BOTHER" => false, + _ => true, + }); + cfg.skip_struct(|s| s != "termios2"); + cfg.type_name(move |ty, is_struct, is_union| match ty { + t if is_struct => format!("struct {}", t), + t if is_union => format!("union {}", t), + t => t.to_string(), + }); + cfg.generate("../src/lib.rs", "linux_fcntl.rs"); +}