Add a method of manually specifying the crate map

Apparently weak linkage and dlopen aren't quite working out for applications
like servo on android. There appears to be a bug or two in how android loads
dynamic libraries and for some reason libservo.so isn't being found.

As a temporary solution, add an extern "C" function to libstd which can be
called if you have a handle to the crate map manually. When crawling the crate
map, we then check this manual symbol before falling back to the old solutions.

cc #11731
This commit is contained in:
Alex Crichton 2014-02-19 15:39:25 -08:00
parent 34a224f4a1
commit 1b3b273f80
4 changed files with 100 additions and 8 deletions

View File

@ -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<fn() -> ~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));
}
}
}

View File

@ -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)

View File

@ -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 <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.
#[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!()
})
}

View File

@ -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 <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.
// 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);
}