Auto merge of #39490 - RReverser:em-linker, r=alexcrichton
Add Emscripten-specific linker Emscripten claims to accept most GNU linker options, but in fact most of `-Wl,...` are useless for it and instead it requires some additional special options which are easier to handle in a separate trait. Currently added: - `export_symbols`: works on executables as special Emscripten case since staticlibs/dylibs aren't compiled to JS, while exports are required to be accessible from JS. Fixes #39171. - `optimize` - translates Rust's optimization level to Emscripten optimization level (whether passed via `-C opt-level=...` or `-O...`). Fixes #36899. - `debuginfo` - translates debug info; Emscripten has 5 debug levels while Rust has 3, so chose to translate `-C debuginfo=1` to `-g3` (preserves whitespace, variable and function names for easy debugging). Fixes #36901. - `no_default_libraries` - tells Emscripten to exclude `memcpy` and co. TODO (in future PR): dynamic linking via `SIDE_MODULE` / `MAIN_MODULE` mechanism.
This commit is contained in:
commit
064a0ee131
1
src/Cargo.lock
generated
1
src/Cargo.lock
generated
@ -551,6 +551,7 @@ dependencies = [
|
||||
"rustc_incremental 0.0.0",
|
||||
"rustc_llvm 0.0.0",
|
||||
"rustc_platform_intrinsics 0.0.0",
|
||||
"serialize 0.0.0",
|
||||
"syntax 0.0.0",
|
||||
"syntax_pos 0.0.0",
|
||||
]
|
||||
|
@ -22,5 +22,6 @@ rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_incremental = { path = "../librustc_incremental" }
|
||||
rustc_llvm = { path = "../librustc_llvm" }
|
||||
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
|
||||
serialize = { path = "../libserialize" }
|
||||
syntax = { path = "../libsyntax" }
|
||||
syntax_pos = { path = "../libsyntax_pos" }
|
||||
|
@ -722,9 +722,13 @@ fn link_natively(sess: &Session,
|
||||
cmd.arg(root.join(obj));
|
||||
}
|
||||
|
||||
if sess.target.target.options.is_like_emscripten &&
|
||||
sess.panic_strategy() == PanicStrategy::Abort {
|
||||
cmd.args(&["-s", "DISABLE_EXCEPTION_CATCHING=1"]);
|
||||
if sess.target.target.options.is_like_emscripten {
|
||||
cmd.arg("-s");
|
||||
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
|
||||
"DISABLE_EXCEPTION_CATCHING=1"
|
||||
} else {
|
||||
"DISABLE_EXCEPTION_CATCHING=0"
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
@ -830,7 +834,8 @@ fn link_args(cmd: &mut Linker,
|
||||
|
||||
// If we're building a dynamic library then some platforms need to make sure
|
||||
// that all symbols are exported correctly from the dynamic library.
|
||||
if crate_type != config::CrateTypeExecutable {
|
||||
if crate_type != config::CrateTypeExecutable ||
|
||||
sess.target.target.options.is_like_emscripten {
|
||||
cmd.export_symbols(tmpdir, crate_type);
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,8 @@ use back::symbol_export::{self, ExportedSymbols};
|
||||
use middle::dependency_format::Linkage;
|
||||
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
|
||||
use session::Session;
|
||||
use session::config::CrateType;
|
||||
use session::config;
|
||||
use session::config::{self, CrateType, OptLevel, DebugInfoLevel};
|
||||
use serialize::{json, Encoder};
|
||||
|
||||
/// For all the linkers we support, and information they might
|
||||
/// need out of the shared crate context before we get rid of it.
|
||||
@ -51,6 +51,12 @@ impl<'a, 'tcx> LinkerInfo {
|
||||
sess: sess,
|
||||
info: self
|
||||
}) as Box<Linker>
|
||||
} else if sess.target.target.options.is_like_emscripten {
|
||||
Box::new(EmLinker {
|
||||
cmd: cmd,
|
||||
sess: sess,
|
||||
info: self
|
||||
}) as Box<Linker>
|
||||
} else {
|
||||
Box::new(GnuLinker {
|
||||
cmd: cmd,
|
||||
@ -488,6 +494,154 @@ impl<'a> Linker for MsvcLinker<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EmLinker<'a> {
|
||||
cmd: &'a mut Command,
|
||||
sess: &'a Session,
|
||||
info: &'a LinkerInfo
|
||||
}
|
||||
|
||||
impl<'a> Linker for EmLinker<'a> {
|
||||
fn include_path(&mut self, path: &Path) {
|
||||
self.cmd.arg("-L").arg(path);
|
||||
}
|
||||
|
||||
fn link_staticlib(&mut self, lib: &str) {
|
||||
self.cmd.arg("-l").arg(lib);
|
||||
}
|
||||
|
||||
fn output_filename(&mut self, path: &Path) {
|
||||
self.cmd.arg("-o").arg(path);
|
||||
}
|
||||
|
||||
fn add_object(&mut self, path: &Path) {
|
||||
self.cmd.arg(path);
|
||||
}
|
||||
|
||||
fn link_dylib(&mut self, lib: &str) {
|
||||
// Emscripten always links statically
|
||||
self.link_staticlib(lib);
|
||||
}
|
||||
|
||||
fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
|
||||
// not supported?
|
||||
self.link_staticlib(lib);
|
||||
}
|
||||
|
||||
fn link_whole_rlib(&mut self, lib: &Path) {
|
||||
// not supported?
|
||||
self.link_rlib(lib);
|
||||
}
|
||||
|
||||
fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
|
||||
self.link_dylib(lib);
|
||||
}
|
||||
|
||||
fn link_rlib(&mut self, lib: &Path) {
|
||||
self.add_object(lib);
|
||||
}
|
||||
|
||||
fn position_independent_executable(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn args(&mut self, args: &[String]) {
|
||||
self.cmd.args(args);
|
||||
}
|
||||
|
||||
fn framework_path(&mut self, _path: &Path) {
|
||||
bug!("frameworks are not supported on Emscripten")
|
||||
}
|
||||
|
||||
fn link_framework(&mut self, _framework: &str) {
|
||||
bug!("frameworks are not supported on Emscripten")
|
||||
}
|
||||
|
||||
fn gc_sections(&mut self, _keep_metadata: bool) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn optimize(&mut self) {
|
||||
// Emscripten performs own optimizations
|
||||
self.cmd.arg(match self.sess.opts.optimize {
|
||||
OptLevel::No => "-O0",
|
||||
OptLevel::Less => "-O1",
|
||||
OptLevel::Default => "-O2",
|
||||
OptLevel::Aggressive => "-O3",
|
||||
OptLevel::Size => "-Os",
|
||||
OptLevel::SizeMin => "-Oz"
|
||||
});
|
||||
// Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved
|
||||
self.cmd.args(&["--memory-init-file", "0"]);
|
||||
}
|
||||
|
||||
fn debuginfo(&mut self) {
|
||||
// Preserve names or generate source maps depending on debug info
|
||||
self.cmd.arg(match self.sess.opts.debuginfo {
|
||||
DebugInfoLevel::NoDebugInfo => "-g0",
|
||||
DebugInfoLevel::LimitedDebugInfo => "-g3",
|
||||
DebugInfoLevel::FullDebugInfo => "-g4"
|
||||
});
|
||||
}
|
||||
|
||||
fn no_default_libraries(&mut self) {
|
||||
self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
|
||||
}
|
||||
|
||||
fn build_dylib(&mut self, _out_filename: &Path) {
|
||||
bug!("building dynamic library is unsupported on Emscripten")
|
||||
}
|
||||
|
||||
fn whole_archives(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn no_whole_archives(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn hint_static(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn hint_dynamic(&mut self) {
|
||||
// noop
|
||||
}
|
||||
|
||||
fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
|
||||
let symbols = &self.info.exports[&crate_type];
|
||||
|
||||
debug!("EXPORTED SYMBOLS:");
|
||||
|
||||
self.cmd.arg("-s");
|
||||
|
||||
let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
|
||||
let mut encoded = String::new();
|
||||
|
||||
{
|
||||
let mut encoder = json::Encoder::new(&mut encoded);
|
||||
let res = encoder.emit_seq(symbols.len(), |encoder| {
|
||||
for (i, sym) in symbols.iter().enumerate() {
|
||||
encoder.emit_seq_elt(i, |encoder| {
|
||||
encoder.emit_str(&("_".to_string() + sym))
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
if let Err(e) = res {
|
||||
self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
|
||||
}
|
||||
}
|
||||
debug!("{}", encoded);
|
||||
arg.push(encoded);
|
||||
|
||||
self.cmd.arg(arg);
|
||||
}
|
||||
|
||||
fn subsystem(&mut self, _subsystem: &str) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
fn exported_symbols(scx: &SharedCrateContext,
|
||||
exported_symbols: &ExportedSymbols,
|
||||
crate_type: CrateType)
|
||||
|
@ -59,6 +59,7 @@ extern crate rustc_bitflags;
|
||||
#[macro_use] extern crate syntax;
|
||||
extern crate syntax_pos;
|
||||
extern crate rustc_errors as errors;
|
||||
extern crate serialize;
|
||||
|
||||
pub use rustc::session;
|
||||
pub use rustc::middle;
|
||||
|
Loading…
x
Reference in New Issue
Block a user