]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/back/linker.rs
Rollup merge of #50257 - estebank:fix-49560, r=nikomatsakis
[rust.git] / src / librustc_trans / back / linker.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use std::collections::HashMap;
12 use std::ffi::{OsStr, OsString};
13 use std::fs::{self, File};
14 use std::io::prelude::*;
15 use std::io::{self, BufWriter};
16 use std::path::{Path, PathBuf};
17
18 use back::archive;
19 use back::command::Command;
20 use back::symbol_export;
21 use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
22 use rustc::middle::dependency_format::Linkage;
23 use rustc::session::Session;
24 use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel};
25 use rustc::ty::TyCtxt;
26 use rustc_target::spec::{LinkerFlavor, LldFlavor};
27 use serialize::{json, Encoder};
28
29 /// For all the linkers we support, and information they might
30 /// need out of the shared crate context before we get rid of it.
31 pub struct LinkerInfo {
32     exports: HashMap<CrateType, Vec<String>>,
33 }
34
35 impl LinkerInfo {
36     pub fn new(tcx: TyCtxt) -> LinkerInfo {
37         LinkerInfo {
38             exports: tcx.sess.crate_types.borrow().iter().map(|&c| {
39                 (c, exported_symbols(tcx, c))
40             }).collect(),
41         }
42     }
43
44     pub fn to_linker<'a>(&'a self,
45                          cmd: Command,
46                          sess: &'a Session) -> Box<Linker+'a> {
47         match sess.linker_flavor() {
48             LinkerFlavor::Lld(LldFlavor::Link) |
49             LinkerFlavor::Msvc => {
50                 Box::new(MsvcLinker {
51                     cmd,
52                     sess,
53                     info: self
54                 }) as Box<Linker>
55             }
56             LinkerFlavor::Em =>  {
57                 Box::new(EmLinker {
58                     cmd,
59                     sess,
60                     info: self
61                 }) as Box<Linker>
62             }
63             LinkerFlavor::Gcc =>  {
64                 Box::new(GccLinker {
65                     cmd,
66                     sess,
67                     info: self,
68                     hinted_static: false,
69                     is_ld: false,
70                 }) as Box<Linker>
71             }
72
73             LinkerFlavor::Lld(LldFlavor::Ld) |
74             LinkerFlavor::Lld(LldFlavor::Ld64) |
75             LinkerFlavor::Ld => {
76                 Box::new(GccLinker {
77                     cmd,
78                     sess,
79                     info: self,
80                     hinted_static: false,
81                     is_ld: true,
82                 }) as Box<Linker>
83             }
84
85             LinkerFlavor::Lld(LldFlavor::Wasm) => {
86                 Box::new(WasmLd {
87                     cmd,
88                 }) as Box<Linker>
89             }
90         }
91     }
92 }
93
94 /// Linker abstraction used by back::link to build up the command to invoke a
95 /// linker.
96 ///
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.
101 pub trait Linker {
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     // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
131     fn finalize(&mut self) -> Command;
132 }
133
134 pub struct GccLinker<'a> {
135     cmd: Command,
136     sess: &'a Session,
137     info: &'a LinkerInfo,
138     hinted_static: bool, // Keeps track of the current hinting mode.
139     // Link as ld
140     is_ld: bool,
141 }
142
143 impl<'a> GccLinker<'a> {
144     /// Argument that must be passed *directly* to the linker
145     ///
146     /// These arguments need to be prepended with '-Wl,' when a gcc-style linker is used
147     fn linker_arg<S>(&mut self, arg: S) -> &mut Self
148         where S: AsRef<OsStr>
149     {
150         if !self.is_ld {
151             let mut os = OsString::from("-Wl,");
152             os.push(arg.as_ref());
153             self.cmd.arg(os);
154         } else {
155             self.cmd.arg(arg);
156         }
157         self
158     }
159
160     fn takes_hints(&self) -> bool {
161         !self.sess.target.target.options.is_like_osx
162     }
163
164     // Some platforms take hints about whether a library is static or dynamic.
165     // For those that support this, we ensure we pass the option if the library
166     // was flagged "static" (most defaults are dynamic) to ensure that if
167     // libfoo.a and libfoo.so both exist that the right one is chosen.
168     fn hint_static(&mut self) {
169         if !self.takes_hints() { return }
170         if !self.hinted_static {
171             self.linker_arg("-Bstatic");
172             self.hinted_static = true;
173         }
174     }
175
176     fn hint_dynamic(&mut self) {
177         if !self.takes_hints() { return }
178         if self.hinted_static {
179             self.linker_arg("-Bdynamic");
180             self.hinted_static = false;
181         }
182     }
183 }
184
185 impl<'a> Linker for GccLinker<'a> {
186     fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); }
187     fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); }
188     fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); }
189     fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); }
190     fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); }
191     fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
192     fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
193     fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
194     fn no_position_independent_executable(&mut self) { self.cmd.arg("-no-pie"); }
195     fn full_relro(&mut self) { self.linker_arg("-z,relro,-z,now"); }
196     fn partial_relro(&mut self) { self.linker_arg("-z,relro"); }
197     fn no_relro(&mut self) { self.linker_arg("-z,norelro"); }
198     fn build_static_executable(&mut self) { self.cmd.arg("-static"); }
199     fn args(&mut self, args: &[String]) { self.cmd.args(args); }
200
201     fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
202         self.hint_dynamic();
203         self.cmd.arg("-l").arg(lib);
204     }
205
206     fn link_framework(&mut self, framework: &str) {
207         self.hint_dynamic();
208         self.cmd.arg("-framework").arg(framework);
209     }
210
211     // Here we explicitly ask that the entire archive is included into the
212     // result artifact. For more details see #15460, but the gist is that
213     // the linker will strip away any unused objects in the archive if we
214     // don't otherwise explicitly reference them. This can occur for
215     // libraries which are just providing bindings, libraries with generic
216     // functions, etc.
217     fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
218         self.hint_static();
219         let target = &self.sess.target.target;
220         if !target.options.is_like_osx {
221             self.linker_arg("--whole-archive").cmd.arg("-l").arg(lib);
222             self.linker_arg("--no-whole-archive");
223         } else {
224             // -force_load is the macOS equivalent of --whole-archive, but it
225             // involves passing the full path to the library to link.
226             let mut v = OsString::from("-force_load,");
227             v.push(&archive::find_library(lib, search_path, &self.sess));
228             self.linker_arg(&v);
229         }
230     }
231
232     fn link_whole_rlib(&mut self, lib: &Path) {
233         self.hint_static();
234         if self.sess.target.target.options.is_like_osx {
235             let mut v = OsString::from("-force_load,");
236             v.push(lib);
237             self.linker_arg(&v);
238         } else {
239             self.linker_arg("--whole-archive").cmd.arg(lib);
240             self.linker_arg("--no-whole-archive");
241         }
242     }
243
244     fn gc_sections(&mut self, keep_metadata: bool) {
245         // The dead_strip option to the linker specifies that functions and data
246         // unreachable by the entry point will be removed. This is quite useful
247         // with Rust's compilation model of compiling libraries at a time into
248         // one object file. For example, this brings hello world from 1.7MB to
249         // 458K.
250         //
251         // Note that this is done for both executables and dynamic libraries. We
252         // won't get much benefit from dylibs because LLVM will have already
253         // stripped away as much as it could. This has not been seen to impact
254         // link times negatively.
255         //
256         // -dead_strip can't be part of the pre_link_args because it's also used
257         // for partial linking when using multiple codegen units (-r).  So we
258         // insert it here.
259         if self.sess.target.target.options.is_like_osx {
260             self.linker_arg("-dead_strip");
261         } else if self.sess.target.target.options.is_like_solaris {
262             self.linker_arg("-z");
263             self.linker_arg("ignore");
264
265         // If we're building a dylib, we don't use --gc-sections because LLVM
266         // has already done the best it can do, and we also don't want to
267         // eliminate the metadata. If we're building an executable, however,
268         // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
269         // reduction.
270         } else if !keep_metadata {
271             self.linker_arg("--gc-sections");
272         }
273     }
274
275     fn optimize(&mut self) {
276         if !self.sess.target.target.options.linker_is_gnu { return }
277
278         // GNU-style linkers support optimization with -O. GNU ld doesn't
279         // need a numeric argument, but other linkers do.
280         if self.sess.opts.optimize == config::OptLevel::Default ||
281            self.sess.opts.optimize == config::OptLevel::Aggressive {
282             self.linker_arg("-O1");
283         }
284     }
285
286     fn pgo_gen(&mut self) {
287         if !self.sess.target.target.options.linker_is_gnu { return }
288
289         // If we're doing PGO generation stuff and on a GNU-like linker, use the
290         // "-u" flag to properly pull in the profiler runtime bits.
291         //
292         // This is because LLVM otherwise won't add the needed initialization
293         // for us on Linux (though the extra flag should be harmless if it
294         // does).
295         //
296         // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030.
297         //
298         // Though it may be worth to try to revert those changes upstream, since
299         // the overhead of the initialization should be minor.
300         self.cmd.arg("-u");
301         self.cmd.arg("__llvm_profile_runtime");
302     }
303
304     fn debuginfo(&mut self) {
305         match self.sess.opts.debuginfo {
306             DebugInfoLevel::NoDebugInfo => {
307                 // If we are building without debuginfo enabled and we were called with
308                 // `-Zstrip-debuginfo-if-disabled=yes`, tell the linker to strip any debuginfo
309                 // found when linking to get rid of symbols from libstd.
310                 match self.sess.opts.debugging_opts.strip_debuginfo_if_disabled {
311                     Some(true) => { self.linker_arg("-S"); },
312                     _ => {},
313                 }
314             },
315             _ => {},
316         };
317     }
318
319     fn no_default_libraries(&mut self) {
320         if !self.is_ld {
321             self.cmd.arg("-nodefaultlibs");
322         }
323     }
324
325     fn build_dylib(&mut self, out_filename: &Path) {
326         // On mac we need to tell the linker to let this library be rpathed
327         if self.sess.target.target.options.is_like_osx {
328             self.cmd.arg("-dynamiclib");
329             self.linker_arg("-dylib");
330
331             // Note that the `osx_rpath_install_name` option here is a hack
332             // purely to support rustbuild right now, we should get a more
333             // principled solution at some point to force the compiler to pass
334             // the right `-Wl,-install_name` with an `@rpath` in it.
335             if self.sess.opts.cg.rpath ||
336                self.sess.opts.debugging_opts.osx_rpath_install_name {
337                 let mut v = OsString::from("-install_name,@rpath/");
338                 v.push(out_filename.file_name().unwrap());
339                 self.linker_arg(&v);
340             }
341         } else {
342             self.cmd.arg("-shared");
343         }
344     }
345
346     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
347         // If we're compiling a dylib, then we let symbol visibility in object
348         // files to take care of whether they're exported or not.
349         //
350         // If we're compiling a cdylib, however, we manually create a list of
351         // exported symbols to ensure we don't expose any more. The object files
352         // have far more public symbols than we actually want to export, so we
353         // hide them all here.
354         if crate_type == CrateType::CrateTypeDylib ||
355            crate_type == CrateType::CrateTypeProcMacro {
356             return
357         }
358
359         let mut arg = OsString::new();
360         let path = tmpdir.join("list");
361
362         debug!("EXPORTED SYMBOLS:");
363
364         if self.sess.target.target.options.is_like_osx {
365             // Write a plain, newline-separated list of symbols
366             let res = (|| -> io::Result<()> {
367                 let mut f = BufWriter::new(File::create(&path)?);
368                 for sym in self.info.exports[&crate_type].iter() {
369                     debug!("  _{}", sym);
370                     writeln!(f, "_{}", sym)?;
371                 }
372                 Ok(())
373             })();
374             if let Err(e) = res {
375                 self.sess.fatal(&format!("failed to write lib.def file: {}", e));
376             }
377         } else {
378             // Write an LD version script
379             let res = (|| -> io::Result<()> {
380                 let mut f = BufWriter::new(File::create(&path)?);
381                 writeln!(f, "{{\n  global:")?;
382                 for sym in self.info.exports[&crate_type].iter() {
383                     debug!("    {};", sym);
384                     writeln!(f, "    {};", sym)?;
385                 }
386                 writeln!(f, "\n  local:\n    *;\n}};")?;
387                 Ok(())
388             })();
389             if let Err(e) = res {
390                 self.sess.fatal(&format!("failed to write version script: {}", e));
391             }
392         }
393
394         if self.sess.target.target.options.is_like_osx {
395             if !self.is_ld {
396                 arg.push("-Wl,")
397             }
398             arg.push("-exported_symbols_list,");
399         } else if self.sess.target.target.options.is_like_solaris {
400             if !self.is_ld {
401                 arg.push("-Wl,")
402             }
403             arg.push("-M,");
404         } else {
405             if !self.is_ld {
406                 arg.push("-Wl,")
407             }
408             arg.push("--version-script=");
409         }
410
411         arg.push(&path);
412         self.cmd.arg(arg);
413     }
414
415     fn subsystem(&mut self, subsystem: &str) {
416         self.linker_arg(&format!("--subsystem,{}", subsystem));
417     }
418
419     fn finalize(&mut self) -> Command {
420         self.hint_dynamic(); // Reset to default before returning the composed command line.
421         let mut cmd = Command::new("");
422         ::std::mem::swap(&mut cmd, &mut self.cmd);
423         cmd
424     }
425
426     fn group_start(&mut self) {
427         if !self.sess.target.target.options.is_like_osx {
428             self.linker_arg("--start-group");
429         }
430     }
431
432     fn group_end(&mut self) {
433         if !self.sess.target.target.options.is_like_osx {
434             self.linker_arg("--end-group");
435         }
436     }
437 }
438
439 pub struct MsvcLinker<'a> {
440     cmd: Command,
441     sess: &'a Session,
442     info: &'a LinkerInfo
443 }
444
445 impl<'a> Linker for MsvcLinker<'a> {
446     fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
447     fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
448     fn args(&mut self, args: &[String]) { self.cmd.args(args); }
449
450     fn build_dylib(&mut self, out_filename: &Path) {
451         self.cmd.arg("/DLL");
452         let mut arg: OsString = "/IMPLIB:".into();
453         arg.push(out_filename.with_extension("dll.lib"));
454         self.cmd.arg(arg);
455     }
456
457     fn build_static_executable(&mut self) {
458         // noop
459     }
460
461     fn gc_sections(&mut self, _keep_metadata: bool) {
462         // MSVC's ICF (Identical COMDAT Folding) link optimization is
463         // slow for Rust and thus we disable it by default when not in
464         // optimization build.
465         if self.sess.opts.optimize != config::OptLevel::No {
466             self.cmd.arg("/OPT:REF,ICF");
467         } else {
468             // It is necessary to specify NOICF here, because /OPT:REF
469             // implies ICF by default.
470             self.cmd.arg("/OPT:REF,NOICF");
471         }
472     }
473
474     fn link_dylib(&mut self, lib: &str) {
475         self.cmd.arg(&format!("{}.lib", lib));
476     }
477
478     fn link_rust_dylib(&mut self, lib: &str, path: &Path) {
479         // When producing a dll, the MSVC linker may not actually emit a
480         // `foo.lib` file if the dll doesn't actually export any symbols, so we
481         // check to see if the file is there and just omit linking to it if it's
482         // not present.
483         let name = format!("{}.dll.lib", lib);
484         if fs::metadata(&path.join(&name)).is_ok() {
485             self.cmd.arg(name);
486         }
487     }
488
489     fn link_staticlib(&mut self, lib: &str) {
490         self.cmd.arg(&format!("{}.lib", lib));
491     }
492
493     fn position_independent_executable(&mut self) {
494         // noop
495     }
496
497     fn no_position_independent_executable(&mut self) {
498         // noop
499     }
500
501     fn full_relro(&mut self) {
502         // noop
503     }
504
505     fn partial_relro(&mut self) {
506         // noop
507     }
508
509     fn no_relro(&mut self) {
510         // noop
511     }
512
513     fn no_default_libraries(&mut self) {
514         // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC
515         // as there's been trouble in the past of linking the C++ standard
516         // library required by LLVM. This likely needs to happen one day, but
517         // in general Windows is also a more controlled environment than
518         // Unix, so it's not necessarily as critical that this be implemented.
519         //
520         // Note that there are also some licensing worries about statically
521         // linking some libraries which require a specific agreement, so it may
522         // not ever be possible for us to pass this flag.
523     }
524
525     fn include_path(&mut self, path: &Path) {
526         let mut arg = OsString::from("/LIBPATH:");
527         arg.push(path);
528         self.cmd.arg(&arg);
529     }
530
531     fn output_filename(&mut self, path: &Path) {
532         let mut arg = OsString::from("/OUT:");
533         arg.push(path);
534         self.cmd.arg(&arg);
535     }
536
537     fn framework_path(&mut self, _path: &Path) {
538         bug!("frameworks are not supported on windows")
539     }
540     fn link_framework(&mut self, _framework: &str) {
541         bug!("frameworks are not supported on windows")
542     }
543
544     fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
545         // not supported?
546         self.link_staticlib(lib);
547     }
548     fn link_whole_rlib(&mut self, path: &Path) {
549         // not supported?
550         self.link_rlib(path);
551     }
552     fn optimize(&mut self) {
553         // Needs more investigation of `/OPT` arguments
554     }
555
556     fn pgo_gen(&mut self) {
557         // Nothing needed here.
558     }
559
560     fn debuginfo(&mut self) {
561         // This will cause the Microsoft linker to generate a PDB file
562         // from the CodeView line tables in the object files.
563         self.cmd.arg("/DEBUG");
564
565         // This will cause the Microsoft linker to embed .natvis info into the the PDB file
566         let sysroot = self.sess.sysroot();
567         let natvis_dir_path = sysroot.join("lib\\rustlib\\etc");
568         if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) {
569             // LLVM 5.0.0's lld-link frontend doesn't yet recognize, and chokes
570             // on, the /NATVIS:... flags.  LLVM 6 (or earlier) should at worst ignore
571             // them, eventually mooting this workaround, per this landed patch:
572             // https://github.com/llvm-mirror/lld/commit/27b9c4285364d8d76bb43839daa100
573             if let Some(ref linker_path) = self.sess.opts.cg.linker {
574                 if let Some(linker_name) = Path::new(&linker_path).file_stem() {
575                     if linker_name.to_str().unwrap().to_lowercase() == "lld-link" {
576                         self.sess.warn("not embedding natvis: lld-link may not support the flag");
577                         return;
578                     }
579                 }
580             }
581             for entry in natvis_dir {
582                 match entry {
583                     Ok(entry) => {
584                         let path = entry.path();
585                         if path.extension() == Some("natvis".as_ref()) {
586                             let mut arg = OsString::from("/NATVIS:");
587                             arg.push(path);
588                             self.cmd.arg(arg);
589                         }
590                     },
591                     Err(err) => {
592                         self.sess.warn(&format!("error enumerating natvis directory: {}", err));
593                     },
594                 }
595             }
596         }
597     }
598
599     // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
600     // export symbols from a dynamic library. When building a dynamic library,
601     // however, we're going to want some symbols exported, so this function
602     // generates a DEF file which lists all the symbols.
603     //
604     // The linker will read this `*.def` file and export all the symbols from
605     // the dynamic library. Note that this is not as simple as just exporting
606     // all the symbols in the current crate (as specified by `trans.reachable`)
607     // but rather we also need to possibly export the symbols of upstream
608     // crates. Upstream rlibs may be linked statically to this dynamic library,
609     // in which case they may continue to transitively be used and hence need
610     // their symbols exported.
611     fn export_symbols(&mut self,
612                       tmpdir: &Path,
613                       crate_type: CrateType) {
614         let path = tmpdir.join("lib.def");
615         let res = (|| -> io::Result<()> {
616             let mut f = BufWriter::new(File::create(&path)?);
617
618             // Start off with the standard module name header and then go
619             // straight to exports.
620             writeln!(f, "LIBRARY")?;
621             writeln!(f, "EXPORTS")?;
622             for symbol in self.info.exports[&crate_type].iter() {
623                 debug!("  _{}", symbol);
624                 writeln!(f, "  {}", symbol)?;
625             }
626             Ok(())
627         })();
628         if let Err(e) = res {
629             self.sess.fatal(&format!("failed to write lib.def file: {}", e));
630         }
631         let mut arg = OsString::from("/DEF:");
632         arg.push(path);
633         self.cmd.arg(&arg);
634     }
635
636     fn subsystem(&mut self, subsystem: &str) {
637         // Note that previous passes of the compiler validated this subsystem,
638         // so we just blindly pass it to the linker.
639         self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem));
640
641         // Windows has two subsystems we're interested in right now, the console
642         // and windows subsystems. These both implicitly have different entry
643         // points (starting symbols). The console entry point starts with
644         // `mainCRTStartup` and the windows entry point starts with
645         // `WinMainCRTStartup`. These entry points, defined in system libraries,
646         // will then later probe for either `main` or `WinMain`, respectively to
647         // start the application.
648         //
649         // In Rust we just always generate a `main` function so we want control
650         // to always start there, so we force the entry point on the windows
651         // subsystem to be `mainCRTStartup` to get everything booted up
652         // correctly.
653         //
654         // For more information see RFC #1665
655         if subsystem == "windows" {
656             self.cmd.arg("/ENTRY:mainCRTStartup");
657         }
658     }
659
660     fn finalize(&mut self) -> Command {
661         let mut cmd = Command::new("");
662         ::std::mem::swap(&mut cmd, &mut self.cmd);
663         cmd
664     }
665
666     // MSVC doesn't need group indicators
667     fn group_start(&mut self) {}
668     fn group_end(&mut self) {}
669 }
670
671 pub struct EmLinker<'a> {
672     cmd: Command,
673     sess: &'a Session,
674     info: &'a LinkerInfo
675 }
676
677 impl<'a> Linker for EmLinker<'a> {
678     fn include_path(&mut self, path: &Path) {
679         self.cmd.arg("-L").arg(path);
680     }
681
682     fn link_staticlib(&mut self, lib: &str) {
683         self.cmd.arg("-l").arg(lib);
684     }
685
686     fn output_filename(&mut self, path: &Path) {
687         self.cmd.arg("-o").arg(path);
688     }
689
690     fn add_object(&mut self, path: &Path) {
691         self.cmd.arg(path);
692     }
693
694     fn link_dylib(&mut self, lib: &str) {
695         // Emscripten always links statically
696         self.link_staticlib(lib);
697     }
698
699     fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
700         // not supported?
701         self.link_staticlib(lib);
702     }
703
704     fn link_whole_rlib(&mut self, lib: &Path) {
705         // not supported?
706         self.link_rlib(lib);
707     }
708
709     fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
710         self.link_dylib(lib);
711     }
712
713     fn link_rlib(&mut self, lib: &Path) {
714         self.add_object(lib);
715     }
716
717     fn position_independent_executable(&mut self) {
718         // noop
719     }
720
721     fn no_position_independent_executable(&mut self) {
722         // noop
723     }
724
725     fn full_relro(&mut self) {
726         // noop
727     }
728
729     fn partial_relro(&mut self) {
730         // noop
731     }
732
733     fn no_relro(&mut self) {
734         // noop
735     }
736
737     fn args(&mut self, args: &[String]) {
738         self.cmd.args(args);
739     }
740
741     fn framework_path(&mut self, _path: &Path) {
742         bug!("frameworks are not supported on Emscripten")
743     }
744
745     fn link_framework(&mut self, _framework: &str) {
746         bug!("frameworks are not supported on Emscripten")
747     }
748
749     fn gc_sections(&mut self, _keep_metadata: bool) {
750         // noop
751     }
752
753     fn optimize(&mut self) {
754         // Emscripten performs own optimizations
755         self.cmd.arg(match self.sess.opts.optimize {
756             OptLevel::No => "-O0",
757             OptLevel::Less => "-O1",
758             OptLevel::Default => "-O2",
759             OptLevel::Aggressive => "-O3",
760             OptLevel::Size => "-Os",
761             OptLevel::SizeMin => "-Oz"
762         });
763         // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved
764         self.cmd.args(&["--memory-init-file", "0"]);
765     }
766
767     fn pgo_gen(&mut self) {
768         // noop, but maybe we need something like the gnu linker?
769     }
770
771     fn debuginfo(&mut self) {
772         // Preserve names or generate source maps depending on debug info
773         self.cmd.arg(match self.sess.opts.debuginfo {
774             DebugInfoLevel::NoDebugInfo => "-g0",
775             DebugInfoLevel::LimitedDebugInfo => "-g3",
776             DebugInfoLevel::FullDebugInfo => "-g4"
777         });
778     }
779
780     fn no_default_libraries(&mut self) {
781         self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
782     }
783
784     fn build_dylib(&mut self, _out_filename: &Path) {
785         bug!("building dynamic library is unsupported on Emscripten")
786     }
787
788     fn build_static_executable(&mut self) {
789         // noop
790     }
791
792     fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
793         let symbols = &self.info.exports[&crate_type];
794
795         debug!("EXPORTED SYMBOLS:");
796
797         self.cmd.arg("-s");
798
799         let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
800         let mut encoded = String::new();
801
802         {
803             let mut encoder = json::Encoder::new(&mut encoded);
804             let res = encoder.emit_seq(symbols.len(), |encoder| {
805                 for (i, sym) in symbols.iter().enumerate() {
806                     encoder.emit_seq_elt(i, |encoder| {
807                         encoder.emit_str(&("_".to_string() + sym))
808                     })?;
809                 }
810                 Ok(())
811             });
812             if let Err(e) = res {
813                 self.sess.fatal(&format!("failed to encode exported symbols: {}", e));
814             }
815         }
816         debug!("{}", encoded);
817         arg.push(encoded);
818
819         self.cmd.arg(arg);
820     }
821
822     fn subsystem(&mut self, _subsystem: &str) {
823         // noop
824     }
825
826     fn finalize(&mut self) -> Command {
827         let mut cmd = Command::new("");
828         ::std::mem::swap(&mut cmd, &mut self.cmd);
829         cmd
830     }
831
832     // Appears not necessary on Emscripten
833     fn group_start(&mut self) {}
834     fn group_end(&mut self) {}
835 }
836
837 fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
838     let mut symbols = Vec::new();
839
840     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
841     for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
842         if level.is_below_threshold(export_threshold) {
843             symbols.push(symbol.symbol_name(tcx).to_string());
844         }
845     }
846
847     let formats = tcx.sess.dependency_formats.borrow();
848     let deps = formats[&crate_type].iter();
849
850     for (index, dep_format) in deps.enumerate() {
851         let cnum = CrateNum::new(index + 1);
852         // For each dependency that we are linking to statically ...
853         if *dep_format == Linkage::Static {
854             // ... we add its symbol list to our export list.
855             for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
856                 if level.is_below_threshold(export_threshold) {
857                     symbols.push(symbol.symbol_name(tcx).to_string());
858                 }
859             }
860         }
861     }
862
863     symbols
864 }
865
866 pub struct WasmLd {
867     cmd: Command,
868 }
869
870 impl Linker for WasmLd {
871     fn link_dylib(&mut self, lib: &str) {
872         self.cmd.arg("-l").arg(lib);
873     }
874
875     fn link_staticlib(&mut self, lib: &str) {
876         self.cmd.arg("-l").arg(lib);
877     }
878
879     fn link_rlib(&mut self, lib: &Path) {
880         self.cmd.arg(lib);
881     }
882
883     fn include_path(&mut self, path: &Path) {
884         self.cmd.arg("-L").arg(path);
885     }
886
887     fn framework_path(&mut self, _path: &Path) {
888         panic!("frameworks not supported")
889     }
890
891     fn output_filename(&mut self, path: &Path) {
892         self.cmd.arg("-o").arg(path);
893     }
894
895     fn add_object(&mut self, path: &Path) {
896         self.cmd.arg(path);
897     }
898
899     fn position_independent_executable(&mut self) {
900     }
901
902     fn full_relro(&mut self) {
903     }
904
905     fn partial_relro(&mut self) {
906     }
907
908     fn no_relro(&mut self) {
909     }
910
911     fn build_static_executable(&mut self) {
912     }
913
914     fn args(&mut self, args: &[String]) {
915         self.cmd.args(args);
916     }
917
918     fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
919         self.cmd.arg("-l").arg(lib);
920     }
921
922     fn link_framework(&mut self, _framework: &str) {
923         panic!("frameworks not supported")
924     }
925
926     fn link_whole_staticlib(&mut self, lib: &str, _search_path: &[PathBuf]) {
927         self.cmd.arg("-l").arg(lib);
928     }
929
930     fn link_whole_rlib(&mut self, lib: &Path) {
931         self.cmd.arg(lib);
932     }
933
934     fn gc_sections(&mut self, _keep_metadata: bool) {
935     }
936
937     fn optimize(&mut self) {
938     }
939
940     fn pgo_gen(&mut self) {
941     }
942
943     fn debuginfo(&mut self) {
944     }
945
946     fn no_default_libraries(&mut self) {
947     }
948
949     fn build_dylib(&mut self, _out_filename: &Path) {
950     }
951
952     fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {
953     }
954
955     fn subsystem(&mut self, _subsystem: &str) {
956     }
957
958     fn no_position_independent_executable(&mut self) {
959     }
960
961     fn finalize(&mut self) -> Command {
962         // There have been reports in the wild (rustwasm/wasm-bindgen#119) of
963         // using threads causing weird hangs and bugs. Disable it entirely as
964         // this isn't yet the bottleneck of compilation at all anyway.
965         self.cmd.arg("--no-threads");
966
967         self.cmd.arg("-z").arg("stack-size=1048576");
968
969         // FIXME we probably shouldn't pass this but instead pass an explicit
970         // whitelist of symbols we'll allow to be undefined. Unfortunately
971         // though we can't handle symbols like `log10` that LLVM injects at a
972         // super late date without actually parsing object files. For now let's
973         // stick to this and hopefully fix it before stabilization happens.
974         self.cmd.arg("--allow-undefined");
975
976         // For now we just never have an entry symbol
977         self.cmd.arg("--no-entry");
978
979         let mut cmd = Command::new("");
980         ::std::mem::swap(&mut cmd, &mut self.cmd);
981         cmd
982     }
983
984     // Not needed for now with LLD
985     fn group_start(&mut self) {}
986     fn group_end(&mut self) {}
987 }