Skip to content

Commit 064a0ee

Browse files
committed
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.
2 parents 2425b22 + f35b598 commit 064a0ee

File tree

5 files changed

+168
-6
lines changed

5 files changed

+168
-6
lines changed

Diff for: src/Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: src/librustc_trans/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ rustc_errors = { path = "../librustc_errors" }
2222
rustc_incremental = { path = "../librustc_incremental" }
2323
rustc_llvm = { path = "../librustc_llvm" }
2424
rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
25+
serialize = { path = "../libserialize" }
2526
syntax = { path = "../libsyntax" }
2627
syntax_pos = { path = "../libsyntax_pos" }

Diff for: src/librustc_trans/back/link.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -722,9 +722,13 @@ fn link_natively(sess: &Session,
722722
cmd.arg(root.join(obj));
723723
}
724724

725-
if sess.target.target.options.is_like_emscripten &&
726-
sess.panic_strategy() == PanicStrategy::Abort {
727-
cmd.args(&["-s", "DISABLE_EXCEPTION_CATCHING=1"]);
725+
if sess.target.target.options.is_like_emscripten {
726+
cmd.arg("-s");
727+
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
728+
"DISABLE_EXCEPTION_CATCHING=1"
729+
} else {
730+
"DISABLE_EXCEPTION_CATCHING=0"
731+
});
728732
}
729733

