Basic iOS support

This commit is contained in:
Valerii Hiora 2014-05-05 10:07:49 +03:00
parent 0c10c68682
commit a49b765f9a
37 changed files with 461 additions and 65 deletions

View File

@ -278,10 +278,13 @@ pub use consts::os::extra::{MAP_STACK};
pub use consts::os::bsd44::{TCP_KEEPIDLE};
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub use consts::os::bsd44::{TCP_KEEPALIVE};
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub use consts::os::extra::{F_FULLFSYNC};
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub use types::os::arch::extra::{mach_timebase_info};
@ -1286,6 +1289,7 @@ pub mod types {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub mod os {
pub mod common {
pub mod posix01 {
@ -3106,6 +3110,7 @@ pub mod consts {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub mod os {
pub mod c95 {
use types::os::arch::c95::{c_int, c_uint};
@ -3769,6 +3774,7 @@ pub mod funcs {
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
pub mod posix88 {
pub mod stat_ {
@ -3783,6 +3789,7 @@ pub mod funcs {
#[cfg(target_os = "linux")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "android")]
#[cfg(target_os = "ios")]
pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
#[cfg(target_os = "macos")]
@ -3795,6 +3802,7 @@ pub mod funcs {
#[cfg(target_os = "linux")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "android")]
#[cfg(target_os = "ios")]
pub fn stat(path: *c_char, buf: *mut stat) -> c_int;
#[cfg(target_os = "macos")]
@ -3967,6 +3975,7 @@ pub mod funcs {
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
pub mod posix01 {
pub mod stat_ {
@ -3977,6 +3986,7 @@ pub mod funcs {
#[cfg(target_os = "linux")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "android")]
#[cfg(target_os = "ios")]
pub fn lstat(path: *c_char, buf: *mut stat) -> c_int;
#[cfg(target_os = "macos")]
@ -4076,6 +4086,7 @@ pub mod funcs {
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
pub mod posix08 {
pub mod unistd {
@ -4156,6 +4167,7 @@ pub mod funcs {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
pub mod bsd44 {
use types::common::c95::{c_void};
@ -4209,6 +4221,7 @@ pub mod funcs {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub mod extra {
use types::os::arch::c95::{c_char, c_int};

View File

@ -20,6 +20,7 @@ pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD};
use libc;
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
pub static FIONBIO: libc::c_ulong = 0x8004667e;
#[cfg(target_os = "linux", not(target_arch = "mips"))]
@ -29,6 +30,7 @@ pub static FIONBIO: libc::c_ulong = 0x5421;
pub static FIONBIO: libc::c_ulong = 0x667e;
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
pub static FIOCLEX: libc::c_ulong = 0x20006601;
#[cfg(target_os = "linux", not(target_arch = "mips"))]
@ -38,6 +40,7 @@ pub static FIOCLEX: libc::c_ulong = 0x5451;
pub static FIOCLEX: libc::c_ulong = 0x6601;
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
pub static MSG_DONTWAIT: libc::c_int = 0x80;
#[cfg(target_os = "linux")]
@ -75,6 +78,7 @@ extern {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
mod select {
pub static FD_SETSIZE: uint = 1024;
@ -187,6 +191,7 @@ mod signal {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
mod signal {
use libc;
@ -201,6 +206,7 @@ mod signal {
pub static SIGCHLD: libc::c_int = 20;
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub type sigset_t = u32;
#[cfg(target_os = "freebsd")]
pub struct sigset_t {
@ -219,6 +225,7 @@ mod signal {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
pub struct sigaction {
pub sa_handler: extern fn(libc::c_int),
sa_tramp: *mut libc::c_void,

View File

@ -133,6 +133,7 @@ impl rtio::RtioFileStream for FileDesc {
return super::mkerr_libc(os_datasync(self.fd()));
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
fn os_datasync(fd: c_int) -> c_int {
unsafe { libc::fcntl(fd, libc::F_FULLFSYNC) }
}
@ -140,7 +141,7 @@ impl rtio::RtioFileStream for FileDesc {
fn os_datasync(fd: c_int) -> c_int {
retry(|| unsafe { libc::fdatasync(fd) })
}
#[cfg(not(target_os = "macos"), not(target_os = "linux"))]
#[cfg(not(target_os = "macos"), not(target_os = "ios"), not(target_os = "linux"))]
fn os_datasync(fd: c_int) -> c_int {
retry(|| unsafe { libc::fsync(fd) })
}

View File

@ -50,6 +50,7 @@ pub mod file;
pub mod file;
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "android")]
#[cfg(target_os = "linux")]

View File

@ -320,6 +320,7 @@ impl TcpStream {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> {
setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
seconds as libc::c_int)
@ -329,7 +330,7 @@ impl TcpStream {
setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
seconds as libc::c_int)
}
#[cfg(not(target_os = "macos"), not(target_os = "freebsd"))]
#[cfg(not(target_os = "macos"), not(target_os = "ios"), not(target_os = "freebsd"))]
fn set_tcp_keepalive(&mut self, _seconds: uint) -> IoResult<()> {
Ok(())
}

View File

@ -769,6 +769,7 @@ fn translate_status(status: c_int) -> rtio::ProcessExit {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
mod imp {
pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 }

View File

@ -93,7 +93,20 @@ pub fn now() -> u64 {
}
}
fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
// Note: although the last parameter isn't used there is no way now to
// convert it to unit type, because LLVM dies in SjLj preparation
// step (unfortunately iOS uses SjLJ exceptions)
//
// It's definitely a temporary workaround just to get it working.
// So far it looks like an LLVM issue and it was reported:
// http://llvm.org/bugs/show_bug.cgi?id=19855
// Actually this issue is pretty common while compiling for armv7 iOS
// and in most cases it is simply solved by using --opt-level=2 (or -O)
//
// For this specific case unfortunately turning optimizations wasn't
// enough.
fn helper(input: libc::c_int, messages: Receiver<Req>, _: int) {
let mut set: c::fd_set = unsafe { mem::zeroed() };
let mut fd = FileDesc::new(input, true);
@ -202,7 +215,9 @@ fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
impl Timer {
pub fn new() -> IoResult<Timer> {
unsafe { HELPER.boot(|| {}, helper); }
// See notes above regarding using int return value
// instead of ()
unsafe { HELPER.boot(|| {0}, helper); }
static mut ID: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
let id = unsafe { ID.fetch_add(1, atomics::Relaxed) };

View File

@ -34,6 +34,14 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
-a0:0:64-n32".to_string()
}
abi::OsiOS => {
"e-p:32:32:32\
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
-f32:32:32-f64:64:64\
-v64:64:64-v128:64:128\
-a0:0:64-n32".to_string()
}
abi::OsWin32 => {
"e-p:32:32:32\
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\

View File

@ -114,6 +114,13 @@ pub mod write {
// which are *far* more efficient. This is obviously undesirable in some
// cases, so if any sort of target feature is specified we don't append v7
// to the feature list.
//
// On iOS only armv7 and newer are supported. So it is useful to
// get all hardware potential via VFP3 (hardware floating point)
// and NEON (SIMD) instructions supported by LLVM.
// Note that without those flags various linking errors might
// arise as some of intrinsicts are converted into function calls
// and nobody provides implementations those functions
fn target_feature<'a>(sess: &'a Session) -> &'a str {
match sess.targ_cfg.os {
abi::OsAndroid => {
@ -122,7 +129,10 @@ pub mod write {
} else {
sess.opts.cg.target_feature.as_slice()
}
}
},
abi::OsiOS if sess.targ_cfg.arch == abi::Arm => {
"+v7,+thumb2,+vfp3,+neon"
},
_ => sess.opts.cg.target_feature.as_slice()
}
}
@ -827,15 +837,23 @@ pub fn filename_for_input(sess: &Session, crate_type: config::CrateType,
out_filename.with_filename(format!("lib{}.rlib", libname))
}
config::CrateTypeDylib => {
let (prefix, suffix) = match sess.targ_cfg.os {
abi::OsWin32 => (loader::WIN32_DLL_PREFIX, loader::WIN32_DLL_SUFFIX),
abi::OsMacos => (loader::MACOS_DLL_PREFIX, loader::MACOS_DLL_SUFFIX),
abi::OsLinux => (loader::LINUX_DLL_PREFIX, loader::LINUX_DLL_SUFFIX),
abi::OsAndroid => (loader::ANDROID_DLL_PREFIX, loader::ANDROID_DLL_SUFFIX),
abi::OsFreebsd => (loader::FREEBSD_DLL_PREFIX, loader::FREEBSD_DLL_SUFFIX),
};
out_filename.with_filename(format!("{}{}{}", prefix, libname,
suffix))
// There is no support of DyLibs on iOS
if sess.targ_cfg.os == abi::OsiOS {
out_filename.with_filename(format!("lib{}.a", libname))
} else {
let (prefix, suffix) = match sess.targ_cfg.os {
abi::OsWin32 => (loader::WIN32_DLL_PREFIX, loader::WIN32_DLL_SUFFIX),
abi::OsMacos => (loader::MACOS_DLL_PREFIX, loader::MACOS_DLL_SUFFIX),
abi::OsLinux => (loader::LINUX_DLL_PREFIX, loader::LINUX_DLL_SUFFIX),
abi::OsAndroid => (loader::ANDROID_DLL_PREFIX, loader::ANDROID_DLL_SUFFIX),
abi::OsFreebsd => (loader::FREEBSD_DLL_PREFIX, loader::FREEBSD_DLL_SUFFIX),
abi::OsiOS => unreachable!(),
};
out_filename.with_filename(format!("{}{}{}",
prefix,
libname,
suffix))
}
}
config::CrateTypeStaticlib => {
out_filename.with_filename(format!("lib{}.a", libname))
@ -886,7 +904,14 @@ fn link_binary_output(sess: &Session,
link_natively(sess, trans, false, &obj_filename, &out_filename);
}
config::CrateTypeDylib => {
link_natively(sess, trans, true, &obj_filename, &out_filename);
if sess.targ_cfg.os == abi::OsiOS {
sess.warn(format!("No dylib for iOS -> saving static library {} to {}",
obj_filename.display(), out_filename.display()).as_slice());
link_staticlib(sess, &obj_filename, &out_filename);
}
else {
link_natively(sess, trans, true, &obj_filename, &out_filename);
}
}
}
@ -991,7 +1016,7 @@ fn link_rlib<'a>(sess: &'a Session,
// symbol table of the archive. This currently dies on OSX (see
// #11162), and isn't necessary there anyway
match sess.targ_cfg.os {
abi::OsMacos => {}
abi::OsMacos | abi::OsiOS => {}
_ => { a.update_symbols(); }
}
}
@ -1104,15 +1129,16 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
// On OSX, debuggers need this utility to get run to do some munging of
// the symbols
if sess.targ_cfg.os == abi::OsMacos && (sess.opts.debuginfo != NoDebugInfo) {
match Command::new("dsymutil").arg(out_filename).status() {
Ok(..) => {}
Err(e) => {
sess.err(format!("failed to run dsymutil: {}", e).as_slice());
sess.abort_if_errors();
if (sess.targ_cfg.os == abi::OsMacos || sess.targ_cfg.os == abi::OsiOS)
&& (sess.opts.debuginfo != NoDebugInfo) {
match Command::new("dsymutil").arg(out_filename).status() {
Ok(..) => {}
Err(e) => {
sess.err(format!("failed to run dsymutil: {}", e).as_slice());
sess.abort_if_errors();
}
}
}
}
}
fn link_args(cmd: &mut Command,
@ -1169,7 +1195,7 @@ fn link_args(cmd: &mut Command,
// already done the best it can do, and we also don't want to eliminate the
// metadata. If we're building an executable, however, --gc-sections drops
// the size of hello world from 1.8MB to 597K, a 67% reduction.
if !dylib && sess.targ_cfg.os != abi::OsMacos {
if !dylib && sess.targ_cfg.os != abi::OsMacos && sess.targ_cfg.os != abi::OsiOS {
cmd.arg("-Wl,--gc-sections");
}
@ -1185,7 +1211,7 @@ fn link_args(cmd: &mut Command,
sess.opts.optimize == config::Aggressive {
cmd.arg("-Wl,-O1");
}
} else if sess.targ_cfg.os == abi::OsMacos {
} else if sess.targ_cfg.os == abi::OsMacos || sess.targ_cfg.os == abi::OsiOS {
// The dead_strip option to the linker specifies that functions and data
// unreachable by the entry point will be removed. This is quite useful
// with Rust's compilation model of compiling libraries at a time into
@ -1348,7 +1374,7 @@ fn add_local_native_libraries(cmd: &mut Command, sess: &Session) {
// For those that support this, we ensure we pass the option if the library
// was flagged "static" (most defaults are dynamic) to ensure that if
// libfoo.a and libfoo.so both exist that the right one is chosen.
let takes_hints = sess.targ_cfg.os != abi::OsMacos;
let takes_hints = sess.targ_cfg.os != abi::OsMacos && sess.targ_cfg.os != abi::OsiOS;
for &(ref l, kind) in sess.cstore.get_used_libraries().borrow().iter() {
match kind {

View File

@ -29,6 +29,14 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
-a0:0:64-n32".to_string()
}
abi::OsiOS => {
"E-p:32:32:32\
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\
-f32:32:32-f64:64:64\
-v64:64:64-v128:64:128\
-a0:0:64-n32".to_string()
}
abi::OsWin32 => {
"E-p:32:32:32\
-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64\

View File

@ -122,7 +122,7 @@ pub fn get_rpath_relative_to_output(os: abi::Os,
abi::OsAndroid | abi::OsLinux | abi::OsFreebsd
=> "$ORIGIN",
abi::OsMacos => "@loader_path",
abi::OsWin32 => unreachable!()
abi::OsWin32 | abi::OsiOS => unreachable!()
};
let mut lib = fs::realpath(&os::make_absolute(lib)).unwrap();

View File

@ -31,6 +31,14 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os)
-n8:16:32".to_string()
}
abi::OsiOS => {
"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16\
-i32:32:32-i64:32:64\
-f32:32:32-f64:32:64-v64:64:64\
-v128:128:128-a0:0:64-f80:128:128\
-n8:16:32".to_string()
}
abi::OsWin32 => {
"e-p:32:32-f64:64:64-i64:64:64-f80:32:32-n8:16:32".to_string()
}

View File

@ -28,6 +28,12 @@ pub fn get_target_strs(target_triple: String, target_os: abi::Os) -> target_strs
s0:64:64-f80:128:128-n8:16:32:64".to_string()
}
abi::OsiOS => {
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-\
s0:64:64-f80:128:128-n8:16:32:64".to_string()
}
abi::OsWin32 => {
// FIXME: Test this. Copied from linux (#2398)
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\

View File

@ -362,7 +362,8 @@ pub fn cfg_os_to_meta_os(os: abi::Os) -> metadata::loader::Os {
abi::OsLinux => loader::OsLinux,
abi::OsAndroid => loader::OsAndroid,
abi::OsMacos => loader::OsMacos,
abi::OsFreebsd => loader::OsFreebsd
abi::OsFreebsd => loader::OsFreebsd,
abi::OsiOS => loader::OsiOS,
}
}
@ -373,6 +374,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
abi::OsLinux => InternedString::new("linux"),
abi::OsAndroid => InternedString::new("android"),
abi::OsFreebsd => InternedString::new("freebsd"),
abi::OsiOS => InternedString::new("ios"),
};
// ARM is bi-endian, however using NDK seems to default
@ -438,7 +440,8 @@ static os_names : &'static [(&'static str, abi::Os)] = &'static [
("darwin", abi::OsMacos),
("android", abi::OsAndroid),
("linux", abi::OsLinux),
("freebsd", abi::OsFreebsd)];
("freebsd", abi::OsFreebsd),
("ios", abi::OsiOS)];
pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
for &(arch, abi) in architecture_abis.iter() {

View File

@ -249,4 +249,3 @@ pub fn expect<T:Clone>(sess: &Session, opt: Option<T>, msg: || -> String)
-> T {
diagnostic::expect(sess.diagnostic(), opt, msg)
}

View File

@ -215,7 +215,8 @@ fn visit_item(e: &Env, i: &ast::Item) {
Some(k) => {
if k.equiv(&("static")) {
cstore::NativeStatic
} else if e.sess.targ_cfg.os == abi::OsMacos &&
} else if (e.sess.targ_cfg.os == abi::OsMacos ||
e.sess.targ_cfg.os == abi::OsiOS) &&
k.equiv(&("framework")) {
cstore::NativeFramework
} else if k.equiv(&("framework")) {

View File

@ -39,6 +39,9 @@ use time;
pub static MACOS_DLL_PREFIX: &'static str = "lib";
pub static MACOS_DLL_SUFFIX: &'static str = ".dylib";
pub static IOS_DLL_PREFIX: &'static str = "lib";
pub static IOS_DLL_SUFFIX: &'static str = ".dylib";
pub static WIN32_DLL_PREFIX: &'static str = "";
pub static WIN32_DLL_SUFFIX: &'static str = ".dll";
@ -56,7 +59,8 @@ pub enum Os {
OsWin32,
OsLinux,
OsAndroid,
OsFreebsd
OsFreebsd,
OsiOS
}
pub struct CrateMismatch {
@ -455,6 +459,7 @@ impl<'a> Context<'a> {
OsLinux => (LINUX_DLL_PREFIX, LINUX_DLL_SUFFIX),
OsAndroid => (ANDROID_DLL_PREFIX, ANDROID_DLL_SUFFIX),
OsFreebsd => (FREEBSD_DLL_PREFIX, FREEBSD_DLL_SUFFIX),
OsiOS => (IOS_DLL_PREFIX, IOS_DLL_SUFFIX),
}
}
@ -593,6 +598,7 @@ fn get_metadata_section_imp(os: Os, filename: &Path) -> Result<MetadataBlob, Str
pub fn meta_section_name(os: Os) -> &'static str {
match os {
OsMacos => "__DATA,__note.rustc",
OsiOS => "__DATA,__note.rustc",
OsWin32 => ".note.rustc",
OsLinux => ".note.rustc",
OsAndroid => ".note.rustc",
@ -603,6 +609,7 @@ pub fn meta_section_name(os: Os) -> &'static str {
pub fn read_meta_section_name(os: Os) -> &'static str {
match os {
OsMacos => "__note.rustc",
OsiOS => "__note.rustc",
OsWin32 => ".note.rustc",
OsLinux => ".note.rustc",
OsAndroid => ".note.rustc",

View File

@ -9,7 +9,7 @@
// except according to those terms.
use syntax::abi::{OsWin32, OsMacos};
use syntax::abi::{OsWin32, OsMacos, OsiOS};
use lib::llvm::*;
use super::cabi::*;
use super::common::*;
@ -36,7 +36,7 @@ pub fn compute_abi_info(ccx: &CrateContext,
enum Strategy { RetValue(Type), RetPointer }
let strategy = match ccx.sess().targ_cfg.os {
OsWin32 | OsMacos => {
OsWin32 | OsMacos | OsiOS => {
match llsize_of_alloc(ccx, rty) {
1 => RetValue(Type::i8(ccx)),
2 => RetValue(Type::i16(ccx)),

View File

@ -680,7 +680,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> {
Some(llpersonality) => llpersonality,
None => {
let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
let f = base::decl_cdecl_fn(self.ccx.llmod,
let f = base::decl_cdecl_fn(self.ccx,
"rust_eh_personality",
fty,
ty::mk_i32());

View File

@ -277,7 +277,8 @@ pub fn finalize(cx: &CrateContext) {
// instruct LLVM to emit an older version of dwarf, however,
// for OS X to understand. For more info see #11352
// This can be overridden using --llvm-opts -dwarf-version,N.
if cx.sess().targ_cfg.os == abi::OsMacos {
if cx.sess().targ_cfg.os == abi::OsMacos ||
cx.sess().targ_cfg.os == abi::OsiOS {
"Dwarf Version".with_c_str(
|s| llvm::LLVMRustAddModuleFlag(cx.llmod, s, 2));
} else {

View File

@ -64,6 +64,7 @@ mod imp {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
mod os {
use libc;

View File

@ -145,6 +145,7 @@ mod imp {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "win32")]
mod imp {
use core::prelude::*;

View File

@ -164,7 +164,7 @@ pub unsafe fn cleanup() {
pub mod shouldnt_be_public {
#[cfg(not(test))]
pub use super::local_ptr::native::maybe_tls_key;
#[cfg(not(windows), not(target_os = "android"))]
#[cfg(not(windows), not(target_os = "android"), not(target_os = "ios"))]
pub use super::local_ptr::compiled::RT_TLS_PTR;
}

View File

@ -17,6 +17,7 @@
use libc;
#[cfg(not(target_arch = "arm"))]
#[cfg(target_os = "ios")]
#[repr(C)]
pub enum _Unwind_Action {
_UA_SEARCH_PHASE = 1,
@ -61,9 +62,12 @@ pub static unwinder_private_data_size: int = 5;
#[cfg(target_arch = "x86_64")]
pub static unwinder_private_data_size: int = 2;
#[cfg(target_arch = "arm")]
#[cfg(target_arch = "arm", not(target_os = "ios"))]
pub static unwinder_private_data_size: int = 20;
#[cfg(target_arch = "arm", target_os = "ios")]
pub static unwinder_private_data_size: int = 5;
#[cfg(target_arch = "mips")]
pub static unwinder_private_data_size: int = 2;
@ -89,8 +93,27 @@ extern {}
#[link(name = "gcc")]
extern {}
extern "C" {
// iOS on armv7 uses SjLj exceptions and requires to link
// agains corresponding routine (..._SjLj_...)
// So here we just skip linking for iOS
#[cfg(not(target_os = "ios", target_arch = "arm"))]
pub fn _Unwind_RaiseException(exception: *_Unwind_Exception)
-> _Unwind_Reason_Code;
pub fn _Unwind_DeleteException(exception: *_Unwind_Exception);
}
// ... and now we just providing access to SjLj counterspart
// through a standard name to hide those details from others
// (see also comment above regarding _Unwind_RaiseException)
#[cfg(target_os = "ios", target_arch = "arm")]
#[inline(always)]
pub unsafe fn _Unwind_RaiseException(exc: *_Unwind_Exception)
-> _Unwind_Reason_Code {
extern "C" {
fn _Unwind_SjLj_RaiseException(e: *_Unwind_Exception)
-> _Unwind_Reason_Code; }
_Unwind_SjLj_RaiseException(exc)
}

View File

@ -24,10 +24,11 @@ use alloc::owned::Box;
#[cfg(windows)] // mingw-w32 doesn't like thread_local things
#[cfg(target_os = "android")] // see #10686
#[cfg(target_os = "ios")]
pub use self::native::{init, cleanup, put, take, try_take, unsafe_take, exists,
unsafe_borrow, try_unsafe_borrow};
#[cfg(not(windows), not(target_os = "android"))]
#[cfg(not(windows), not(target_os = "android"), not(target_os = "ios"))]
pub use self::compiled::{init, cleanup, put, take, try_take, unsafe_take, exists,
unsafe_borrow, try_unsafe_borrow};
@ -81,7 +82,7 @@ pub unsafe fn borrow<T>() -> Borrowed<T> {
/// implemented using LLVM's thread_local attribute which isn't necessarily
/// working on all platforms. This implementation is faster, however, so we use
/// it wherever possible.
#[cfg(not(windows), not(target_os = "android"))]
#[cfg(not(windows), not(target_os = "android"), not(target_os = "ios"))]
pub mod compiled {
use core::prelude::*;

View File

@ -283,6 +283,7 @@ mod imp {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
mod os {
use libc;
@ -294,6 +295,10 @@ mod imp {
static __PTHREAD_MUTEX_SIZE__: uint = 40;
#[cfg(target_arch = "x86")]
static __PTHREAD_COND_SIZE__: uint = 24;
#[cfg(target_arch = "arm")]
static __PTHREAD_MUTEX_SIZE__: uint = 40;
#[cfg(target_arch = "arm")]
static __PTHREAD_COND_SIZE__: uint = 24;
static _PTHREAD_MUTEX_SIG_init: libc::c_long = 0x32AAABA7;
static _PTHREAD_COND_SIG_init: libc::c_long = 0x3CB0B1BB;

View File

@ -173,7 +173,8 @@ pub unsafe fn record_sp_limit(limit: uint) {
return target_record_sp_limit(limit);
// x86-64
#[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)]
#[cfg(target_arch = "x86_64", target_os = "macos")]
#[cfg(target_arch = "x86_64", target_os = "ios")] #[inline(always)]
unsafe fn target_record_sp_limit(limit: uint) {
asm!("movq $$0x60+90*8, %rsi
movq $0, %gs:(%rsi)" :: "r"(limit) : "rsi" : "volatile")
@ -195,7 +196,8 @@ pub unsafe fn record_sp_limit(limit: uint) {
}
// x86
#[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)]
#[cfg(target_arch = "x86", target_os = "macos")]
#[cfg(target_arch = "x86", target_os = "ios")] #[inline(always)]
unsafe fn target_record_sp_limit(limit: uint) {
asm!("movl $$0x48+90*4, %eax
movl $0, %gs:(%eax)" :: "r"(limit) : "eax" : "volatile")
@ -243,7 +245,8 @@ pub unsafe fn get_sp_limit() -> uint {
return target_get_sp_limit();
// x86-64
#[cfg(target_arch = "x86_64", target_os = "macos")] #[inline(always)]
#[cfg(target_arch = "x86_64", target_os = "macos")]
#[cfg(target_arch = "x86_64", target_os = "ios")] #[inline(always)]
unsafe fn target_get_sp_limit() -> uint {
let limit;
asm!("movq $$0x60+90*8, %rsi
@ -270,7 +273,8 @@ pub unsafe fn get_sp_limit() -> uint {
}
// x86
#[cfg(target_arch = "x86", target_os = "macos")] #[inline(always)]
#[cfg(target_arch = "x86", target_os = "macos")]
#[cfg(target_arch = "x86", target_os = "ios")] #[inline(always)]
unsafe fn target_get_sp_limit() -> uint {
let limit;
asm!("movl $$0x48+90*4, %eax

View File

@ -276,7 +276,6 @@ mod imp {
}
pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); }
// glibc >= 2.15 has a __pthread_get_minstack() function that returns
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
// storage. We need that information to avoid blowing up when a small stack
@ -345,4 +344,3 @@ mod tests {
assert_eq!(42, Thread::start_stack(1, proc () 42).join());
}
}

View File

@ -37,13 +37,14 @@ pub unsafe fn destroy(key: Key) {
assert!(pthread_key_delete(key) == 0);
}
#[cfg(target_os="macos")]
#[cfg(target_os = "macos")]
#[allow(non_camel_case_types)] // foreign type
type pthread_key_t = ::libc::c_ulong;
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
#[cfg(target_os="android")]
#[cfg(target_os = "ios")]
#[allow(non_camel_case_types)] // foreign type
type pthread_key_t = ::libc::c_uint;

View File

@ -285,16 +285,74 @@ pub mod eabi {
}
else { // cleanup phase
unsafe {
__gcc_personality_v0(version, actions, exception_class, ue_header,
__gcc_personality_v0(version, actions, exception_class, ue_header,
context)
}
}
}
}
// iOS on armv7 is using SjLj exceptions and therefore requires to use
// a specialized personality routine: __gcc_personality_sj0
#[cfg(target_os = "ios", target_arch = "arm", not(test))]
#[doc(hidden)]
#[allow(visible_private_types)]
pub mod eabi {
use uw = libunwind;
use libc::c_int;
extern "C" {
#[cfg(target_os = "ios", target_arch = "arm")]
fn __gcc_personality_sj0(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
ue_header: *uw::_Unwind_Exception,
context: *uw::_Unwind_Context)
-> uw::_Unwind_Reason_Code;
}
#[lang="eh_personality"]
#[no_mangle] // so we can reference it by name from middle/trans/base.rs
pub extern "C" fn rust_eh_personality(
version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
ue_header: *uw::_Unwind_Exception,
context: *uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code
{
unsafe {
__gcc_personality_sj0(version, actions, exception_class, ue_header,
context)
}
}
#[no_mangle] // referenced from rust_try.ll
pub extern "C" fn rust_eh_personality_catch(
version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
ue_header: *uw::_Unwind_Exception,
context: *uw::_Unwind_Context
) -> uw::_Unwind_Reason_Code
{
if (actions as c_int & uw::_UA_SEARCH_PHASE as c_int) != 0 { // search phase
uw::_URC_HANDLER_FOUND // catch!
}
else { // cleanup phase
unsafe {
__gcc_personality_sj0(version, actions, exception_class, ue_header,
context)
}
}
}
}
// ARM EHABI uses a slightly different personality routine signature,
// but otherwise works the same.
#[cfg(target_arch = "arm", not(test))]
#[cfg(target_arch = "arm", not(test), not(target_os = "ios"))]
#[allow(visible_private_types)]
pub mod eabi {
use uw = libunwind;
@ -332,7 +390,7 @@ pub mod eabi {
}
else { // cleanup phase
unsafe {
__gcc_personality_v0(state, ue_header, context)
__gcc_personality_v0(state, ue_header, context)
}
}
}

View File

@ -153,7 +153,7 @@ impl DynamicLibrary {
}
}
#[cfg(test)]
#[cfg(test, not(target_os = "ios"))]
mod test {
use super::*;
use prelude::*;
@ -205,6 +205,7 @@ mod test {
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
pub mod dl {
use prelude::*;

View File

@ -552,6 +552,7 @@ pub fn pipe() -> Pipe {
/// Returns the proper dll filename for the given basename of a file
/// as a String.
#[cfg(not(target_os="ios"))]
pub fn dll_filename(base: &str) -> String {
format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
}
@ -608,6 +609,7 @@ pub fn self_exe_name() -> Option<Path> {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
fn load_self() -> Option<Vec<u8>> {
unsafe {
use libc::funcs::extra::_NSGetExecutablePath;
@ -802,6 +804,7 @@ pub fn change_dir(p: &Path) -> bool {
/// Returns the platform-specific value of errno
pub fn errno() -> int {
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
fn errno_location() -> *c_int {
extern {
@ -850,6 +853,7 @@ pub fn error_string(errnum: uint) -> String {
#[cfg(unix)]
fn strerror(errnum: uint) -> String {
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
@ -995,6 +999,64 @@ fn real_args_as_bytes() -> Vec<Vec<u8>> {
}
}
// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
// and use underscores in their names - they're most probably
// are considered private and therefore should be avoided
// Here is another way to get arguments using Objective C
// runtime
//
// In general it looks like:
// res = Vec::new()
// let args = [[NSProcessInfo processInfo] arguments]
// for i in range(0, [args count])
// res.push([args objectAtIndex:i])
// res
#[cfg(target_os = "ios")]
fn real_args_as_bytes() -> Vec<Vec<u8>> {
use c_str::CString;
use iter::range;
use mem;
#[link(name = "objc")]
extern {
fn sel_registerName(name: *libc::c_uchar) -> Sel;
fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
fn objc_getClass(class_name: *libc::c_uchar) -> NsId;
}
#[link(name = "Foundation", kind = "framework")]
extern {}
type Sel = *libc::c_void;
type NsId = *libc::c_void;
let mut res = Vec::new();
unsafe {
let processInfoSel = sel_registerName("processInfo\0".as_ptr());
let argumentsSel = sel_registerName("arguments\0".as_ptr());
let utf8Sel = sel_registerName("UTF8String\0".as_ptr());
let countSel = sel_registerName("count\0".as_ptr());
let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr());
let klass = objc_getClass("NSProcessInfo\0".as_ptr());
let info = objc_msgSend(klass, processInfoSel);
let args = objc_msgSend(info, argumentsSel);
let cnt: int = mem::transmute(objc_msgSend(args, countSel));
for i in range(0, cnt) {
let tmp = objc_msgSend(args, objectAtSel, i);
let utf_c_str: *libc::c_char = mem::transmute(objc_msgSend(tmp, utf8Sel));
let s = CString::new(utf_c_str, false);
if s.is_not_null() {
res.push(Vec::from_slice(s.as_bytes_no_nul()))
}
}
}
res
}
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
@ -1532,6 +1594,25 @@ pub mod consts {
pub static EXE_EXTENSION: &'static str = "";
}
#[cfg(target_os = "ios")]
pub mod consts {
pub use os::arch_consts::ARCH;
pub static FAMILY: &'static str = "unix";
/// A string describing the specific operating system in use: in this
/// case, `ios`.
pub static SYSNAME: &'static str = "ios";
/// Specifies the filename suffix used for executable binaries on this
/// platform: in this case, the empty string.
pub static EXE_SUFFIX: &'static str = "";
/// Specifies the file extension, if any, used for executable binaries
/// on this platform: in this case, the empty string.
pub static EXE_EXTENSION: &'static str = "";
}
#[cfg(target_os = "freebsd")]
pub mod consts {
pub use os::arch_consts::ARCH;

View File

@ -13,7 +13,7 @@
pub use self::imp::OsRng;
#[cfg(unix)]
#[cfg(unix, not(target_os = "ios"))]
mod imp {
use io::{IoResult, File};
use path::Path;
@ -28,7 +28,7 @@ mod imp {
/// `/dev/urandom`.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
/// service provider with the `PROV_RSA_FULL` type.
///
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
/// This does not block.
#[cfg(unix)]
pub struct OsRng {
@ -58,6 +58,71 @@ mod imp {
}
}
#[cfg(target_os = "ios")]
mod imp {
extern crate libc;
use collections::Collection;
use io::{IoResult};
use kinds::marker;
use mem;
use os;
use rand::Rng;
use result::{Ok};
use self::libc::{c_int, size_t};
use slice::MutableVector;
/// A random number generator that retrieves randomness straight from
/// the operating system. Platform sources:
///
/// - Unix-like systems (Linux, Android, Mac OSX): read directly from
/// `/dev/urandom`.
/// - Windows: calls `CryptGenRandom`, using the default cryptographic
/// service provider with the `PROV_RSA_FULL` type.
/// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
/// This does not block.
pub struct OsRng {
marker: marker::NoCopy
}
struct SecRandom;
static kSecRandomDefault: *SecRandom = 0 as *SecRandom;
#[link(name = "Security", kind = "framework")]
extern "C" {
fn SecRandomCopyBytes(rnd: *SecRandom, count: size_t, bytes: *mut u8) -> c_int;
}
impl OsRng {
/// Create a new `OsRng`.
pub fn new() -> IoResult<OsRng> {
Ok(OsRng {marker: marker::NoCopy} )
}
}
impl Rng for OsRng {
fn next_u32(&mut self) -> u32 {
let mut v = [0u8, .. 4];
self.fill_bytes(v);
unsafe { mem::transmute(v) }
}
fn next_u64(&mut self) -> u64 {
let mut v = [0u8, .. 8];
self.fill_bytes(v);
unsafe { mem::transmute(v) }
}
fn fill_bytes(&mut self, v: &mut [u8]) {
let ret = unsafe {
SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
};
if ret == -1 {
fail!("couldn't generate random bytes: {}", os::last_os_error());
}
}
}
}
#[cfg(windows)]
mod imp {
extern crate libc;

View File

@ -237,22 +237,58 @@ fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> {
#[cfg(unix)]
mod imp {
use c_str::CString;
use io::{IoResult, IoError, Writer};
use io::{IoResult, Writer};
use libc;
use mem;
use option::{Some, None, Option};
use result::{Ok, Err};
use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
struct Context<'a> {
idx: int,
writer: &'a mut Writer,
last_error: Option<IoError>,
/// As always - iOS on arm uses SjLj exceptions and
/// _Unwind_Backtrace is even not available there. Still,
/// backtraces could be extracted using a backtrace function,
/// which thanks god is public
#[cfg(target_os = "ios", target_arch = "arm")]
#[inline(never)]
pub fn write(w: &mut Writer) -> IoResult<()> {
use iter::{Iterator, range};
use result;
use slice::{MutableVector};
extern {
fn backtrace(buf: *mut *libc::c_void, sz: libc::c_int) -> libc::c_int;
}
// while it doesn't requires lock for work as everything is
// local, it still displays much nicier backtraces when a
// couple of tasks fail simultaneously
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
let _g = unsafe { LOCK.lock() };
try!(writeln!(w, "stack backtrace:"));
// 100 lines should be enough
static size: libc::c_int = 100;
let mut buf: [*libc::c_void, ..size] = unsafe {mem::zeroed()};
let cnt = unsafe { backtrace(buf.as_mut_ptr(), size) as uint};
// skipping the first one as it is write itself
result::fold_(range(1, cnt).map(|i| {
print(w, i as int, buf[i])
}))
}
#[cfg(not(target_os = "ios", target_arch = "arm"))]
#[inline(never)] // if we know this is a function call, we can skip it when
// tracing
pub fn write(w: &mut Writer) -> IoResult<()> {
use io::IoError;
struct Context<'a> {
idx: int,
writer: &'a mut Writer,
last_error: Option<IoError>,
}
// When using libbacktrace, we use some necessary global state, so we
// need to prevent more than one thread from entering this block. This
// is semi-reasonable in terms of printing anyway, and we know that all
@ -291,7 +327,7 @@ mod imp {
// instructions after it. This means that the return instruction
// pointer points *outside* of the calling function, and by
// unwinding it we go back to the original function.
let ip = if cfg!(target_os = "macos") {
let ip = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
ip
} else {
unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
@ -323,6 +359,7 @@ mod imp {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
fn print(w: &mut Writer, idx: int, addr: *libc::c_void) -> IoResult<()> {
use intrinsics;
#[repr(C)]
@ -347,7 +384,7 @@ mod imp {
}
}
#[cfg(not(target_os = "macos"))]
#[cfg(not(target_os = "macos"), not(target_os = "ios"))]
fn print(w: &mut Writer, idx: int, addr: *libc::c_void) -> IoResult<()> {
use collections::Collection;
use iter::Iterator;
@ -487,9 +524,14 @@ mod imp {
/// Unwind library interface used for backtraces
///
/// Note that the native libraries come from librustrt, not this module.
/// Note that the native libraries come from librustrt, not this
/// module.
/// Note that dead code is allowed as here are just bindings
/// iOS doesn't use all of them it but adding more
/// platform-specific configs pollutes the code too much
#[allow(non_camel_case_types)]
#[allow(non_snake_case_functions)]
#[allow(dead_code)]
mod uw {
use libc;
@ -514,6 +556,8 @@ mod imp {
arg: *libc::c_void) -> _Unwind_Reason_Code;
extern {
// No native _Unwind_Backtrace on iOS
#[cfg(not(target_os = "ios", target_arch = "arm"))]
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
trace_argument: *libc::c_void)
-> _Unwind_Reason_Code;

View File

@ -39,3 +39,7 @@ extern {}
#[cfg(target_os = "macos")]
#[link(name = "System")]
extern {}
#[cfg(target_os = "ios")]
#[link(name = "System")]
extern {}

View File

@ -11,7 +11,7 @@
use std::fmt;
#[deriving(PartialEq)]
pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, }
pub enum Os { OsWin32, OsMacos, OsLinux, OsAndroid, OsFreebsd, OsiOS, }
#[deriving(PartialEq, Eq, Hash, Encodable, Decodable, Clone)]
pub enum Abi {

View File

@ -48,7 +48,7 @@ mod rustrt {
}
}
#[cfg(unix, not(target_os = "macos"))]
#[cfg(unix, not(target_os = "macos"), not(target_os = "ios"))]
mod imp {
use libc::{c_int, timespec};
@ -63,6 +63,7 @@ mod imp {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
mod imp {
use libc::{timeval, timezone, c_int, mach_timebase_info};
@ -123,6 +124,7 @@ pub fn get_time() -> Timespec {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
unsafe fn os_get_time() -> (i64, i32) {
use std::ptr;
let mut tv = libc::timeval { tv_sec: 0, tv_usec: 0 };
@ -130,7 +132,7 @@ pub fn get_time() -> Timespec {
(tv.tv_sec as i64, tv.tv_usec * 1000)
}
#[cfg(not(target_os = "macos"), not(windows))]
#[cfg(not(target_os = "macos"), not(target_os = "ios"), not(windows))]
unsafe fn os_get_time() -> (i64, i32) {
let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 };
imp::clock_gettime(libc::CLOCK_REALTIME, &mut tv);
@ -162,6 +164,7 @@ pub fn precise_time_ns() -> u64 {
}
#[cfg(target_os = "macos")]
#[cfg(target_os = "ios")]
fn os_precise_time_ns() -> u64 {
static mut TIMEBASE: libc::mach_timebase_info = libc::mach_timebase_info { numer: 0,
denom: 0 };
@ -175,7 +178,7 @@ pub fn precise_time_ns() -> u64 {
}
}
#[cfg(not(windows), not(target_os = "macos"))]
#[cfg(not(windows), not(target_os = "macos"), not(target_os = "ios"))]
fn os_precise_time_ns() -> u64 {
let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };
unsafe {