diff --git a/src/libstd/rt/crate_map.rs b/src/libstd/rt/crate_map.rs index 847375121c89..409b77d1a3f8 100644 --- a/src/libstd/rt/crate_map.rs +++ b/src/libstd/rt/crate_map.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use cast; use cmp::TotalOrd; use container::MutableSet; use iter::Iterator; @@ -35,6 +36,34 @@ pub struct CrateMap<'a> { event_loop_factory: Option ~EventLoop>, } +// When working on android, apparently weak symbols don't work so well for +// finding the crate map, and neither does dlopen + dlsym. This is mainly a +// problem when integrating a shared library with an existing application. +// Standalone binaries do not appear to have this problem. The reasons are a +// little mysterious, and more information can be found in #11731. +// +// For now we provide a way to tell libstd about the crate map manually that's +// checked before the normal weak symbol/dlopen paths. In theory this is useful +// on other platforms where our dlopen/weak linkage strategy mysteriously fails +// but the crate map can be specified manually. +static mut MANUALLY_PROVIDED_CRATE_MAP: *CrateMap<'static> = + 0 as *CrateMap<'static>; +#[no_mangle] +#[cfg(not(test))] +pub extern fn rust_set_crate_map(map: *CrateMap<'static>) { + unsafe { MANUALLY_PROVIDED_CRATE_MAP = map; } +} + +fn manual_crate_map() -> Option<&'static CrateMap<'static>> { + unsafe { + if MANUALLY_PROVIDED_CRATE_MAP.is_null() { + None + } else { + Some(cast::transmute(MANUALLY_PROVIDED_CRATE_MAP)) + } + } +} + #[cfg(not(windows))] pub fn get_crate_map() -> Option<&'static CrateMap<'static>> { extern { @@ -42,20 +71,26 @@ pub fn get_crate_map() -> Option<&'static CrateMap<'static>> { static CRATE_MAP: CrateMap<'static>; } - let ptr: (*CrateMap) = &'static CRATE_MAP; - if ptr.is_null() { - return None; - } else { - return Some(&'static CRATE_MAP); - } + manual_crate_map().or_else(|| { + let ptr: (*CrateMap) = &'static CRATE_MAP; + if ptr.is_null() { + None + } else { + Some(&'static CRATE_MAP) + } + }) } #[cfg(windows)] pub fn get_crate_map() -> Option<&'static CrateMap<'static>> { - use cast::transmute; use c_str::ToCStr; use unstable::dynamic_lib::dl; + match manual_crate_map() { + Some(cm) => return Some(cm), + None => {} + } + let sym = unsafe { let module = dl::open_internal(); let rust_crate_map_toplevel = if cfg!(target_arch = "x86") { @@ -74,7 +109,7 @@ pub fn get_crate_map() -> Option<&'static CrateMap<'static>> { return None; } else { unsafe { - return Some(transmute(sym)); + return Some(cast::transmute(sym)); } } } diff --git a/src/test/run-make/c-set-crate-map-manually/Makefile b/src/test/run-make/c-set-crate-map-manually/Makefile new file mode 100644 index 000000000000..954f10d3eddf --- /dev/null +++ b/src/test/run-make/c-set-crate-map-manually/Makefile @@ -0,0 +1,7 @@ +-include ../tools.mk + +all: + $(RUSTC) lib.rs -C gen-crate-map + ln -nsf $(call DYLIB,boot-*) $(call DYLIB,boot) + $(CC) main.c -o $(call RUN,main) -lboot -Wl,-rpath,$(TMPDIR) + RUST_LOG=boot $(call RUN,main) diff --git a/src/test/run-make/c-set-crate-map-manually/lib.rs b/src/test/run-make/c-set-crate-map-manually/lib.rs new file mode 100644 index 000000000000..15b0a9140cf5 --- /dev/null +++ b/src/test/run-make/c-set-crate-map-manually/lib.rs @@ -0,0 +1,30 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[crate_id="boot#0.1"]; +#[crate_type="dylib"]; +#[no_uv]; + +extern crate rustuv; +extern crate green; + +use std::rt::crate_map::{CrateMap, rust_set_crate_map}; + +// pull in this symbol from libstd into this crate (for convenience) +#[no_mangle] +pub static set_crate_map: extern "C" fn(*CrateMap<'static>) = rust_set_crate_map; + +#[no_mangle] // this needs to get called from C +pub extern "C" fn foo(argc: int, argv: **u8) -> int { + green::start(argc, argv, proc() { + if log_enabled!(std::logging::DEBUG) { return } + fail!() + }) +} diff --git a/src/test/run-make/c-set-crate-map-manually/main.c b/src/test/run-make/c-set-crate-map-manually/main.c new file mode 100644 index 000000000000..a69ec7d0c86e --- /dev/null +++ b/src/test/run-make/c-set-crate-map-manually/main.c @@ -0,0 +1,20 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// this is the rust entry point that we're going to call. +int foo(int argc, char *argv[]); + +extern void (*set_crate_map)(void *map); +extern int _rust_crate_map_toplevel; + +int main(int argc, char *argv[]) { + set_crate_map(&_rust_crate_map_toplevel); + return foo(argc, argv); +}