Skip to content

std: Add compatibility with android-9 #33211

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 28, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/libstd/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion src/libstd/num/f64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
119 changes: 119 additions & 0 deletions src/libstd/sys/unix/android.rs
Original file line number Diff line number Diff line change
@@ -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(|_| ())
}
}
}
}
}
11 changes: 7 additions & 4 deletions src/libstd/sys/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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> {
Expand Down
32 changes: 2 additions & 30 deletions src/libstd/sys/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use ops::Neg;
#[macro_use]
pub mod weak;

pub mod android;
pub mod backtrace;
pub mod condvar;
pub mod ext;
Expand Down Expand Up @@ -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;

Expand Down