Skip to content

Commit

Permalink
auto merge of #12408 : alexcrichton/rust/manual-crate-map, r=brson
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bors committed Feb 25, 2014
2 parents 3276090 + 1b3b273 commit fd83b2b
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 8 deletions.
51 changes: 43 additions & 8 deletions src/libstd/rt/crate_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -35,27 +36,61 @@ 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 {
#[crate_map]
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") {
Expand All @@ -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));
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/test/run-make/c-set-crate-map-manually/Makefile
Original file line number Diff line number Diff line change
@@ -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)
30 changes: 30 additions & 0 deletions src/test/run-make/c-set-crate-map-manually/lib.rs
Original file line number Diff line number Diff line change
@@ -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!()
})
}
20 changes: 20 additions & 0 deletions src/test/run-make/c-set-crate-map-manually/main.c
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit fd83b2b

Please sign in to comment.