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};
}
#[cfg(target_os = "macos")]
+ #[cfg(target_os = "ios")]
pub mod os {
pub mod common {
pub mod posix01 {
}
#[cfg(target_os = "macos")]
+ #[cfg(target_os = "ios")]
pub mod os {
pub mod c95 {
use types::os::arch::c95::{c_int, c_uint};
#[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_ {
#[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")]
#[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")]
#[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_ {
#[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")]
#[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 {
}
#[cfg(target_os = "macos")]
+ #[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
pub mod bsd44 {
use types::common::c95::{c_void};
}
#[cfg(target_os = "macos")]
+ #[cfg(target_os = "ios")]
pub mod extra {
use types::os::arch::c95::{c_char, c_int};
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"))]
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"))]
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")]
}
#[cfg(target_os = "macos")]
+#[cfg(target_os = "ios")]
mod select {
pub static FD_SETSIZE: uint = 1024;
}
#[cfg(target_os = "macos")]
+#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
mod signal {
use libc;
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 {
}
#[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,
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) }
}
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) })
}
pub mod file;
#[cfg(target_os = "macos")]
+#[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "android")]
#[cfg(target_os = "linux")]
}
#[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)
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(())
}
}
#[cfg(target_os = "macos")]
+ #[cfg(target_os = "ios")]
#[cfg(target_os = "freebsd")]
mod imp {
pub fn WIFEXITED(status: i32) -> bool { (status & 0x7f) == 0 }
}
}
-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);
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) };
-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\
// 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 => {
} 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()
}
}
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))
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);
+ }
}
}
// 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(); }
}
}
// 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,
// 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");
}
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
// 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 {
-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\
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();
-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()
}
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-\
abi::OsLinux => loader::OsLinux,
abi::OsAndroid => loader::OsAndroid,
abi::OsMacos => loader::OsMacos,
- abi::OsFreebsd => loader::OsFreebsd
+ abi::OsFreebsd => loader::OsFreebsd,
+ abi::OsiOS => loader::OsiOS,
}
}
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
("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() {
-> T {
diagnostic::expect(sess.diagnostic(), opt, msg)
}
-
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")) {
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";
OsWin32,
OsLinux,
OsAndroid,
- OsFreebsd
+ OsFreebsd,
+ OsiOS
}
pub struct CrateMismatch {
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),
}
}
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",
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",
// 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::*;
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)),
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());
// 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 {
}
#[cfg(target_os = "macos")]
+ #[cfg(target_os = "ios")]
mod os {
use libc;
}
#[cfg(target_os = "macos")]
+#[cfg(target_os = "ios")]
#[cfg(target_os = "win32")]
mod imp {
use core::prelude::*;
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;
}
use libc;
#[cfg(not(target_arch = "arm"))]
+#[cfg(target_os = "ios")]
#[repr(C)]
pub enum _Unwind_Action {
_UA_SEARCH_PHASE = 1,
#[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;
#[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)
+}
#[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};
/// 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::*;
}
#[cfg(target_os = "macos")]
+ #[cfg(target_os = "ios")]
mod os {
use libc;
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;
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")
}
// 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")
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
}
// 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
}
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
assert_eq!(42, Thread::start_stack(1, proc () 42).join());
}
}
-
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;
}
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;
}
else { // cleanup phase
unsafe {
- __gcc_personality_v0(state, ue_header, context)
+ __gcc_personality_v0(state, ue_header, context)
}
}
}
}
}
-#[cfg(test)]
+#[cfg(test, not(target_os = "ios"))]
mod test {
use super::*;
use prelude::*;
#[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::*;
/// 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)
}
}
#[cfg(target_os = "macos")]
+ #[cfg(target_os = "ios")]
fn load_self() -> Option<Vec<u8>> {
unsafe {
use libc::funcs::extra::_NSGetExecutablePath;
/// 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 {
#[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)
}
}
+// 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")]
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;
pub use self::imp::OsRng;
-#[cfg(unix)]
+#[cfg(unix, not(target_os = "ios"))]
mod imp {
use io::{IoResult, File};
use path::Path;
/// `/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 {
}
}
+#[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;
#[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
// 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) }
}
#[cfg(target_os = "macos")]
+ #[cfg(target_os = "ios")]
fn print(w: &mut Writer, idx: int, addr: *libc::c_void) -> IoResult<()> {
use intrinsics;
#[repr(C)]
}
}
- #[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;
/// 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;
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;
#[cfg(target_os = "macos")]
#[link(name = "System")]
extern {}
+
+#[cfg(target_os = "ios")]
+#[link(name = "System")]
+extern {}
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 {
}
}
-#[cfg(unix, not(target_os = "macos"))]
+#[cfg(unix, not(target_os = "macos"), not(target_os = "ios"))]
mod imp {
use libc::{c_int, timespec};
}
#[cfg(target_os = "macos")]
+#[cfg(target_os = "ios")]
mod imp {
use libc::{timeval, timezone, c_int, mach_timebase_info};
}
#[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 };
(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);
}
#[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 };
}
}
- #[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 {