]>
Commit | Line | Data |
---|---|---|
a1dfa0c6 XL |
1 | use super::symbol_export; |
2 | use super::command::Command; | |
3 | use super::archive; | |
4 | ||
b7449926 | 5 | use rustc_data_structures::fx::FxHashMap; |
cc61c64b | 6 | use std::ffi::{OsStr, OsString}; |
e9174d1e | 7 | use std::fs::{self, File}; |
e9174d1e | 8 | use std::io::prelude::*; |
9e0c209e | 9 | use std::io::{self, BufWriter}; |
62682a34 | 10 | use std::path::{Path, PathBuf}; |
3157f602 | 11 | |
476ff2be | 12 | use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; |
ea8adc8c | 13 | use rustc::middle::dependency_format::Linkage; |
7cac9316 | 14 | use rustc::session::Session; |
b7449926 | 15 | use rustc::session::config::{self, CrateType, OptLevel, DebugInfo, |
9fa01778 | 16 | LinkerPluginLto, Lto}; |
ea8adc8c | 17 | use rustc::ty::TyCtxt; |
83c7162d | 18 | use rustc_target::spec::{LinkerFlavor, LldFlavor}; |
416331ca | 19 | use rustc_serialize::{json, Encoder}; |
e1599b0c | 20 | use syntax::symbol::Symbol; |
3157f602 XL |
21 | |
22 | /// For all the linkers we support, and information they might | |
23 | /// need out of the shared crate context before we get rid of it. | |
24 | pub struct LinkerInfo { | |
b7449926 | 25 | exports: FxHashMap<CrateType, Vec<String>>, |
3157f602 XL |
26 | } |
27 | ||
ea8adc8c | 28 | impl LinkerInfo { |
dc9dc135 | 29 | pub fn new(tcx: TyCtxt<'_>) -> LinkerInfo { |
3157f602 | 30 | LinkerInfo { |
ea8adc8c XL |
31 | exports: tcx.sess.crate_types.borrow().iter().map(|&c| { |
32 | (c, exported_symbols(tcx, c)) | |
9e0c209e | 33 | }).collect(), |
3157f602 XL |
34 | } |
35 | } | |
36 | ||
a1dfa0c6 XL |
37 | pub fn to_linker<'a>( |
38 | &'a self, | |
39 | cmd: Command, | |
40 | sess: &'a Session, | |
41 | flavor: LinkerFlavor, | |
42 | target_cpu: &'a str, | |
43 | ) -> Box<dyn Linker+'a> { | |
b7449926 | 44 | match flavor { |
0531ce1d | 45 | LinkerFlavor::Lld(LldFlavor::Link) | |
cc61c64b XL |
46 | LinkerFlavor::Msvc => { |
47 | Box::new(MsvcLinker { | |
3b2f2976 XL |
48 | cmd, |
49 | sess, | |
cc61c64b | 50 | info: self |
8faf50e0 | 51 | }) as Box<dyn Linker> |
cc61c64b XL |
52 | } |
53 | LinkerFlavor::Em => { | |
54 | Box::new(EmLinker { | |
3b2f2976 XL |
55 | cmd, |
56 | sess, | |
cc61c64b | 57 | info: self |
8faf50e0 | 58 | }) as Box<dyn Linker> |
cc61c64b XL |
59 | } |
60 | LinkerFlavor::Gcc => { | |
61 | Box::new(GccLinker { | |
3b2f2976 XL |
62 | cmd, |
63 | sess, | |
cc61c64b XL |
64 | info: self, |
65 | hinted_static: false, | |
66 | is_ld: false, | |
a1dfa0c6 | 67 | target_cpu, |
8faf50e0 | 68 | }) as Box<dyn Linker> |
cc61c64b | 69 | } |
0531ce1d XL |
70 | |
71 | LinkerFlavor::Lld(LldFlavor::Ld) | | |
72 | LinkerFlavor::Lld(LldFlavor::Ld64) | | |
cc61c64b XL |
73 | LinkerFlavor::Ld => { |
74 | Box::new(GccLinker { | |
3b2f2976 XL |
75 | cmd, |
76 | sess, | |
cc61c64b XL |
77 | info: self, |
78 | hinted_static: false, | |
79 | is_ld: true, | |
a1dfa0c6 | 80 | target_cpu, |
8faf50e0 | 81 | }) as Box<dyn Linker> |
cc61c64b | 82 | } |
0531ce1d XL |
83 | |
84 | LinkerFlavor::Lld(LldFlavor::Wasm) => { | |
0731742a | 85 | Box::new(WasmLd::new(cmd, sess, self)) as Box<dyn Linker> |
abe05a73 | 86 | } |
9fa01778 XL |
87 | |
88 | LinkerFlavor::PtxLinker => { | |
89 | Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker> | |
90 | } | |
3157f602 XL |
91 | } |
92 | } | |
93 | } | |
62682a34 | 94 | |
9fa01778 | 95 | /// Linker abstraction used by `back::link` to build up the command to invoke a |
62682a34 SL |
96 | /// linker. |
97 | /// | |
98 | /// This trait is the total list of requirements needed by `back::link` and | |
99 | /// represents the meaning of each option being passed down. This trait is then | |
100 | /// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an | |
0731742a | 101 | /// MSVC linker (e.g., `link.exe`) is being used. |
62682a34 | 102 | pub trait Linker { |
e1599b0c XL |
103 | fn link_dylib(&mut self, lib: Symbol); |
104 | fn link_rust_dylib(&mut self, lib: Symbol, path: &Path); | |
105 | fn link_framework(&mut self, framework: Symbol); | |
106 | fn link_staticlib(&mut self, lib: Symbol); | |
62682a34 | 107 | fn link_rlib(&mut self, lib: &Path); |
c1a9b12d | 108 | fn link_whole_rlib(&mut self, lib: &Path); |
e1599b0c | 109 | fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]); |
62682a34 SL |
110 | fn include_path(&mut self, path: &Path); |
111 | fn framework_path(&mut self, path: &Path); | |
112 | fn output_filename(&mut self, path: &Path); | |
113 | fn add_object(&mut self, path: &Path); | |
a7813a04 | 114 | fn gc_sections(&mut self, keep_metadata: bool); |
62682a34 | 115 | fn position_independent_executable(&mut self); |
0531ce1d | 116 | fn no_position_independent_executable(&mut self); |
3b2f2976 | 117 | fn full_relro(&mut self); |
0531ce1d XL |
118 | fn partial_relro(&mut self); |
119 | fn no_relro(&mut self); | |
62682a34 | 120 | fn optimize(&mut self); |
0531ce1d | 121 | fn pgo_gen(&mut self); |
c1a9b12d | 122 | fn debuginfo(&mut self); |
62682a34 SL |
123 | fn no_default_libraries(&mut self); |
124 | fn build_dylib(&mut self, out_filename: &Path); | |
3b2f2976 | 125 | fn build_static_executable(&mut self); |
62682a34 | 126 | fn args(&mut self, args: &[String]); |
3157f602 | 127 | fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType); |
c30ab7b3 | 128 | fn subsystem(&mut self, subsystem: &str); |
0531ce1d XL |
129 | fn group_start(&mut self); |
130 | fn group_end(&mut self); | |
9fa01778 | 131 | fn linker_plugin_lto(&mut self); |
cc61c64b XL |
132 | // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?). |
133 | fn finalize(&mut self) -> Command; | |
62682a34 SL |
134 | } |
135 | ||
cc61c64b XL |
136 | pub struct GccLinker<'a> { |
137 | cmd: Command, | |
3157f602 | 138 | sess: &'a Session, |
cc61c64b XL |
139 | info: &'a LinkerInfo, |
140 | hinted_static: bool, // Keeps track of the current hinting mode. | |
141 | // Link as ld | |
142 | is_ld: bool, | |
a1dfa0c6 | 143 | target_cpu: &'a str, |
62682a34 SL |
144 | } |
145 | ||
cc61c64b XL |
146 | impl<'a> GccLinker<'a> { |
147 | /// Argument that must be passed *directly* to the linker | |
148 | /// | |
9fa01778 | 149 | /// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used. |
cc61c64b XL |
150 | fn linker_arg<S>(&mut self, arg: S) -> &mut Self |
151 | where S: AsRef<OsStr> | |
152 | { | |
153 | if !self.is_ld { | |
154 | let mut os = OsString::from("-Wl,"); | |
155 | os.push(arg.as_ref()); | |
156 | self.cmd.arg(os); | |
157 | } else { | |
158 | self.cmd.arg(arg); | |
159 | } | |
160 | self | |
161 | } | |
162 | ||
62682a34 | 163 | fn takes_hints(&self) -> bool { |
532ac7d7 XL |
164 | // Really this function only returns true if the underlying linker |
165 | // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We | |
166 | // don't really have a foolproof way to detect that, so rule out some | |
167 | // platforms where currently this is guaranteed to *not* be the case: | |
168 | // | |
169 | // * On OSX they have their own linker, not binutils' | |
170 | // * For WebAssembly the only functional linker is LLD, which doesn't | |
171 | // support hint flags | |
172 | !self.sess.target.target.options.is_like_osx && | |
173 | self.sess.target.target.arch != "wasm32" | |
62682a34 | 174 | } |
cc61c64b XL |
175 | |
176 | // Some platforms take hints about whether a library is static or dynamic. | |
177 | // For those that support this, we ensure we pass the option if the library | |
178 | // was flagged "static" (most defaults are dynamic) to ensure that if | |
179 | // libfoo.a and libfoo.so both exist that the right one is chosen. | |
180 | fn hint_static(&mut self) { | |
181 | if !self.takes_hints() { return } | |
182 | if !self.hinted_static { | |
183 | self.linker_arg("-Bstatic"); | |
184 | self.hinted_static = true; | |
185 | } | |
186 | } | |
187 | ||
188 | fn hint_dynamic(&mut self) { | |
189 | if !self.takes_hints() { return } | |
190 | if self.hinted_static { | |
191 | self.linker_arg("-Bdynamic"); | |
192 | self.hinted_static = false; | |
193 | } | |
194 | } | |
8faf50e0 | 195 | |
9fa01778 | 196 | fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) { |
8faf50e0 XL |
197 | if let Some(plugin_path) = plugin_path { |
198 | let mut arg = OsString::from("-plugin="); | |
199 | arg.push(plugin_path); | |
200 | self.linker_arg(&arg); | |
201 | } | |
202 | ||
203 | let opt_level = match self.sess.opts.optimize { | |
204 | config::OptLevel::No => "O0", | |
205 | config::OptLevel::Less => "O1", | |
206 | config::OptLevel::Default => "O2", | |
207 | config::OptLevel::Aggressive => "O3", | |
208 | config::OptLevel::Size => "Os", | |
209 | config::OptLevel::SizeMin => "Oz", | |
210 | }; | |
211 | ||
212 | self.linker_arg(&format!("-plugin-opt={}", opt_level)); | |
a1dfa0c6 XL |
213 | let target_cpu = self.target_cpu; |
214 | self.linker_arg(&format!("-plugin-opt=mcpu={}", target_cpu)); | |
8faf50e0 | 215 | } |
62682a34 SL |
216 | } |
217 | ||
cc61c64b | 218 | impl<'a> Linker for GccLinker<'a> { |
e1599b0c XL |
219 | fn link_dylib(&mut self, lib: Symbol) { |
220 | self.hint_dynamic(); | |
221 | self.cmd.arg(format!("-l{}", lib)); | |
222 | } | |
223 | fn link_staticlib(&mut self, lib: Symbol) { | |
224 | self.hint_static(); | |
225 | self.cmd.arg(format!("-l{}", lib)); | |
8faf50e0 | 226 | } |
cc61c64b | 227 | fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); } |
62682a34 SL |
228 | fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } |
229 | fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); } | |
230 | fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); } | |
231 | fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } | |
232 | fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); } | |
0531ce1d | 233 | fn no_position_independent_executable(&mut self) { self.cmd.arg("-no-pie"); } |
8faf50e0 XL |
234 | fn full_relro(&mut self) { self.linker_arg("-zrelro"); self.linker_arg("-znow"); } |
235 | fn partial_relro(&mut self) { self.linker_arg("-zrelro"); } | |
236 | fn no_relro(&mut self) { self.linker_arg("-znorelro"); } | |
3b2f2976 | 237 | fn build_static_executable(&mut self) { self.cmd.arg("-static"); } |
62682a34 SL |
238 | fn args(&mut self, args: &[String]) { self.cmd.args(args); } |
239 | ||
e1599b0c | 240 | fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { |
cc61c64b | 241 | self.hint_dynamic(); |
a1dfa0c6 | 242 | self.cmd.arg(format!("-l{}", lib)); |
c1a9b12d SL |
243 | } |
244 | ||
e1599b0c | 245 | fn link_framework(&mut self, framework: Symbol) { |
cc61c64b | 246 | self.hint_dynamic(); |
e1599b0c | 247 | self.cmd.arg("-framework").sym_arg(framework); |
62682a34 SL |
248 | } |
249 | ||
cc61c64b XL |
250 | // Here we explicitly ask that the entire archive is included into the |
251 | // result artifact. For more details see #15460, but the gist is that | |
252 | // the linker will strip away any unused objects in the archive if we | |
253 | // don't otherwise explicitly reference them. This can occur for | |
254 | // libraries which are just providing bindings, libraries with generic | |
255 | // functions, etc. | |
e1599b0c | 256 | fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) { |
cc61c64b | 257 | self.hint_static(); |
62682a34 SL |
258 | let target = &self.sess.target.target; |
259 | if !target.options.is_like_osx { | |
a1dfa0c6 | 260 | self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib)); |
cc61c64b | 261 | self.linker_arg("--no-whole-archive"); |
62682a34 | 262 | } else { |
cc61c64b | 263 | // -force_load is the macOS equivalent of --whole-archive, but it |
62682a34 | 264 | // involves passing the full path to the library to link. |
8faf50e0 XL |
265 | self.linker_arg("-force_load"); |
266 | let lib = archive::find_library(lib, search_path, &self.sess); | |
267 | self.linker_arg(&lib); | |
c1a9b12d SL |
268 | } |
269 | } | |
270 | ||
271 | fn link_whole_rlib(&mut self, lib: &Path) { | |
cc61c64b | 272 | self.hint_static(); |
c1a9b12d | 273 | if self.sess.target.target.options.is_like_osx { |
8faf50e0 XL |
274 | self.linker_arg("-force_load"); |
275 | self.linker_arg(&lib); | |
c1a9b12d | 276 | } else { |
cc61c64b XL |
277 | self.linker_arg("--whole-archive").cmd.arg(lib); |
278 | self.linker_arg("--no-whole-archive"); | |
62682a34 SL |
279 | } |
280 | } | |
281 | ||
a7813a04 | 282 | fn gc_sections(&mut self, keep_metadata: bool) { |
62682a34 SL |
283 | // The dead_strip option to the linker specifies that functions and data |
284 | // unreachable by the entry point will be removed. This is quite useful | |
285 | // with Rust's compilation model of compiling libraries at a time into | |
286 | // one object file. For example, this brings hello world from 1.7MB to | |
287 | // 458K. | |
288 | // | |
289 | // Note that this is done for both executables and dynamic libraries. We | |
290 | // won't get much benefit from dylibs because LLVM will have already | |
291 | // stripped away as much as it could. This has not been seen to impact | |
292 | // link times negatively. | |
293 | // | |
294 | // -dead_strip can't be part of the pre_link_args because it's also used | |
295 | // for partial linking when using multiple codegen units (-r). So we | |
296 | // insert it here. | |
297 | if self.sess.target.target.options.is_like_osx { | |
cc61c64b | 298 | self.linker_arg("-dead_strip"); |
7453a54e | 299 | } else if self.sess.target.target.options.is_like_solaris { |
8faf50e0 | 300 | self.linker_arg("-zignore"); |
62682a34 SL |
301 | |
302 | // If we're building a dylib, we don't use --gc-sections because LLVM | |
303 | // has already done the best it can do, and we also don't want to | |
304 | // eliminate the metadata. If we're building an executable, however, | |
305 | // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% | |
306 | // reduction. | |
a7813a04 | 307 | } else if !keep_metadata { |
cc61c64b | 308 | self.linker_arg("--gc-sections"); |
62682a34 SL |
309 | } |
310 | } | |
311 | ||
312 | fn optimize(&mut self) { | |
313 | if !self.sess.target.target.options.linker_is_gnu { return } | |
314 | ||
315 | // GNU-style linkers support optimization with -O. GNU ld doesn't | |
316 | // need a numeric argument, but other linkers do. | |
9cc50fc6 SL |
317 | if self.sess.opts.optimize == config::OptLevel::Default || |
318 | self.sess.opts.optimize == config::OptLevel::Aggressive { | |
cc61c64b | 319 | self.linker_arg("-O1"); |
62682a34 SL |
320 | } |
321 | } | |
322 | ||
0531ce1d XL |
323 | fn pgo_gen(&mut self) { |
324 | if !self.sess.target.target.options.linker_is_gnu { return } | |
325 | ||
326 | // If we're doing PGO generation stuff and on a GNU-like linker, use the | |
327 | // "-u" flag to properly pull in the profiler runtime bits. | |
328 | // | |
329 | // This is because LLVM otherwise won't add the needed initialization | |
330 | // for us on Linux (though the extra flag should be harmless if it | |
331 | // does). | |
332 | // | |
333 | // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030. | |
334 | // | |
335 | // Though it may be worth to try to revert those changes upstream, since | |
336 | // the overhead of the initialization should be minor. | |
337 | self.cmd.arg("-u"); | |
338 | self.cmd.arg("__llvm_profile_runtime"); | |
339 | } | |
340 | ||
c1a9b12d | 341 | fn debuginfo(&mut self) { |
a1dfa0c6 XL |
342 | if let DebugInfo::None = self.sess.opts.debuginfo { |
343 | // If we are building without debuginfo enabled and we were called with | |
344 | // `-Zstrip-debuginfo-if-disabled=yes`, tell the linker to strip any debuginfo | |
345 | // found when linking to get rid of symbols from libstd. | |
346 | if let Some(true) = self.sess.opts.debugging_opts.strip_debuginfo_if_disabled { | |
347 | self.linker_arg("-S"); | |
348 | } | |
0531ce1d | 349 | }; |
c1a9b12d SL |
350 | } |
351 | ||
62682a34 | 352 | fn no_default_libraries(&mut self) { |
cc61c64b XL |
353 | if !self.is_ld { |
354 | self.cmd.arg("-nodefaultlibs"); | |
355 | } | |
62682a34 SL |
356 | } |
357 | ||
358 | fn build_dylib(&mut self, out_filename: &Path) { | |
359 | // On mac we need to tell the linker to let this library be rpathed | |
360 | if self.sess.target.target.options.is_like_osx { | |
cc61c64b XL |
361 | self.cmd.arg("-dynamiclib"); |
362 | self.linker_arg("-dylib"); | |
62682a34 | 363 | |
476ff2be SL |
364 | // Note that the `osx_rpath_install_name` option here is a hack |
365 | // purely to support rustbuild right now, we should get a more | |
366 | // principled solution at some point to force the compiler to pass | |
367 | // the right `-Wl,-install_name` with an `@rpath` in it. | |
a1dfa0c6 | 368 | if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { |
8faf50e0 XL |
369 | self.linker_arg("-install_name"); |
370 | let mut v = OsString::from("@rpath/"); | |
62682a34 | 371 | v.push(out_filename.file_name().unwrap()); |
cc61c64b | 372 | self.linker_arg(&v); |
62682a34 SL |
373 | } |
374 | } else { | |
375 | self.cmd.arg("-shared"); | |
416331ca XL |
376 | if self.sess.target.target.options.is_like_windows { |
377 | // The output filename already contains `dll_suffix` so | |
378 | // the resulting import library will have a name in the | |
379 | // form of libfoo.dll.a | |
380 | let implib_name = out_filename | |
381 | .file_name() | |
382 | .and_then(|file| file.to_str()) | |
383 | .map(|file| format!("{}{}{}", | |
384 | self.sess.target.target.options.staticlib_prefix, | |
385 | file, | |
386 | self.sess.target.target.options.staticlib_suffix)); | |
387 | if let Some(implib_name) = implib_name { | |
388 | let implib = out_filename | |
389 | .parent() | |
390 | .map(|dir| dir.join(&implib_name)); | |
391 | if let Some(implib) = implib { | |
392 | self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap())); | |
393 | } | |
394 | } | |
395 | } | |
62682a34 SL |
396 | } |
397 | } | |
398 | ||
3157f602 | 399 | fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { |
48663c56 | 400 | // Symbol visibility in object files typically takes care of this. |
60c5eb7d XL |
401 | if crate_type == CrateType::Executable && |
402 | self.sess.target.target.options.override_export_symbols.is_none() { | |
48663c56 XL |
403 | return; |
404 | } | |
405 | ||
dc9dc135 XL |
406 | // We manually create a list of exported symbols to ensure we don't expose any more. |
407 | // The object files have far more public symbols than we actually want to export, | |
408 | // so we hide them all here. | |
a7813a04 | 409 | |
dc9dc135 | 410 | if !self.sess.target.target.options.limit_rdylib_exports { |
532ac7d7 XL |
411 | return; |
412 | } | |
413 | ||
dc9dc135 XL |
414 | if crate_type == CrateType::ProcMacro { |
415 | return | |
416 | } | |
417 | ||
9e0c209e | 418 | let mut arg = OsString::new(); |
a7813a04 | 419 | let path = tmpdir.join("list"); |
9e0c209e | 420 | |
476ff2be SL |
421 | debug!("EXPORTED SYMBOLS:"); |
422 | ||
423 | if self.sess.target.target.options.is_like_osx { | |
424 | // Write a plain, newline-separated list of symbols | |
532ac7d7 | 425 | let res: io::Result<()> = try { |
9e0c209e | 426 | let mut f = BufWriter::new(File::create(&path)?); |
9e0c209e | 427 | for sym in self.info.exports[&crate_type].iter() { |
476ff2be SL |
428 | debug!(" _{}", sym); |
429 | writeln!(f, "_{}", sym)?; | |
9e0c209e | 430 | } |
532ac7d7 | 431 | }; |
9e0c209e | 432 | if let Err(e) = res { |
476ff2be | 433 | self.sess.fatal(&format!("failed to write lib.def file: {}", e)); |
a7813a04 | 434 | } |
a7813a04 | 435 | } else { |
476ff2be | 436 | // Write an LD version script |
532ac7d7 | 437 | let res: io::Result<()> = try { |
9e0c209e | 438 | let mut f = BufWriter::new(File::create(&path)?); |
e1599b0c XL |
439 | writeln!(f, "{{")?; |
440 | if !self.info.exports[&crate_type].is_empty() { | |
441 | writeln!(f, " global:")?; | |
442 | for sym in self.info.exports[&crate_type].iter() { | |
443 | debug!(" {};", sym); | |
444 | writeln!(f, " {};", sym)?; | |
445 | } | |
9e0c209e | 446 | } |
476ff2be | 447 | writeln!(f, "\n local:\n *;\n}};")?; |
532ac7d7 | 448 | }; |
9e0c209e | 449 | if let Err(e) = res { |
476ff2be | 450 | self.sess.fatal(&format!("failed to write version script: {}", e)); |
9e0c209e | 451 | } |
a7813a04 | 452 | } |
9e0c209e | 453 | |
476ff2be | 454 | if self.sess.target.target.options.is_like_osx { |
cc61c64b XL |
455 | if !self.is_ld { |
456 | arg.push("-Wl,") | |
457 | } | |
458 | arg.push("-exported_symbols_list,"); | |
476ff2be | 459 | } else if self.sess.target.target.options.is_like_solaris { |
cc61c64b XL |
460 | if !self.is_ld { |
461 | arg.push("-Wl,") | |
462 | } | |
463 | arg.push("-M,"); | |
476ff2be | 464 | } else { |
cc61c64b XL |
465 | if !self.is_ld { |
466 | arg.push("-Wl,") | |
467 | } | |
468 | arg.push("--version-script="); | |
476ff2be SL |
469 | } |
470 | ||
471 | arg.push(&path); | |
a7813a04 | 472 | self.cmd.arg(arg); |
e9174d1e | 473 | } |
c30ab7b3 SL |
474 | |
475 | fn subsystem(&mut self, subsystem: &str) { | |
8faf50e0 XL |
476 | self.linker_arg("--subsystem"); |
477 | self.linker_arg(&subsystem); | |
cc61c64b XL |
478 | } |
479 | ||
480 | fn finalize(&mut self) -> Command { | |
481 | self.hint_dynamic(); // Reset to default before returning the composed command line. | |
a1dfa0c6 XL |
482 | |
483 | ::std::mem::replace(&mut self.cmd, Command::new("")) | |
c30ab7b3 | 484 | } |
0531ce1d XL |
485 | |
486 | fn group_start(&mut self) { | |
532ac7d7 | 487 | if self.takes_hints() { |
0531ce1d XL |
488 | self.linker_arg("--start-group"); |
489 | } | |
490 | } | |
491 | ||
492 | fn group_end(&mut self) { | |
532ac7d7 | 493 | if self.takes_hints() { |
0531ce1d XL |
494 | self.linker_arg("--end-group"); |
495 | } | |
496 | } | |
94b46f34 | 497 | |
9fa01778 XL |
498 | fn linker_plugin_lto(&mut self) { |
499 | match self.sess.opts.cg.linker_plugin_lto { | |
500 | LinkerPluginLto::Disabled => { | |
94b46f34 XL |
501 | // Nothing to do |
502 | } | |
9fa01778 XL |
503 | LinkerPluginLto::LinkerPluginAuto => { |
504 | self.push_linker_plugin_lto_args(None); | |
8faf50e0 | 505 | } |
9fa01778 XL |
506 | LinkerPluginLto::LinkerPlugin(ref path) => { |
507 | self.push_linker_plugin_lto_args(Some(path.as_os_str())); | |
94b46f34 XL |
508 | } |
509 | } | |
510 | } | |
62682a34 SL |
511 | } |
512 | ||
513 | pub struct MsvcLinker<'a> { | |
cc61c64b | 514 | cmd: Command, |
3157f602 XL |
515 | sess: &'a Session, |
516 | info: &'a LinkerInfo | |
62682a34 SL |
517 | } |
518 | ||
519 | impl<'a> Linker for MsvcLinker<'a> { | |
520 | fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); } | |
521 | fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } | |
522 | fn args(&mut self, args: &[String]) { self.cmd.args(args); } | |
7453a54e SL |
523 | |
524 | fn build_dylib(&mut self, out_filename: &Path) { | |
525 | self.cmd.arg("/DLL"); | |
526 | let mut arg: OsString = "/IMPLIB:".into(); | |
527 | arg.push(out_filename.with_extension("dll.lib")); | |
528 | self.cmd.arg(arg); | |
529 | } | |
530 | ||
3b2f2976 XL |
531 | fn build_static_executable(&mut self) { |
532 | // noop | |
533 | } | |
534 | ||
a7813a04 | 535 | fn gc_sections(&mut self, _keep_metadata: bool) { |
476ff2be SL |
536 | // MSVC's ICF (Identical COMDAT Folding) link optimization is |
537 | // slow for Rust and thus we disable it by default when not in | |
538 | // optimization build. | |
539 | if self.sess.opts.optimize != config::OptLevel::No { | |
540 | self.cmd.arg("/OPT:REF,ICF"); | |
541 | } else { | |
542 | // It is necessary to specify NOICF here, because /OPT:REF | |
543 | // implies ICF by default. | |
544 | self.cmd.arg("/OPT:REF,NOICF"); | |
545 | } | |
a7813a04 | 546 | } |
62682a34 | 547 | |
e1599b0c | 548 | fn link_dylib(&mut self, lib: Symbol) { |
62682a34 SL |
549 | self.cmd.arg(&format!("{}.lib", lib)); |
550 | } | |
c1a9b12d | 551 | |
e1599b0c | 552 | fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) { |
c1a9b12d SL |
553 | // When producing a dll, the MSVC linker may not actually emit a |
554 | // `foo.lib` file if the dll doesn't actually export any symbols, so we | |
555 | // check to see if the file is there and just omit linking to it if it's | |
556 | // not present. | |
7453a54e | 557 | let name = format!("{}.dll.lib", lib); |
c1a9b12d SL |
558 | if fs::metadata(&path.join(&name)).is_ok() { |
559 | self.cmd.arg(name); | |
560 | } | |
561 | } | |
562 | ||
e1599b0c | 563 | fn link_staticlib(&mut self, lib: Symbol) { |
62682a34 SL |
564 | self.cmd.arg(&format!("{}.lib", lib)); |
565 | } | |
566 | ||
567 | fn position_independent_executable(&mut self) { | |
568 | // noop | |
569 | } | |
570 | ||
0531ce1d | 571 | fn no_position_independent_executable(&mut self) { |
3b2f2976 XL |
572 | // noop |
573 | } | |
574 | ||
575 | fn full_relro(&mut self) { | |
576 | // noop | |
577 | } | |
578 | ||
0531ce1d XL |
579 | fn partial_relro(&mut self) { |
580 | // noop | |
581 | } | |
582 | ||
583 | fn no_relro(&mut self) { | |
584 | // noop | |
585 | } | |
586 | ||
62682a34 SL |
587 | fn no_default_libraries(&mut self) { |
588 | // Currently we don't pass the /NODEFAULTLIB flag to the linker on MSVC | |
589 | // as there's been trouble in the past of linking the C++ standard | |
590 | // library required by LLVM. This likely needs to happen one day, but | |
591 | // in general Windows is also a more controlled environment than | |
592 | // Unix, so it's not necessarily as critical that this be implemented. | |
593 | // | |
594 | // Note that there are also some licensing worries about statically | |
595 | // linking some libraries which require a specific agreement, so it may | |
596 | // not ever be possible for us to pass this flag. | |
597 | } | |
598 | ||
599 | fn include_path(&mut self, path: &Path) { | |
600 | let mut arg = OsString::from("/LIBPATH:"); | |
601 | arg.push(path); | |
602 | self.cmd.arg(&arg); | |
603 | } | |
604 | ||
605 | fn output_filename(&mut self, path: &Path) { | |
606 | let mut arg = OsString::from("/OUT:"); | |
607 | arg.push(path); | |
608 | self.cmd.arg(&arg); | |
609 | } | |
610 | ||
611 | fn framework_path(&mut self, _path: &Path) { | |
54a0048b | 612 | bug!("frameworks are not supported on windows") |
62682a34 | 613 | } |
e1599b0c | 614 | fn link_framework(&mut self, _framework: Symbol) { |
54a0048b | 615 | bug!("frameworks are not supported on windows") |
62682a34 SL |
616 | } |
617 | ||
e1599b0c | 618 | fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) { |
62682a34 SL |
619 | // not supported? |
620 | self.link_staticlib(lib); | |
621 | } | |
c1a9b12d SL |
622 | fn link_whole_rlib(&mut self, path: &Path) { |
623 | // not supported? | |
624 | self.link_rlib(path); | |
625 | } | |
62682a34 SL |
626 | fn optimize(&mut self) { |
627 | // Needs more investigation of `/OPT` arguments | |
628 | } | |
c1a9b12d | 629 | |
0531ce1d XL |
630 | fn pgo_gen(&mut self) { |
631 | // Nothing needed here. | |
632 | } | |
633 | ||
c1a9b12d | 634 | fn debuginfo(&mut self) { |
b039eaaf SL |
635 | // This will cause the Microsoft linker to generate a PDB file |
636 | // from the CodeView line tables in the object files. | |
637 | self.cmd.arg("/DEBUG"); | |
3b2f2976 | 638 | |
a1dfa0c6 | 639 | // This will cause the Microsoft linker to embed .natvis info into the PDB file |
0731742a | 640 | let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc"); |
3b2f2976 XL |
641 | if let Ok(natvis_dir) = fs::read_dir(&natvis_dir_path) { |
642 | for entry in natvis_dir { | |
643 | match entry { | |
644 | Ok(entry) => { | |
645 | let path = entry.path(); | |
646 | if path.extension() == Some("natvis".as_ref()) { | |
647 | let mut arg = OsString::from("/NATVIS:"); | |
648 | arg.push(path); | |
649 | self.cmd.arg(arg); | |
650 | } | |
651 | }, | |
652 | Err(err) => { | |
653 | self.sess.warn(&format!("error enumerating natvis directory: {}", err)); | |
654 | }, | |
655 | } | |
656 | } | |
657 | } | |
c1a9b12d SL |
658 | } |
659 | ||
e9174d1e SL |
660 | // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to |
661 | // export symbols from a dynamic library. When building a dynamic library, | |
662 | // however, we're going to want some symbols exported, so this function | |
663 | // generates a DEF file which lists all the symbols. | |
664 | // | |
665 | // The linker will read this `*.def` file and export all the symbols from | |
666 | // the dynamic library. Note that this is not as simple as just exporting | |
94b46f34 | 667 | // all the symbols in the current crate (as specified by `codegen.reachable`) |
e9174d1e SL |
668 | // but rather we also need to possibly export the symbols of upstream |
669 | // crates. Upstream rlibs may be linked statically to this dynamic library, | |
670 | // in which case they may continue to transitively be used and hence need | |
671 | // their symbols exported. | |
a7813a04 | 672 | fn export_symbols(&mut self, |
a7813a04 XL |
673 | tmpdir: &Path, |
674 | crate_type: CrateType) { | |
48663c56 XL |
675 | // Symbol visibility takes care of this typically |
676 | if crate_type == CrateType::Executable { | |
677 | return; | |
678 | } | |
679 | ||
e9174d1e | 680 | let path = tmpdir.join("lib.def"); |
532ac7d7 | 681 | let res: io::Result<()> = try { |
54a0048b | 682 | let mut f = BufWriter::new(File::create(&path)?); |
e9174d1e SL |
683 | |
684 | // Start off with the standard module name header and then go | |
685 | // straight to exports. | |
54a0048b SL |
686 | writeln!(f, "LIBRARY")?; |
687 | writeln!(f, "EXPORTS")?; | |
9e0c209e | 688 | for symbol in self.info.exports[&crate_type].iter() { |
8bb4bdeb | 689 | debug!(" _{}", symbol); |
3157f602 | 690 | writeln!(f, " {}", symbol)?; |
e9174d1e | 691 | } |
532ac7d7 | 692 | }; |
e9174d1e | 693 | if let Err(e) = res { |
3157f602 | 694 | self.sess.fatal(&format!("failed to write lib.def file: {}", e)); |
e9174d1e SL |
695 | } |
696 | let mut arg = OsString::from("/DEF:"); | |
697 | arg.push(path); | |
698 | self.cmd.arg(&arg); | |
699 | } | |
c30ab7b3 SL |
700 | |
701 | fn subsystem(&mut self, subsystem: &str) { | |
702 | // Note that previous passes of the compiler validated this subsystem, | |
703 | // so we just blindly pass it to the linker. | |
704 | self.cmd.arg(&format!("/SUBSYSTEM:{}", subsystem)); | |
705 | ||
706 | // Windows has two subsystems we're interested in right now, the console | |
707 | // and windows subsystems. These both implicitly have different entry | |
708 | // points (starting symbols). The console entry point starts with | |
709 | // `mainCRTStartup` and the windows entry point starts with | |
710 | // `WinMainCRTStartup`. These entry points, defined in system libraries, | |
711 | // will then later probe for either `main` or `WinMain`, respectively to | |
712 | // start the application. | |
713 | // | |
714 | // In Rust we just always generate a `main` function so we want control | |
715 | // to always start there, so we force the entry point on the windows | |
716 | // subsystem to be `mainCRTStartup` to get everything booted up | |
717 | // correctly. | |
718 | // | |
719 | // For more information see RFC #1665 | |
720 | if subsystem == "windows" { | |
721 | self.cmd.arg("/ENTRY:mainCRTStartup"); | |
722 | } | |
723 | } | |
cc61c64b XL |
724 | |
725 | fn finalize(&mut self) -> Command { | |
a1dfa0c6 | 726 | ::std::mem::replace(&mut self.cmd, Command::new("")) |
cc61c64b | 727 | } |
0531ce1d XL |
728 | |
729 | // MSVC doesn't need group indicators | |
730 | fn group_start(&mut self) {} | |
731 | fn group_end(&mut self) {} | |
94b46f34 | 732 | |
9fa01778 | 733 | fn linker_plugin_lto(&mut self) { |
94b46f34 XL |
734 | // Do nothing |
735 | } | |
62682a34 | 736 | } |
a7813a04 | 737 | |
8bb4bdeb | 738 | pub struct EmLinker<'a> { |
cc61c64b | 739 | cmd: Command, |
8bb4bdeb XL |
740 | sess: &'a Session, |
741 | info: &'a LinkerInfo | |
742 | } | |
743 | ||
744 | impl<'a> Linker for EmLinker<'a> { | |
745 | fn include_path(&mut self, path: &Path) { | |
746 | self.cmd.arg("-L").arg(path); | |
747 | } | |
748 | ||
e1599b0c XL |
749 | fn link_staticlib(&mut self, lib: Symbol) { |
750 | self.cmd.arg("-l").sym_arg(lib); | |
8bb4bdeb XL |
751 | } |
752 | ||
753 | fn output_filename(&mut self, path: &Path) { | |
754 | self.cmd.arg("-o").arg(path); | |
755 | } | |
756 | ||
757 | fn add_object(&mut self, path: &Path) { | |
758 | self.cmd.arg(path); | |
759 | } | |
760 | ||
e1599b0c | 761 | fn link_dylib(&mut self, lib: Symbol) { |
8bb4bdeb XL |
762 | // Emscripten always links statically |
763 | self.link_staticlib(lib); | |
764 | } | |
765 | ||
e1599b0c | 766 | fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) { |
8bb4bdeb XL |
767 | // not supported? |
768 | self.link_staticlib(lib); | |
769 | } | |
770 | ||
771 | fn link_whole_rlib(&mut self, lib: &Path) { | |
772 | // not supported? | |
773 | self.link_rlib(lib); | |
774 | } | |
775 | ||
e1599b0c | 776 | fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { |
8bb4bdeb XL |
777 | self.link_dylib(lib); |
778 | } | |
779 | ||
780 | fn link_rlib(&mut self, lib: &Path) { | |
781 | self.add_object(lib); | |
782 | } | |
783 | ||
784 | fn position_independent_executable(&mut self) { | |
785 | // noop | |
786 | } | |
787 | ||
0531ce1d | 788 | fn no_position_independent_executable(&mut self) { |
3b2f2976 XL |
789 | // noop |
790 | } | |
791 | ||
792 | fn full_relro(&mut self) { | |
793 | // noop | |
794 | } | |
795 | ||
0531ce1d XL |
796 | fn partial_relro(&mut self) { |
797 | // noop | |
798 | } | |
799 | ||
800 | fn no_relro(&mut self) { | |
801 | // noop | |
802 | } | |
803 | ||
8bb4bdeb XL |
804 | fn args(&mut self, args: &[String]) { |
805 | self.cmd.args(args); | |
806 | } | |
807 | ||
808 | fn framework_path(&mut self, _path: &Path) { | |
809 | bug!("frameworks are not supported on Emscripten") | |
810 | } | |
811 | ||
e1599b0c | 812 | fn link_framework(&mut self, _framework: Symbol) { |
8bb4bdeb XL |
813 | bug!("frameworks are not supported on Emscripten") |
814 | } | |
815 | ||
816 | fn gc_sections(&mut self, _keep_metadata: bool) { | |
817 | // noop | |
818 | } | |
819 | ||
820 | fn optimize(&mut self) { | |
821 | // Emscripten performs own optimizations | |
822 | self.cmd.arg(match self.sess.opts.optimize { | |
823 | OptLevel::No => "-O0", | |
824 | OptLevel::Less => "-O1", | |
825 | OptLevel::Default => "-O2", | |
826 | OptLevel::Aggressive => "-O3", | |
827 | OptLevel::Size => "-Os", | |
828 | OptLevel::SizeMin => "-Oz" | |
829 | }); | |
830 | // Unusable until https://github.com/rust-lang/rust/issues/38454 is resolved | |
831 | self.cmd.args(&["--memory-init-file", "0"]); | |
832 | } | |
833 | ||
0531ce1d XL |
834 | fn pgo_gen(&mut self) { |
835 | // noop, but maybe we need something like the gnu linker? | |
836 | } | |
837 | ||
8bb4bdeb XL |
838 | fn debuginfo(&mut self) { |
839 | // Preserve names or generate source maps depending on debug info | |
840 | self.cmd.arg(match self.sess.opts.debuginfo { | |
b7449926 XL |
841 | DebugInfo::None => "-g0", |
842 | DebugInfo::Limited => "-g3", | |
843 | DebugInfo::Full => "-g4" | |
8bb4bdeb XL |
844 | }); |
845 | } | |
846 | ||
847 | fn no_default_libraries(&mut self) { | |
848 | self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]); | |
849 | } | |
850 | ||
851 | fn build_dylib(&mut self, _out_filename: &Path) { | |
852 | bug!("building dynamic library is unsupported on Emscripten") | |
853 | } | |
854 | ||
3b2f2976 XL |
855 | fn build_static_executable(&mut self) { |
856 | // noop | |
857 | } | |
858 | ||
8bb4bdeb XL |
859 | fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { |
860 | let symbols = &self.info.exports[&crate_type]; | |
861 | ||
862 | debug!("EXPORTED SYMBOLS:"); | |
863 | ||
864 | self.cmd.arg("-s"); | |
865 | ||
866 | let mut arg = OsString::from("EXPORTED_FUNCTIONS="); | |
867 | let mut encoded = String::new(); | |
868 | ||
869 | { | |
870 | let mut encoder = json::Encoder::new(&mut encoded); | |
871 | let res = encoder.emit_seq(symbols.len(), |encoder| { | |
872 | for (i, sym) in symbols.iter().enumerate() { | |
873 | encoder.emit_seq_elt(i, |encoder| { | |
a1dfa0c6 | 874 | encoder.emit_str(&("_".to_owned() + sym)) |
8bb4bdeb XL |
875 | })?; |
876 | } | |
877 | Ok(()) | |
878 | }); | |
879 | if let Err(e) = res { | |
880 | self.sess.fatal(&format!("failed to encode exported symbols: {}", e)); | |
881 | } | |
882 | } | |
883 | debug!("{}", encoded); | |
884 | arg.push(encoded); | |
885 | ||
886 | self.cmd.arg(arg); | |
887 | } | |
888 | ||
889 | fn subsystem(&mut self, _subsystem: &str) { | |
890 | // noop | |
891 | } | |
cc61c64b XL |
892 | |
893 | fn finalize(&mut self) -> Command { | |
a1dfa0c6 | 894 | ::std::mem::replace(&mut self.cmd, Command::new("")) |
cc61c64b | 895 | } |
0531ce1d XL |
896 | |
897 | // Appears not necessary on Emscripten | |
898 | fn group_start(&mut self) {} | |
899 | fn group_end(&mut self) {} | |
94b46f34 | 900 | |
9fa01778 | 901 | fn linker_plugin_lto(&mut self) { |
94b46f34 XL |
902 | // Do nothing |
903 | } | |
8bb4bdeb XL |
904 | } |
905 | ||
8faf50e0 | 906 | pub struct WasmLd<'a> { |
0531ce1d | 907 | cmd: Command, |
8faf50e0 | 908 | sess: &'a Session, |
0bf4aa26 | 909 | info: &'a LinkerInfo, |
0531ce1d XL |
910 | } |
911 | ||
0731742a | 912 | impl<'a> WasmLd<'a> { |
416331ca XL |
913 | fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> { |
914 | // If the atomics feature is enabled for wasm then we need a whole bunch | |
915 | // of flags: | |
916 | // | |
917 | // * `--shared-memory` - the link won't even succeed without this, flags | |
918 | // the one linear memory as `shared` | |
919 | // | |
920 | // * `--max-memory=1G` - when specifying a shared memory this must also | |
921 | // be specified. We conservatively choose 1GB but users should be able | |
922 | // to override this with `-C link-arg`. | |
923 | // | |
924 | // * `--import-memory` - it doesn't make much sense for memory to be | |
925 | // exported in a threaded module because typically you're | |
926 | // sharing memory and instantiating the module multiple times. As a | |
927 | // result if it were exported then we'd just have no sharing. | |
928 | // | |
929 | // * `--passive-segments` - all memory segments should be passive to | |
930 | // prevent each module instantiation from reinitializing memory. | |
931 | // | |
932 | // * `--export=__wasm_init_memory` - when using `--passive-segments` the | |
933 | // linker will synthesize this function, and so we need to make sure | |
934 | // that our usage of `--export` below won't accidentally cause this | |
935 | // function to get deleted. | |
936 | // | |
937 | // * `--export=*tls*` - when `#[thread_local]` symbols are used these | |
938 | // symbols are how the TLS segments are initialized and configured. | |
939 | let atomics = sess.opts.cg.target_feature.contains("+atomics") || | |
940 | sess.target.target.options.features.contains("+atomics"); | |
941 | if atomics { | |
942 | cmd.arg("--shared-memory"); | |
943 | cmd.arg("--max-memory=1073741824"); | |
944 | cmd.arg("--import-memory"); | |
945 | cmd.arg("--passive-segments"); | |
946 | cmd.arg("--export=__wasm_init_memory"); | |
947 | cmd.arg("--export=__wasm_init_tls"); | |
948 | cmd.arg("--export=__tls_size"); | |
949 | cmd.arg("--export=__tls_align"); | |
950 | cmd.arg("--export=__tls_base"); | |
951 | } | |
0731742a XL |
952 | WasmLd { cmd, sess, info } |
953 | } | |
954 | } | |
955 | ||
8faf50e0 | 956 | impl<'a> Linker for WasmLd<'a> { |
e1599b0c XL |
957 | fn link_dylib(&mut self, lib: Symbol) { |
958 | self.cmd.arg("-l").sym_arg(lib); | |
0531ce1d XL |
959 | } |
960 | ||
e1599b0c XL |
961 | fn link_staticlib(&mut self, lib: Symbol) { |
962 | self.cmd.arg("-l").sym_arg(lib); | |
0531ce1d XL |
963 | } |
964 | ||
965 | fn link_rlib(&mut self, lib: &Path) { | |
966 | self.cmd.arg(lib); | |
967 | } | |
968 | ||
969 | fn include_path(&mut self, path: &Path) { | |
970 | self.cmd.arg("-L").arg(path); | |
971 | } | |
972 | ||
973 | fn framework_path(&mut self, _path: &Path) { | |
974 | panic!("frameworks not supported") | |
975 | } | |
976 | ||
977 | fn output_filename(&mut self, path: &Path) { | |
978 | self.cmd.arg("-o").arg(path); | |
979 | } | |
980 | ||
981 | fn add_object(&mut self, path: &Path) { | |
982 | self.cmd.arg(path); | |
983 | } | |
984 | ||
985 | fn position_independent_executable(&mut self) { | |
986 | } | |
987 | ||
988 | fn full_relro(&mut self) { | |
989 | } | |
990 | ||
991 | fn partial_relro(&mut self) { | |
992 | } | |
993 | ||
994 | fn no_relro(&mut self) { | |
995 | } | |
996 | ||
997 | fn build_static_executable(&mut self) { | |
998 | } | |
999 | ||
1000 | fn args(&mut self, args: &[String]) { | |
1001 | self.cmd.args(args); | |
1002 | } | |
1003 | ||
e1599b0c XL |
1004 | fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { |
1005 | self.cmd.arg("-l").sym_arg(lib); | |
0531ce1d XL |
1006 | } |
1007 | ||
e1599b0c | 1008 | fn link_framework(&mut self, _framework: Symbol) { |
0531ce1d XL |
1009 | panic!("frameworks not supported") |
1010 | } | |
1011 | ||
e1599b0c XL |
1012 | fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) { |
1013 | self.cmd.arg("-l").sym_arg(lib); | |
0531ce1d XL |
1014 | } |
1015 | ||
1016 | fn link_whole_rlib(&mut self, lib: &Path) { | |
1017 | self.cmd.arg(lib); | |
1018 | } | |
1019 | ||
1020 | fn gc_sections(&mut self, _keep_metadata: bool) { | |
8faf50e0 | 1021 | self.cmd.arg("--gc-sections"); |
0531ce1d XL |
1022 | } |
1023 | ||
1024 | fn optimize(&mut self) { | |
8faf50e0 XL |
1025 | self.cmd.arg(match self.sess.opts.optimize { |
1026 | OptLevel::No => "-O0", | |
1027 | OptLevel::Less => "-O1", | |
1028 | OptLevel::Default => "-O2", | |
1029 | OptLevel::Aggressive => "-O3", | |
1030 | // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2` | |
1031 | // instead. | |
1032 | OptLevel::Size => "-O2", | |
1033 | OptLevel::SizeMin => "-O2" | |
1034 | }); | |
0531ce1d XL |
1035 | } |
1036 | ||
1037 | fn pgo_gen(&mut self) { | |
1038 | } | |
1039 | ||
1040 | fn debuginfo(&mut self) { | |
1041 | } | |
1042 | ||
1043 | fn no_default_libraries(&mut self) { | |
1044 | } | |
1045 | ||
1046 | fn build_dylib(&mut self, _out_filename: &Path) { | |
532ac7d7 | 1047 | self.cmd.arg("--no-entry"); |
0531ce1d XL |
1048 | } |
1049 | ||
0bf4aa26 XL |
1050 | fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) { |
1051 | for sym in self.info.exports[&crate_type].iter() { | |
1052 | self.cmd.arg("--export").arg(&sym); | |
1053 | } | |
416331ca XL |
1054 | |
1055 | // LLD will hide these otherwise-internal symbols since our `--export` | |
1056 | // list above is a whitelist of what to export. Various bits and pieces | |
1057 | // of tooling use this, so be sure these symbols make their way out of | |
1058 | // the linker as well. | |
1059 | self.cmd.arg("--export=__heap_base"); | |
1060 | self.cmd.arg("--export=__data_end"); | |
0531ce1d XL |
1061 | } |
1062 | ||
1063 | fn subsystem(&mut self, _subsystem: &str) { | |
1064 | } | |
1065 | ||
1066 | fn no_position_independent_executable(&mut self) { | |
1067 | } | |
1068 | ||
1069 | fn finalize(&mut self) -> Command { | |
a1dfa0c6 | 1070 | ::std::mem::replace(&mut self.cmd, Command::new("")) |
0531ce1d XL |
1071 | } |
1072 | ||
1073 | // Not needed for now with LLD | |
1074 | fn group_start(&mut self) {} | |
1075 | fn group_end(&mut self) {} | |
94b46f34 | 1076 | |
9fa01778 | 1077 | fn linker_plugin_lto(&mut self) { |
94b46f34 XL |
1078 | // Do nothing for now |
1079 | } | |
0531ce1d | 1080 | } |
a1dfa0c6 | 1081 | |
dc9dc135 | 1082 | fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> { |
a1dfa0c6 XL |
1083 | if let Some(ref exports) = tcx.sess.target.target.options.override_export_symbols { |
1084 | return exports.clone() | |
1085 | } | |
1086 | ||
1087 | let mut symbols = Vec::new(); | |
1088 | ||
1089 | let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); | |
1090 | for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() { | |
1091 | if level.is_below_threshold(export_threshold) { | |
1092 | symbols.push(symbol.symbol_name(tcx).to_string()); | |
1093 | } | |
1094 | } | |
1095 | ||
e74abb32 XL |
1096 | let formats = tcx.dependency_formats(LOCAL_CRATE); |
1097 | let deps = formats.iter().filter_map(|(t, list)| { | |
1098 | if *t == crate_type { | |
1099 | Some(list) | |
1100 | } else { | |
1101 | None | |
1102 | } | |
1103 | }).next().unwrap(); | |
a1dfa0c6 | 1104 | |
e74abb32 | 1105 | for (index, dep_format) in deps.iter().enumerate() { |
a1dfa0c6 XL |
1106 | let cnum = CrateNum::new(index + 1); |
1107 | // For each dependency that we are linking to statically ... | |
1108 | if *dep_format == Linkage::Static { | |
1109 | // ... we add its symbol list to our export list. | |
1110 | for &(symbol, level) in tcx.exported_symbols(cnum).iter() { | |
e74abb32 XL |
1111 | if !level.is_below_threshold(export_threshold) { |
1112 | continue; | |
a1dfa0c6 | 1113 | } |
e74abb32 XL |
1114 | |
1115 | // FIXME rust-lang/rust#64319, rust-lang/rust#64872: | |
1116 | // We want to block export of generics from dylibs, | |
1117 | // but we must fix rust-lang/rust#65890 before we can | |
1118 | // do that robustly. | |
1119 | ||
1120 | symbols.push(symbol.symbol_name(tcx).to_string()); | |
a1dfa0c6 XL |
1121 | } |
1122 | } | |
1123 | } | |
1124 | ||
1125 | symbols | |
1126 | } | |
9fa01778 XL |
1127 | |
1128 | /// Much simplified and explicit CLI for the NVPTX linker. The linker operates | |
1129 | /// with bitcode and uses LLVM backend to generate a PTX assembly. | |
1130 | pub struct PtxLinker<'a> { | |
1131 | cmd: Command, | |
1132 | sess: &'a Session, | |
1133 | } | |
1134 | ||
1135 | impl<'a> Linker for PtxLinker<'a> { | |
1136 | fn link_rlib(&mut self, path: &Path) { | |
1137 | self.cmd.arg("--rlib").arg(path); | |
1138 | } | |
1139 | ||
1140 | fn link_whole_rlib(&mut self, path: &Path) { | |
1141 | self.cmd.arg("--rlib").arg(path); | |
1142 | } | |
1143 | ||
1144 | fn include_path(&mut self, path: &Path) { | |
1145 | self.cmd.arg("-L").arg(path); | |
1146 | } | |
1147 | ||
1148 | fn debuginfo(&mut self) { | |
1149 | self.cmd.arg("--debug"); | |
1150 | } | |
1151 | ||
1152 | fn add_object(&mut self, path: &Path) { | |
1153 | self.cmd.arg("--bitcode").arg(path); | |
1154 | } | |
1155 | ||
1156 | fn args(&mut self, args: &[String]) { | |
1157 | self.cmd.args(args); | |
1158 | } | |
1159 | ||
1160 | fn optimize(&mut self) { | |
1161 | match self.sess.lto() { | |
1162 | Lto::Thin | Lto::Fat | Lto::ThinLocal => { | |
1163 | self.cmd.arg("-Olto"); | |
1164 | }, | |
1165 | ||
1166 | Lto::No => { }, | |
1167 | }; | |
1168 | } | |
1169 | ||
1170 | fn output_filename(&mut self, path: &Path) { | |
1171 | self.cmd.arg("-o").arg(path); | |
1172 | } | |
1173 | ||
1174 | fn finalize(&mut self) -> Command { | |
1175 | // Provide the linker with fallback to internal `target-cpu`. | |
1176 | self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu { | |
1177 | Some(ref s) => s, | |
1178 | None => &self.sess.target.target.options.cpu | |
1179 | }); | |
1180 | ||
1181 | ::std::mem::replace(&mut self.cmd, Command::new("")) | |
1182 | } | |
1183 | ||
e1599b0c | 1184 | fn link_dylib(&mut self, _lib: Symbol) { |
9fa01778 XL |
1185 | panic!("external dylibs not supported") |
1186 | } | |
1187 | ||
e1599b0c | 1188 | fn link_rust_dylib(&mut self, _lib: Symbol, _path: &Path) { |
9fa01778 XL |
1189 | panic!("external dylibs not supported") |
1190 | } | |
1191 | ||
e1599b0c | 1192 | fn link_staticlib(&mut self, _lib: Symbol) { |
9fa01778 XL |
1193 | panic!("staticlibs not supported") |
1194 | } | |
1195 | ||
e1599b0c | 1196 | fn link_whole_staticlib(&mut self, _lib: Symbol, _search_path: &[PathBuf]) { |
9fa01778 XL |
1197 | panic!("staticlibs not supported") |
1198 | } | |
1199 | ||
1200 | fn framework_path(&mut self, _path: &Path) { | |
1201 | panic!("frameworks not supported") | |
1202 | } | |
1203 | ||
e1599b0c | 1204 | fn link_framework(&mut self, _framework: Symbol) { |
9fa01778 XL |
1205 | panic!("frameworks not supported") |
1206 | } | |
1207 | ||
1208 | fn position_independent_executable(&mut self) { | |
1209 | } | |
1210 | ||
1211 | fn full_relro(&mut self) { | |
1212 | } | |
1213 | ||
1214 | fn partial_relro(&mut self) { | |
1215 | } | |
1216 | ||
1217 | fn no_relro(&mut self) { | |
1218 | } | |
1219 | ||
1220 | fn build_static_executable(&mut self) { | |
1221 | } | |
1222 | ||
1223 | fn gc_sections(&mut self, _keep_metadata: bool) { | |
1224 | } | |
1225 | ||
1226 | fn pgo_gen(&mut self) { | |
1227 | } | |
1228 | ||
1229 | fn no_default_libraries(&mut self) { | |
1230 | } | |
1231 | ||
1232 | fn build_dylib(&mut self, _out_filename: &Path) { | |
1233 | } | |
1234 | ||
1235 | fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) { | |
1236 | } | |
1237 | ||
1238 | fn subsystem(&mut self, _subsystem: &str) { | |
1239 | } | |
1240 | ||
1241 | fn no_position_independent_executable(&mut self) { | |
1242 | } | |
1243 | ||
1244 | fn group_start(&mut self) { | |
1245 | } | |
1246 | ||
1247 | fn group_end(&mut self) { | |
1248 | } | |
1249 | ||
1250 | fn linker_plugin_lto(&mut self) { | |
1251 | } | |
1252 | } |