1 use super::symbol_export;
2 use super::command::Command;
5 use rustc_data_structures::fx::FxHashMap;
6 use std::ffi::{OsStr, OsString};
7 use std::fs::{self, File};
8 use std::io::prelude::*;
9 use std::io::{self, BufWriter};
10 use std::path::{Path, PathBuf};
12 use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
13 use rustc::middle::dependency_format::Linkage;
14 use rustc::session::Session;
15 use rustc::session::config::{self, CrateType, OptLevel, DebugInfo,
17 use rustc::ty::TyCtxt;
18 use rustc_target::spec::{LinkerFlavor, LldFlavor};
19 use serialize::{json, Encoder};
21 /// For all the linkers we support, and information they might
22 /// need out of the shared crate context before we get rid of it.
23 pub struct LinkerInfo {
24 exports: FxHashMap<CrateType, Vec<String>>,
28 pub fn new(tcx: TyCtxt) -> LinkerInfo {
30 exports: tcx.sess.crate_types.borrow().iter().map(|&c| {
31 (c, exported_symbols(tcx, c))
42 ) -> Box<dyn Linker+'a> {
44 LinkerFlavor::Lld(LldFlavor::Link) |
45 LinkerFlavor::Msvc => {
59 LinkerFlavor::Gcc => {
70 LinkerFlavor::Lld(LldFlavor::Ld) |
71 LinkerFlavor::Lld(LldFlavor::Ld64) |
83 LinkerFlavor::Lld(LldFlavor::Wasm) => {
84 Box::new(WasmLd::new(cmd, sess, self)) as Box<dyn Linker>
87 LinkerFlavor::PtxLinker => {
88 Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>
94 /// Linker abstraction used by `back::link` to build up the command to invoke a
97 /// This trait is the total list of requirements needed by `back::link` and
98 /// represents the meaning of each option being passed down. This trait is then
99 /// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an
100 /// MSVC linker (e.g., `link.exe`) is being used.
102 fn link_dylib(&mut self, lib: &str);
103 fn link_rust_dylib(&mut self, lib: &str, path: &Path);
104 fn link_framework(&mut self, framework: &str);
105 fn link_staticlib(&mut self, lib: &str);
106 fn link_rlib(&mut self, lib: &Path);
107 fn link_whole_rlib(&mut self, lib: &Path);
108 fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]);
109 fn include_path(&mut self, path: &Path);
110 fn framework_path(&mut self, path: &Path);
111 fn output_filename(&mut self, path: &Path);
112 fn add_object(&mut self, path: &Path);
113 fn gc_sections(&mut self, keep_metadata: bool);
114 fn position_independent_executable(&mut self);
115 fn no_position_independent_executable(&mut self);
116 fn full_relro(&mut self);
117 fn partial_relro(&mut self);
118 fn no_relro(&mut self);
119 fn optimize(&mut self);
120 fn pgo_gen(&mut self);
121 fn debuginfo(&mut self);
122 fn no_default_libraries(&mut self);
123 fn build_dylib(&mut self, out_filename: &Path);
124 fn build_static_executable(&mut self);
125 fn args(&mut self, args: &[String]);
126 fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
127 fn subsystem(&mut self, subsystem: &str);
128 fn group_start(&mut self);
129 fn group_end(&mut self);
130 fn cross_lang_lto(&mut self);
131 // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
132 fn finalize(&mut self) -> Command;
135 pub struct GccLinker<'a> {
138 info: &'a LinkerInfo,
139 hinted_static: bool, // Keeps track of the current hinting mode.
145 impl<'a> GccLinker<'a> {
146 /// Argument that must be passed *directly* to the linker
148 /// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used.
149 fn linker_arg<S>(&mut self, arg: S) -> &mut Self
150 where S: AsRef<OsStr>
153 let mut os = OsString::from("-Wl,");
154 os.push(arg.as_ref());
162 fn takes_hints(&self) -> bool {
163 !self.sess.target.target.options.is_like_osx
166 // Some platforms take hints about whether a library is static or dynamic.
167 // For those that support this, we ensure we pass the option if the library
168 // was flagged "static" (most defaults are dynamic) to ensure that if
169 // libfoo.a and libfoo.so both exist that the right one is chosen.
170 fn hint_static(&mut self) {
171 if !self.takes_hints() { return }
172 if !self.hinted_static {
173 self.linker_arg("-Bstatic");
174 self.hinted_static = true;
178 fn hint_dynamic(&mut self) {
179 if !self.takes_hints() { return }
180 if self.hinted_static {
181 self.linker_arg("-Bdynamic");
182 self.hinted_static = false;
186 fn push_cross_lang_lto_args(&mut self, plugin_path: Option<&OsStr>) {
187 if let Some(plugin_path) = plugin_path {
188 let mut arg = OsString::from("-plugin=");
189 arg.push(plugin_path);
190 self.linker_arg(&arg);
193 let opt_level = match self.sess.opts.optimize {
194 config::OptLevel::No => "O0",
195 config::OptLevel::Less => "O1",
196 config::OptLevel::Default => "O2",
197 config::OptLevel::Aggressive => "O3",
198 config::OptLevel::Size => "Os",
199 config::OptLevel::SizeMin => "Oz",
202 self.linker_arg(&format!("-plugin-opt={}", opt_level));
203 let target_cpu = self.target_cpu;
204 self.linker_arg(&format!("-plugin-opt=mcpu={}", target_cpu));
208 impl<'a> Linker for GccLinker<'a> {
209 fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg(format!("-l{}", lib)); }
210 fn link_staticlib(&mut self, lib: &str) {
211 self.hint_static(); self.cmd.arg(format!("-l{}", lib));
213 fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); }
214 fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); }
215 fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); }
216 fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
217 fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
218 fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
219 fn no_position_independent_executable(&mut self) { self.cmd.arg("-no-pie"); }
220 fn full_relro(&mut self) { self.linker_arg("-zrelro"); self.linker_arg("-znow"); }
221 fn partial_relro(&mut self) { self.linker_arg("-zrelro"); }
222 fn no_relro(&mut self) { self.linker_arg("-znorelro"); }
223 fn build_static_executable(&mut self) { self.cmd.arg("-static"); }
224 fn args(&mut self, args: &[String]) { self.cmd.args(args); }
226 fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
228 self.cmd.arg(format!("-l{}", lib));
231 fn link_framework(&mut self, framework: &str) {
233 self.cmd.arg("-framework").arg(framework);
236 // Here we explicitly ask that the entire archive is included into the
237 // result artifact. For more details see #15460, but the gist is that
238 // the linker will strip away any unused objects in the archive if we
239 // don't otherwise explicitly reference them. This can occur for
240 // libraries which are just providing bindings, libraries with generic
242 fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
244 let target = &self.sess.target.target;
245 if !target.options.is_like_osx {
246 self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib));
247 self.linker_arg("--no-whole-archive");
249 // -force_load is the macOS equivalent of --whole-archive, but it
250 // involves passing the full path to the library to link.
251 self.linker_arg("-force_load");
252 let lib = archive::find_library(lib, search_path, &self.sess);
253 self.linker_arg(&lib);
257 fn link_whole_rlib(&mut self, lib: &Path) {
259 if self.sess.target.target.options.is_like_osx {
260 self.linker_arg("-force_load");
261 self.linker_arg(&lib);
263 self.linker_arg("--whole-archive").cmd.arg(lib);
264 self.linker_arg("--no-whole-archive");
268 fn gc_sections(&mut self, keep_metadata: bool) {
269 // The dead_strip option to the linker specifies that functions and data
270 // unreachable by the entry point will be removed. This is quite useful
271 // with Rust's compilation model of compiling libraries at a time into
272 // one object file. For example, this brings hello world from 1.7MB to
275 // Note that this is done for both executables and dynamic libraries. We
276 // won't get much benefit from dylibs because LLVM will have already
277 // stripped away as much as it could. This has not been seen to impact
278 // link times negatively.
280 // -dead_strip can't be part of the pre_link_args because it's also used
281 // for partial linking when using multiple codegen units (-r). So we
283 if self.sess.target.target.options.is_like_osx {
284 self.linker_arg("-dead_strip");
285 } else if self.sess.target.target.options.is_like_solaris {
286 self.linker_arg("-zignore");
288 // If we're building a dylib, we don't use --gc-sections because LLVM
289 // has already done the best it can do, and we also don't want to
290 // eliminate the metadata. If we're building an executable, however,
291 // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
293 } else if !keep_metadata {
294 self.linker_arg("--gc-sections");
298 fn optimize(&mut self) {
299 if !self.sess.target.target.options.linker_is_gnu { return }
301 // GNU-style linkers support optimization with -O. GNU ld doesn't
302 // need a numeric argument, but other linkers do.
303 if self.sess.opts.optimize == config::OptLevel::Default ||
304 self.sess.opts.optimize == config::OptLevel::Aggressive {
305 self.linker_arg("-O1");
309 fn pgo_gen(&mut self) {
310 if !self.sess.target.target.options.linker_is_gnu { return }
312 // If we're doing PGO generation stuff and on a GNU-like linker, use the
313 // "-u" flag to properly pull in the profiler runtime bits.
315 // This is because LLVM otherwise won't add the needed initialization
316 // for us on Linux (though the extra flag should be harmless if it
319 // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030.
321 // Though it may be worth to try to revert those changes upstream, since
322 // the overhead of the initialization should be minor.
324 self.cmd.arg("__llvm_profile_runtime");
327 fn debuginfo(&mut self) {
328 if let DebugInfo::None = self.sess.opts.debuginfo {
329 // If we are building without debuginfo enabled and we were called with
330 // `-Zstrip-debuginfo-if-disabled=yes`, tell the linker to strip any debuginfo
331 // found when linking to get rid of symbols from libstd.
332 if let Some(true) = self.sess.opts.debugging_opts.strip_debuginfo_if_disabled {
333 self.linker_arg("-S");
338 fn no_default_libraries(&mut self) {
340 self.cmd.arg("-nodefaultlibs");
344 fn build_dylib(&mut self, out_filename: &Path) {
345 // On mac we need to tell the linker to let this library be rpathed
346 if self.sess.target.target.options.is_like_osx {
347 self.cmd.arg("-dynamiclib");
348 self.linker_arg("-dylib");
350 // Note that the `osx_rpath_install_name` option here is a hack
351 // purely to support rustbuild right now, we should get a more
352 // principled solution at some point to force the compiler to pass
353 // the right `-Wl,-install_name` with an `@rpath` in it.
354 if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
355 self.linker_arg("-install_name");
356 let mut v = OsString::from("@rpath/");
357 v.push(out_filename.file_name().unwrap());
361 self.cmd.arg("-shared");
365 fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
366 // If we're compiling a dylib, then we let symbol visibility in object
367 // files to take care of whether they're exported or not.
369 // If we're compiling a cdylib, however, we manually create a list of
370 // exported symbols to ensure we don't expose any more. The object files
371 // have far more public symbols than we actually want to export, so we
372 // hide them all here.
373 if crate_type == CrateType::Dylib ||
374 crate_type == CrateType::ProcMacro {
378 let mut arg = OsString::new();
379 let path = tmpdir.join("list");
381 debug!("EXPORTED SYMBOLS:");
383 if self.sess.target.target.options.is_like_osx {
384 // Write a plain, newline-separated list of symbols
385 let res = (|| -> io::Result<()> {
386 let mut f = BufWriter::new(File::create(&path)?);
387 for sym in self.info.exports[&crate_type].iter() {
389 writeln!(f, "_{}", sym)?;
393 if let Err(e) = res {
394 self.sess.fatal(&format!("failed to write lib.def file: {}", e));
397 // Write an LD version script
398 let res = (|| -> io::Result<()> {
399 let mut f = BufWriter::new(File::create(&path)?);
400 writeln!(f, "{{\n global:")?;
401 for sym in self.info.exports[&crate_type].iter() {
403 writeln!(f, " {};", sym)?;
405 writeln!(f, "\n local:\n *;\n}};")?;
408 if let Err(e) = res {
409 self.sess.fatal(&format!("failed to write version script: {}", e));
413 if self.sess.target.target.options.is_like_osx {
417 arg.push("-exported_symbols_list,");
418 } else if self.sess.target.target.options.is_like_solaris {
427 arg.push("--version-script=");
434 fn subsystem(&mut self, subsystem: &str) {
435 self.linker_arg("--subsystem");
436 self.linker_arg(&subsystem);
439 fn finalize(&mut self) -> Command {
440 self.hint_dynamic(); // Reset to default before returning the composed command line.
442 ::std::mem::replace(&mut self.cmd, Command::new(""))
445 fn group_start(&mut self) {
446 if !self.sess.target.target.options.is_like_osx {
447 self.linker_arg("--start-group");
451 fn group_end(&mut self) {
452 if !self.sess.target.target.options.is_like_osx {
453 self.linker_arg("--end-group");
457 fn cross_lang_lto(&mut self) {
458 match self.sess.opts.debugging_opts.cross_lang_lto {
459 CrossLangLto::Disabled => {
462 CrossLangLto::LinkerPluginAuto => {
463 self.push_cross_lang_lto_args(None);
465 CrossLangLto::LinkerPlugin(ref path) => {
466 self.push_cross_lang_lto_args(Some(path.as_os_str()));
472 pub struct MsvcLinker<'a> {
478 impl<'a> Linker for MsvcLinker<'a> {
479 fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
480 fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
481 fn args(&mut self, args: &[String]) { self.cmd.args(args); }
483 fn build_dylib(&mut self, out_filename: &Path) {
484 self.cmd.arg("/DLL");
485 let mut arg: OsString = "/IMPLIB:".into();
486 arg.push(out_filename.with_extension("dll.lib"));
490 fn build_static_executable(&mut self) {
494 fn gc_sections(&mut self, _keep_metadata: bool) {
495 // MSVC's ICF (Identical COMDAT Folding) link optimization is
496 // slow for Rust and thus we disable it by default when not in
497 // optimization build.
498 if self.sess.opts.optimize != config::OptLevel::No {
499 self.cmd.arg("/OPT:REF,ICF");
501 // It is necessary to specify NOICF here, because /OPT:REF
502 // implies ICF by default.
503 self.cmd.arg("/OPT:REF,NOICF");
507 fn link_dylib(&mut self, lib: &str) {
508 self.cmd.arg(&format!("{}.lib", lib));
511 fn link_rust_dylib(&mut self, lib: &str, path: &Path) {
512 // When producing a dll, the MSVC linker may not actually emit a
513 // `foo.lib` file if the dll doesn't actually export any symbols, so we
514 // check to see if the file is there and just omit linking to it if it's
516 let name = format!("{}.dll.lib", lib);
517 if fs::metadata(&path.join(&name)).is_ok() {
522 fn link_staticlib(&mut self, lib: &str) {
523 self.cmd.arg(&format!("{}.lib", lib));
526 fn position_independent_executable(&mut self) {
530 fn no_position_independent_executable(&mut self) {
534 fn full_relro(&mut self) {
538 fn partial_relro(&mut self) {
542 fn no_relro(&mut self) {
546 fn no_default_libraries(&mut self) {
547 // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC
548 // as there's been trouble in the past of linking the C++ standard
549 // library required by LLVM. This likely needs to happen one day, but
550 // in general Windows is also a more controlled environment than
551 // Unix, so it's not necessarily as critical that this be implemented.
553 // Note that there are also some licensing worries about statically
554 // linking some libraries which require a specific agreement, so it may
555 // not ever be possible for us to pass this flag.
558 fn include_path(&mut self, path: &Path) {
559 let mut arg = OsString::from("/LIBPATH:");
564 fn output_filename(&mut self, path: &Path) {
565 let mut arg = OsString::from("/OUT:");
570 fn framework_path(&mut self, _path: &Path) {
571 bug!("frameworks are not supported on windows")
573 fn link_framework(&mut self, _framework: &str) {
574 bug!("frameworks are not supported on windows")
577 fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
579 self.link_staticlib(lib);
581 fn link_whole_rlib(&mut self, path: &Path) {
583 self.link_rlib(path);
585 fn optimize(&mut self) {
586 // Needs more investigation of `/OPT` arguments
589 fn pgo_gen(&mut self) {
590 // Nothing needed here.
593 fn debuginfo(&mut self) {
594 // This will cause the Microsoft linker to generate a PDB file
595 // from the CodeView line tables in the object files.
596 self.cmd.arg("/DEBUG");
598 // This will cause the Microsoft linker to embed .natvis info into the PDB file
599 let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc");
600 if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
601 // LLVM 5.0.0's lld-link frontend doesn't yet recognize, and chokes
602 // on, the /NATVIS:... flags. LLVM 6 (or earlier) should at worst ignore
603 // them, eventually mooting this workaround, per this landed patch:
604 // https://github.com/llvm-mirror/lld/commit/27b9c4285364d8d76bb43839daa100
605 if let Some(ref linker_path) = self.sess.opts.cg.linker {
606 if let Some(linker_name) = Path::new(&linker_path).file_stem() {
607 if linker_name.to_str().unwrap().to_lowercase() == "lld-link" {
608 self.sess.warn("not embedding natvis: lld-link may not support the flag");
613 for entry in natvis_dir {
616 let path = entry.path();
617 if path.extension() == Some("natvis".as_ref()) {
618 let mut arg = OsString::from("/NATVIS:");
624 self.sess.warn(&format!("error enumerating natvis directory: {}", err));
631 // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
632 // export symbols from a dynamic library. When building a dynamic library,
633 // however, we're going to want some symbols exported, so this function
634 // generates a DEF file which lists all the symbols.
636 // The linker will read this `*.def` file and export all the symbols from
637 // the dynamic library. Note that this is not as simple as just exporting
638 // all the symbols in the current crate (as specified by `codegen.reachable`)
639 // but rather we also need to possibly export the symbols of upstream
640 // crates. Upstream rlibs may be linked statically to this dynamic library,
641 // in which case they may continue to transitively be used and hence need
642 // their symbols exported.
643 fn export_symbols(&mut self,
645 crate_type: CrateType) {
646 let path = tmpdir.join("lib.def");
647 let res = (|| -> io::Result<()> {
648 let mut f = BufWriter::new(File::create(&path)?);
650 // Start off with the standard module name header and then go
651 // straight to exports.
652 writeln!(f, "LIBRARY")?;
653 writeln!(f, "EXPORTS")?;
654 for symbol in self.info.exports[&crate_type].iter() {
655 debug!(" _{}", symbol);
656 writeln!(f, " {}", symbol)?;
660 if let Err(e) = res {
661 self.sess.fatal(&format!("failed to write lib.def file: {}", e));
663 let mut arg = OsString::from("/DEF:");
668 fn subsystem(&mut self, subsystem: &str) {
669 // Note that previous passes of the compiler validated this subsystem,
670 // so we just blindly pass it to the linker.
671 self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem));
673 // Windows has two subsystems we're interested in right now, the console
674 // and windows subsystems. These both implicitly have different entry
675 // points (starting symbols). The console entry point starts with
676 // `mainCRTStartup` and the windows entry point starts with
677 // `WinMainCRTStartup`. These entry points, defined in system libraries,
678 // will then later probe for either `main` or `WinMain`, respectively to
679 // start the application.
681 // In Rust we just always generate a `main` function so we want control
682 // to always start there, so we force the entry point on the windows
683 // subsystem to be `mainCRTStartup` to get everything booted up
686 // For more information see RFC #1665
687 if subsystem == "windows" {
688 self.cmd.arg("/ENTRY:mainCRTStartup");
692 fn finalize(&mut self) -> Command {
693 ::std::mem::replace(&mut self.cmd, Command::new(""))
696 // MSVC doesn't need group indicators
697 fn group_start(&mut self) {}
698 fn group_end(&mut self) {}
700 fn cross_lang_lto(&mut self) {
705 pub struct EmLinker<'a> {
711 impl<'a> Linker for EmLinker<'a> {
712 fn include_path(&mut self, path: &Path) {
713 self.cmd.arg("-L").arg(path);
716 fn link_staticlib(&mut self, lib: &str) {
717 self.cmd.arg("-l").arg(lib);
720 fn output_filename(&mut self, path: &Path) {
721 self.cmd.arg("-o").arg(path);
724 fn add_object(&mut self, path: &Path) {
728 fn link_dylib(&mut self, lib: &str) {
729 // Emscripten always links statically
730 self.link_staticlib(lib);
733 fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
735 self.link_staticlib(lib);
738 fn link_whole_rlib(&mut self, lib: &Path) {
743 fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
744 self.link_dylib(lib);
747 fn link_rlib(&mut self, lib: &Path) {
748 self.add_object(lib);
751 fn position_independent_executable(&mut self) {
755 fn no_position_independent_executable(&mut self) {
759 fn full_relro(&mut self) {
763 fn partial_relro(&mut self) {
767 fn no_relro(&mut self) {
771 fn args(&mut self, args: &[String]) {
775 fn framework_path(&mut self, _path: &Path) {
776 bug!("frameworks are not supported on Emscripten")
779 fn link_framework(&mut self, _framework: &str) {
780 bug!("frameworks are not supported on Emscripten")
783 fn gc_sections(&mut self, _keep_metadata: bool) {
787 fn optimize(&mut self) {
788 // Emscripten performs own optimizations
789 self.cmd.arg(match self.sess.opts.optimize {
790 OptLevel::No => "-O0",
791 OptLevel::Less => "-O1",
792 OptLevel::Default => "-O2",
793 OptLevel::Aggressive => "-O3",
794 OptLevel::Size => "-Os",
795 OptLevel::SizeMin => "-Oz"
797 // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved
798 self.cmd.args(&["--memory-init-file", "0"]);
801 fn pgo_gen(&mut self) {
802 // noop, but maybe we need something like the gnu linker?
805 fn debuginfo(&mut self) {
806 // Preserve names or generate source maps depending on debug info
807 self.cmd.arg(match self.sess.opts.debuginfo {
808 DebugInfo::None => "-g0",
809 DebugInfo::Limited => "-g3",
810 DebugInfo::Full => "-g4"
814 fn no_default_libraries(&mut self) {
815 self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
818 fn build_dylib(&mut self, _out_filename: &Path) {
819 bug!("building dynamic library is unsupported on Emscripten")
822 fn build_static_executable(&mut self) {
826 fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
827 let symbols = &self.info.exports[&crate_type];
829 debug!("EXPORTED SYMBOLS:");
833 let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
834 let mut encoded = String::new();
837 let mut encoder = json::Encoder::new(&mut encoded);
838 let res = encoder.emit_seq(symbols.len(), |encoder| {
839 for (i, sym) in symbols.iter().enumerate() {
840 encoder.emit_seq_elt(i, |encoder| {
841 encoder.emit_str(&("_".to_owned() + sym))
846 if let Err(e) = res {
847 self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
850 debug!("{}", encoded);
856 fn subsystem(&mut self, _subsystem: &str) {
860 fn finalize(&mut self) -> Command {
861 ::std::mem::replace(&mut self.cmd, Command::new(""))
864 // Appears not necessary on Emscripten
865 fn group_start(&mut self) {}
866 fn group_end(&mut self) {}
868 fn cross_lang_lto(&mut self) {
873 pub struct WasmLd<'a> {
876 info: &'a LinkerInfo,
879 impl<'a> WasmLd<'a> {
880 fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
881 // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
882 // using threads causing weird hangs and bugs. Disable it entirely as
883 // this isn't yet the bottleneck of compilation at all anyway.
884 cmd.arg("--no-threads");
886 // By default LLD only gives us one page of stack (64k) which is a
887 // little small. Default to a larger stack closer to other PC platforms
888 // (1MB) and users can always inject their own link-args to override this.
889 cmd.arg("-z").arg("stack-size=1048576");
891 // By default LLD's memory layout is:
893 // 1. First, a blank page
894 // 2. Next, all static data
895 // 3. Finally, the main stack (which grows down)
897 // This has the unfortunate consequence that on stack overflows you
898 // corrupt static data and can cause some exceedingly weird bugs. To
899 // help detect this a little sooner we instead request that the stack is
900 // placed before static data.
902 // This means that we'll generate slightly larger binaries as references
903 // to static data will take more bytes in the ULEB128 encoding, but
904 // stack overflow will be guaranteed to trap as it underflows instead of
905 // corrupting static data.
906 cmd.arg("--stack-first");
908 // FIXME we probably shouldn't pass this but instead pass an explicit
909 // whitelist of symbols we'll allow to be undefined. Unfortunately
910 // though we can't handle symbols like `log10` that LLVM injects at a
911 // super late date without actually parsing object files. For now let's
912 // stick to this and hopefully fix it before stabilization happens.
913 cmd.arg("--allow-undefined");
915 // For now we just never have an entry symbol
916 cmd.arg("--no-entry");
918 // Rust code should never have warnings, and warnings are often
919 // indicative of bugs, let's prevent them.
920 cmd.arg("--fatal-warnings");
922 // The symbol visibility story is a bit in flux right now with LLD.
923 // It's... not entirely clear to me what's going on, but this looks to
924 // make everything work when `export_symbols` isn't otherwise called for
925 // things like executables.
926 cmd.arg("--export-dynamic");
928 // LLD only implements C++-like demangling, which doesn't match our own
929 // mangling scheme. Tell LLD to not demangle anything and leave it up to
930 // us to demangle these symbols later.
931 cmd.arg("--no-demangle");
933 WasmLd { cmd, sess, info }
937 impl<'a> Linker for WasmLd<'a> {
938 fn link_dylib(&mut self, lib: &str) {
939 self.cmd.arg("-l").arg(lib);
942 fn link_staticlib(&mut self, lib: &str) {
943 self.cmd.arg("-l").arg(lib);
946 fn link_rlib(&mut self, lib: &Path) {
950 fn include_path(&mut self, path: &Path) {
951 self.cmd.arg("-L").arg(path);
954 fn framework_path(&mut self, _path: &Path) {
955 panic!("frameworks not supported")
958 fn output_filename(&mut self, path: &Path) {
959 self.cmd.arg("-o").arg(path);
962 fn add_object(&mut self, path: &Path) {
966 fn position_independent_executable(&mut self) {
969 fn full_relro(&mut self) {
972 fn partial_relro(&mut self) {
975 fn no_relro(&mut self) {
978 fn build_static_executable(&mut self) {
981 fn args(&mut self, args: &[String]) {
985 fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
986 self.cmd.arg("-l").arg(lib);
989 fn link_framework(&mut self, _framework: &str) {
990 panic!("frameworks not supported")
993 fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
994 self.cmd.arg("-l").arg(lib);
997 fn link_whole_rlib(&mut self, lib: &Path) {
1001 fn gc_sections(&mut self, _keep_metadata: bool) {
1002 self.cmd.arg("--gc-sections");
1005 fn optimize(&mut self) {
1006 self.cmd.arg(match self.sess.opts.optimize {
1007 OptLevel::No => "-O0",
1008 OptLevel::Less => "-O1",
1009 OptLevel::Default => "-O2",
1010 OptLevel::Aggressive => "-O3",
1011 // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2`
1013 OptLevel::Size => "-O2",
1014 OptLevel::SizeMin => "-O2"
1018 fn pgo_gen(&mut self) {
1021 fn debuginfo(&mut self) {
1024 fn no_default_libraries(&mut self) {
1027 fn build_dylib(&mut self, _out_filename: &Path) {
1030 fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
1031 for sym in self.info.exports[&crate_type].iter() {
1032 self.cmd.arg("--export").arg(&sym);
1036 fn subsystem(&mut self, _subsystem: &str) {
1039 fn no_position_independent_executable(&mut self) {
1042 fn finalize(&mut self) -> Command {
1043 ::std::mem::replace(&mut self.cmd, Command::new(""))
1046 // Not needed for now with LLD
1047 fn group_start(&mut self) {}
1048 fn group_end(&mut self) {}
1050 fn cross_lang_lto(&mut self) {
1051 // Do nothing for now
1055 fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
1056 if let Some(ref exports) = tcx.sess.target.target.options.override_export_symbols {
1057 return exports.clone()
1060 let mut symbols = Vec::new();
1062 let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
1063 for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
1064 if level.is_below_threshold(export_threshold) {
1065 symbols.push(symbol.symbol_name(tcx).to_string());
1069 let formats = tcx.sess.dependency_formats.borrow();
1070 let deps = formats[&crate_type].iter();
1072 for (index, dep_format) in deps.enumerate() {
1073 let cnum = CrateNum::new(index + 1);
1074 // For each dependency that we are linking to statically ...
1075 if *dep_format == Linkage::Static {
1076 // ... we add its symbol list to our export list.
1077 for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
1078 if level.is_below_threshold(export_threshold) {
1079 symbols.push(symbol.symbol_name(tcx).to_string());
1088 /// Much simplified and explicit CLI for the NVPTX linker. The linker operates
1089 /// with bitcode and uses LLVM backend to generate a PTX assembly.
1090 pub struct PtxLinker<'a> {
1095 impl<'a> Linker for PtxLinker<'a> {
1096 fn link_rlib(&mut self, path: &Path) {
1097 self.cmd.arg("--rlib").arg(path);
1100 fn link_whole_rlib(&mut self, path: &Path) {
1101 self.cmd.arg("--rlib").arg(path);
1104 fn include_path(&mut self, path: &Path) {
1105 self.cmd.arg("-L").arg(path);
1108 fn debuginfo(&mut self) {
1109 self.cmd.arg("--debug");
1112 fn add_object(&mut self, path: &Path) {
1113 self.cmd.arg("--bitcode").arg(path);
1116 fn args(&mut self, args: &[String]) {
1117 self.cmd.args(args);
1120 fn optimize(&mut self) {
1121 match self.sess.lto() {
1122 Lto::Thin | Lto::Fat | Lto::ThinLocal => {
1123 self.cmd.arg("-Olto");
1130 fn output_filename(&mut self, path: &Path) {
1131 self.cmd.arg("-o").arg(path);
1134 fn finalize(&mut self) -> Command {
1135 // Provide the linker with fallback to internal `target-cpu`.
1136 self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu {
1138 None => &self.sess.target.target.options.cpu
1141 ::std::mem::replace(&mut self.cmd, Command::new(""))
1144 fn link_dylib(&mut self, _lib: &str) {
1145 panic!("external dylibs not supported")
1148 fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) {
1149 panic!("external dylibs not supported")
1152 fn link_staticlib(&mut self, _lib: &str) {
1153 panic!("staticlibs not supported")
1156 fn link_whole_staticlib(&mut self, _lib: &str, _search_path: &[PathBuf]) {
1157 panic!("staticlibs not supported")
1160 fn framework_path(&mut self, _path: &Path) {
1161 panic!("frameworks not supported")
1164 fn link_framework(&mut self, _framework: &str) {
1165 panic!("frameworks not supported")
1168 fn position_independent_executable(&mut self) {
1171 fn full_relro(&mut self) {
1174 fn partial_relro(&mut self) {
1177 fn no_relro(&mut self) {
1180 fn build_static_executable(&mut self) {
1183 fn gc_sections(&mut self, _keep_metadata: bool) {
1186 fn pgo_gen(&mut self) {
1189 fn no_default_libraries(&mut self) {
1192 fn build_dylib(&mut self, _out_filename: &Path) {
1195 fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {
1198 fn subsystem(&mut self, _subsystem: &str) {
1201 fn no_position_independent_executable(&mut self) {
1204 fn group_start(&mut self) {
1207 fn group_end(&mut self) {
1210 fn cross_lang_lto(&mut self) {