diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2016-04-25 13:39:05 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2016-04-27 09:28:48 -0700 |
| commit | c31e2e77ed955faafffe7b22859f045cc1e5deec (patch) | |
| tree | f5e315e9518b6c78f18b40a55d70bcc0da86db56 /src | |
| parent | cfae4dea875ddcc5f23481106a149ea15b6be1e5 (diff) | |
| download | rust-c31e2e77ed955faafffe7b22859f045cc1e5deec.tar.gz rust-c31e2e77ed955faafffe7b22859f045cc1e5deec.zip | |
std: Add compatibility with android-9
The Gecko folks currently use Android API level 9 for their builds, so they're requesting that we move back our minimum supported API level from 18 to 9. Turns out, ABI-wise at least, there's not that many changes we need to take care of. The `ftruncate64` API appeared in android-12 and the `log2` and `log2f` APIs appeared in android-18. We can have a simple shim for `ftruncate64` which falls back on `ftruncate` and the `log2` function can be approximated with just `ln(f) / ln(2)`. This should at least get the standard library building on API level 9, although the tests aren't quite happening there just yet. As we seem to be growing a number of Android compatibility shims, they're now centralized in a common `sys::android` module.
Diffstat (limited to 'src')
| -rw-r--r-- | src/libstd/num/f32.rs | 5 | ||||
| -rw-r--r-- | src/libstd/num/f64.rs | 7 | ||||
| -rw-r--r-- | src/libstd/sys/unix/android.rs | 119 | ||||
| -rw-r--r-- | src/libstd/sys/unix/fs.rs | 11 | ||||
| -rw-r--r-- | src/libstd/sys/unix/mod.rs | 32 |
5 files changed, 138 insertions, 36 deletions
diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 624748f352e..94aa3d6b513 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -646,7 +646,10 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f32 { - unsafe { intrinsics::log2f32(self) } + #[cfg(target_os = "android")] + return ::sys::android::log2f32(self); + #[cfg(not(target_os = "android"))] + return unsafe { intrinsics::log2f32(self) }; } /// Returns the base 10 logarithm of the number. diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 6515301aefd..2beffb64d3d 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -546,7 +546,12 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn log2(self) -> f64 { - self.log_wrapper(|n| { unsafe { intrinsics::log2f64(n) } }) + self.log_wrapper(|n| { + #[cfg(target_os = "android")] + return ::sys::android::log2f64(n); + #[cfg(not(target_os = "android"))] + return unsafe { intrinsics::log2f64(n) }; + }) } /// Returns the base 10 logarithm of the number. diff --git a/src/libstd/sys/unix/android.rs b/src/libstd/sys/unix/android.rs new file mode 100644 index 00000000000..abbe3fc1846 --- /dev/null +++ b/src/libstd/sys/unix/android.rs @@ -0,0 +1,119 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Android ABI-compatibility module +//! +//! The ABI of Android has changed quite a bit over time, and libstd attempts to +//! be both forwards and backwards compatible as much as possible. We want to +//! always work with the most recent version of Android, but we also want to +//! work with older versions of Android for whenever projects need to. +//! +//! Our current minimum supported Android version is `android-9`, e.g. Android +//! with API level 9. We then in theory want to work on that and all future +//! versions of Android! +//! +//! Some of the detection here is done at runtime via `dlopen` and +//! introspection. Other times no detection is performed at all and we just +//! provide a fallback implementation as some versions of Android we support +//! don't have the function. +//! +//! You'll find more details below about why each compatibility shim is needed. + +#![cfg(target_os = "android")] + +use libc::{c_int, sighandler_t}; + +use io; +use sys::cvt_r; + +// The `log2` and `log2f` functions apparently appeared in android-18, or at +// least you can see they're not present in the android-17 header [1] and they +// are present in android-18 [2]. +// +// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms +// /android-17/arch-arm/usr/include/math.h +// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms +// /android-18/arch-arm/usr/include/math.h +// +// Note that these shims are likely less precise than directly calling `log2`, +// but hopefully that should be enough for now... +// +// Note that mathematically, for any arbitrary `y`: +// +// log_2(x) = log_y(x) / log_y(2) +// = log_y(x) / (1 / log_2(y)) +// = log_y(x) * log_2(y) +// +// Hence because `ln` (log_e) is available on all Android we just choose `y = e` +// and get: +// +// log_2(x) = ln(x) * log_2(e) + +#[cfg(not(test))] +pub fn log2f32(f: f32) -> f32 { + f.ln() * ::f32::consts::LOG2_E +} + +#[cfg(not(test))] +pub fn log2f64(f: f64) -> f64 { + f.ln() * ::f64::consts::LOG2_E +} + +// Back in the day [1] the `signal` function was just an inline wrapper +// around `bsd_signal`, but starting in API level android-20 the `signal` +// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was +// removed [3]. +// +// Basically this means that if we want to be binary compatible with multiple +// Android releases (oldest being 9 and newest being 21) then we need to check +// for both symbols and not actually link against either. +// +// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms +// /android-18/arch-arm/usr/include/signal.h +// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental +// /platforms/android-20/arch-arm +// /usr/include/signal.h +// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms +// /android-21/arch-arm/usr/include/signal.h +pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t { + weak!(fn signal(c_int, sighandler_t) -> sighandler_t); + weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t); + + let f = signal.get().or_else(|| bsd_signal.get()); + let f = f.expect("neither `signal` nor `bsd_signal` symbols found"); + f(signum, handler) +} + +// The `ftruncate64` symbol apparently appeared in android-12, so we do some +// dynamic detection to see if we can figure out whether `ftruncate64` exists. +// +// If it doesn't we just fall back to `ftruncate`, generating an error for +// too-large values. +pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { + weak!(fn ftruncate64(c_int, i64) -> c_int); + + extern { + fn ftruncate(fd: c_int, off: i32) -> c_int; + } + + unsafe { + match ftruncate64.get() { + Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()), + None => { + if size > i32::max_value() as u64 { + Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot truncate >2GB")) + } else { + cvt_r(|| ftruncate(fd, size as i32)).map(|_| ()) + } + } + } + } +} diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index d5d17e7ee12..0969a59ea43 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -27,7 +27,7 @@ use sys_common::{AsInner, FromInner}; #[cfg(any(target_os = "linux", target_os = "emscripten"))] use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64}; #[cfg(target_os = "android")] -use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off64_t, ftruncate64, lseek64, +use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off64_t, lseek64, dirent as dirent64, open as open64}; #[cfg(not(any(target_os = "linux", target_os = "emscripten", @@ -475,10 +475,13 @@ impl File { } pub fn truncate(&self, size: u64) -> io::Result<()> { - cvt_r(|| unsafe { + #[cfg(target_os = "android")] + return ::sys::android::ftruncate64(self.0.raw(), size); + + #[cfg(not(target_os = "android"))] + return cvt_r(|| unsafe { ftruncate64(self.0.raw(), size as off64_t) - })?; - Ok(()) + }).map(|_| ()); } pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index f8b2d4dd232..12a877f7478 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -31,6 +31,7 @@ use ops::Neg; #[macro_use] pub mod weak; +pub mod android; pub mod backtrace; pub mod condvar; pub mod ext; @@ -91,37 +92,8 @@ pub fn init() { unsafe fn reset_sigpipe() {} } -// Currently the minimum supported Android version of the standard library is -// API level 18 (android-18). Back in those days [1] the `signal` function was -// just an inline wrapper around `bsd_signal`, but starting in API level -// android-20 the `signal` symbols was introduced [2]. Finally, in android-21 -// the API `bsd_signal` was removed [3]. -// -// Basically this means that if we want to be binary compatible with multiple -// Android releases (oldest being 18 and newest being 21) then we need to check -// for both symbols and not actually link against either. -// -// Note that if we're not on android we just link against the `android` symbol -// itself. -// -// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms -// /android-18/arch-arm/usr/include/signal.h -// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental -// /platforms/android-20/arch-arm -// /usr/include/signal.h -// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms -// /android-21/arch-arm/usr/include/signal.h #[cfg(target_os = "android")] -unsafe fn signal(signum: libc::c_int, - handler: libc::sighandler_t) -> libc::sighandler_t { - weak!(fn signal(libc::c_int, libc::sighandler_t) -> libc::sighandler_t); - weak!(fn bsd_signal(libc::c_int, libc::sighandler_t) -> libc::sighandler_t); - - let f = signal.get().or_else(|| bsd_signal.get()); - let f = f.expect("neither `signal` nor `bsd_signal` symbols found"); - f(signum, handler) -} - +pub use sys::android::signal; #[cfg(not(target_os = "android"))] pub use libc::signal; |