730734
{
@@ -830,7 +834,8 @@ fn link_args(cmd: &mut Linker,
830834

831835
// If we're building a dynamic library then some platforms need to make sure
832836
// that all symbols are exported correctly from the dynamic library.
833-
if crate_type != config::CrateTypeExecutable {
837+
if crate_type != config::CrateTypeExecutable ||
838+
sess.target.target.options.is_like_emscripten {
834839
cmd.export_symbols(tmpdir, crate_type);
835840
}
836841

Diff for: src/librustc_trans/back/linker.rs

+156-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use back::symbol_export::{self, ExportedSymbols};
2323
use middle::dependency_format::Linkage;
2424
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
2525
use session::Session;
26-
use session::config::CrateType;
27-
use session::config;
26+
use session::config::{self, CrateType, OptLevel, DebugInfoLevel};
27+
use serialize::{json, Encoder};
2828

2929
/// For all the linkers we support, and information they might
3030
/// need out of the shared crate context before we get rid of it.
@@ -51,6 +51,12 @@ impl<'a, 'tcx> LinkerInfo {
5151
sess: sess,
5252
info: self
5353
}) as Box<Linker>
54+
} else if sess.target.target.options.is_like_emscripten {
55+
Box::new(EmLinker {
56+
cmd: cmd,
57+
sess: sess,
58+
info: self
59+
}) as Box<Linker>
5460
} else {
5561
Box::new(GnuLinker {
5662
cmd: cmd,
@@ -488,6 +494,154 @@ impl<'a> Linker for MsvcLinker<'a> {
488494
}
489495
}
490496

497+
pub struct EmLinker<'a> {
498+
cmd: &'a mut Command,
499+
sess: &'a Session,
500+
info: &'a LinkerInfo
501+
}
502+
503+
impl<'a> Linker for EmLinker<'a> {
504+
fn include_path(&mut self, path: &Path) {
505+
self.cmd.arg("-L").arg(path);
506+
}
507+
508+
fn link_staticlib(&mut self, lib: &str) {
509+
self.cmd.arg("-l").arg(lib);
510+
}
511+
512+
fn output_filename(&mut self, path: &Path) {
513+
self.cmd.arg("-o").arg(path);
514+
}
515+
516+
fn add_object(&mut self, path: &Path) {
517+
self.cmd.arg(path);
518+
}
519+
520+
fn link_dylib(&mut self, lib: &str) {
521+
// Emscripten always links statically
522+
self.link_staticlib(lib);
523+
}
524+
525+
fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
526+
// not supported?
527+
self.link_staticlib(lib);
528+
}
529+
530+
fn link_whole_rlib(&mut self, lib: &Path) {
531+
// not supported?
532+
self.link_rlib(lib);
533+
}
534+
535+
fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
536+
self.link_dylib(lib);
537+
}
538+
539+
fn link_rlib(&mut self, lib: &Path) {
540+
self.add_object(lib);
541+
}
542+
543+
fn position_independent_executable(&mut self) {
544+
// noop
545+
}
546+
547+
fn args(&mut self, args: &[String]) {
548+
self.cmd.args(args);
549+
}
550+
551+
fn framework_path(&mut self, _path: &Path) {
552+
bug!("frameworks are not supported on Emscripten")
553+
}
554+
555+
fn link_framework(&mut self, _framework: &str) {
556+
bug!("frameworks are not supported on Emscripten")
557+
}
558+
559+
fn gc_sections(&mut self, _keep_metadata: bool) {
560+
// noop
561+
}
562+
563+
fn optimize(&mut self) {
564+
// Emscripten performs own optimizations
565+
self.cmd.arg(match self.sess.opts.optimize {
566+
OptLevel::No => "-O0",
567+
OptLevel::Less => "-O1",
568+
OptLevel::Default => "-O2",
569+
OptLevel::Aggressive => "-O3",
570+
OptLevel::Size => "-Os",
571+
OptLevel::SizeMin => "-Oz"
572+
});
573+
// Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved
574+
self.cmd.args(&["--memory-init-file", "0"]);
575+
}
576+
577+
fn debuginfo(&mut self) {
578+
// Preserve names or generate source maps depending on debug info
579+
self.cmd.arg(match self.sess.opts.debuginfo {
580+
DebugInfoLevel::NoDebugInfo => "-g0",
581+
DebugInfoLevel::LimitedDebugInfo => "-g3",
582+
DebugInfoLevel::FullDebugInfo => "-g4"
583+
});
584+
}
585+
586+
fn no_default_libraries(&mut self) {
587+
self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
588+
}
589+
590+
fn build_dylib(&mut self, _out_filename: &Path) {
591+
bug!("building dynamic library is unsupported on Emscripten")
592+
}
593+
594+
fn whole_archives(&mut self) {
595+
// noop
596+
}
597+
598+
fn no_whole_archives(&mut self) {
599+
// noop
600+
}
601+
602+
fn hint_static(&mut self) {
603+
// noop
604+
}
605+
606+
fn hint_dynamic(&mut self) {
607+
// noop
608+
}
609+
610+
fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
611+
let symbols = &self.info.exports[&crate_type];
612+
613+
debug!("EXPORTED SYMBOLS:");
614+
615+
self.cmd.arg("-s");
616+
617+
let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
618+
let mut encoded = String::new();
619+
620+
{
621+
let mut encoder = json::Encoder::new(&mut encoded);
622+
let res = encoder.emit_seq(symbols.len(), |encoder| {
623+
for (i, sym) in symbols.iter().enumerate() {
624+
encoder.emit_seq_elt(i, |encoder| {
625+
encoder.emit_str(&("_".to_string() + sym))
626+
})?;
627+
}
628+
Ok(())
629+
});
630+
if let Err(e) = res {
631+
self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
632+
}
633+
}
634+
debug!("{}", encoded);
635+
arg.push(encoded);
636+
637+
self.cmd.arg(arg);
638+
}
639+
640+
fn subsystem(&mut self, _subsystem: &str) {
641+
// noop
642+
}
643+
}
644+
491645
fn exported_symbols(scx: &SharedCrateContext,
492646
exported_symbols: &ExportedSymbols,
493647
crate_type: CrateType)

Diff for: src/librustc_trans/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ extern crate rustc_bitflags;
5959
#[macro_use] extern crate syntax;
6060
extern crate syntax_pos;
6161
extern crate rustc_errors as errors;
62+
extern crate serialize;
6263

6364
pub use rustc::session;
6465
pub use rustc::middle;

0 commit comments

Comments
 (0)