1 use super::command
::Command
;
2 use super::symbol_export
;
3 use rustc_span
::symbol
::sym
;
5 use std
::ffi
::{OsStr, OsString}
;
6 use std
::fs
::{self, File}
;
7 use std
::io
::prelude
::*;
8 use std
::io
::{self, BufWriter}
;
9 use std
::path
::{Path, PathBuf}
;
10 use std
::{env, mem, str}
;
12 use rustc_hir
::def_id
::{CrateNum, LOCAL_CRATE}
;
13 use rustc_metadata
::find_native_static_library
;
14 use rustc_middle
::middle
::dependency_format
::Linkage
;
15 use rustc_middle
::middle
::exported_symbols
::{ExportedSymbol, SymbolExportInfo, SymbolExportKind}
;
16 use rustc_middle
::ty
::TyCtxt
;
17 use rustc_session
::config
::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}
;
18 use rustc_session
::Session
;
19 use rustc_target
::spec
::{LinkOutputKind, LinkerFlavor, LldFlavor}
;
21 use cc
::windows_registry
;
23 /// Disables non-English messages from localized linkers.
24 /// Such messages may cause issues with text encoding on Windows (#35785)
25 /// and prevent inspection of linker output in case of errors, which we occasionally do.
26 /// This should be acceptable because other messages from rustc are in English anyway,
27 /// and may also be desirable to improve searchability of the linker diagnostics.
28 pub fn disable_localization(linker
: &mut Command
) {
29 // No harm in setting both env vars simultaneously.
30 // Unix-style linkers.
31 linker
.env("LC_ALL", "C");
33 linker
.env("VSLANG", "1033");
36 // The third parameter is for env vars, used on windows to set up the
37 // path for MSVC to find its DLLs, and gcc to find its bundled
39 pub fn get_linker
<'a
>(
45 ) -> Box
<dyn Linker
+ 'a
> {
46 let msvc_tool
= windows_registry
::find_tool(&sess
.opts
.target_triple
.triple(), "link.exe");
48 // If our linker looks like a batch script on Windows then to execute this
49 // we'll need to spawn `cmd` explicitly. This is primarily done to handle
50 // emscripten where the linker is `emcc.bat` and needs to be spawned as
51 // `cmd /c emcc.bat ...`.
53 // This worked historically but is needed manually since #42436 (regression
54 // was tagged as #42791) and some more info can be found on #44443 for
56 let mut cmd
= match linker
.to_str() {
57 Some(linker
) if cfg
!(windows
) && linker
.ends_with(".bat") => Command
::bat_script(linker
),
59 LinkerFlavor
::Lld(f
) => Command
::lld(linker
, f
),
60 LinkerFlavor
::Msvc
if sess
.opts
.cg
.linker
.is_none() && sess
.target
.linker
.is_none() => {
61 Command
::new(msvc_tool
.as_ref().map_or(linker
, |t
| t
.path()))
63 _
=> Command
::new(linker
),
67 // UWP apps have API restrictions enforced during Store submissions.
68 // To comply with the Windows App Certification Kit,
69 // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc).
71 if (flavor
== LinkerFlavor
::Msvc
|| flavor
== LinkerFlavor
::Lld(LldFlavor
::Link
))
74 if let Some(ref tool
) = msvc_tool
{
75 let original_path
= tool
.path();
76 if let Some(ref root_lib_path
) = original_path
.ancestors().nth(4) {
77 let arch
= match t
.arch
.as_ref() {
78 "x86_64" => Some("x64"),
80 "aarch64" => Some("arm64"),
84 if let Some(ref a
) = arch
{
85 // FIXME: Move this to `fn linker_with_args`.
86 let mut arg
= OsString
::from("/LIBPATH:");
87 arg
.push(format
!("{}\\lib\\{}\\store", root_lib_path
.display(), a
));
90 warn
!("arch is not supported");
93 warn
!("MSVC root path lib location not found");
96 warn
!("link.exe not found");
100 // The compiler's sysroot often has some bundled tools, so add it to the
101 // PATH for the child.
102 let mut new_path
= sess
.get_tools_search_paths(self_contained
);
103 let mut msvc_changed_path
= false;
104 if sess
.target
.is_like_msvc
{
105 if let Some(ref tool
) = msvc_tool
{
106 cmd
.args(tool
.args());
107 for &(ref k
, ref v
) in tool
.env() {
109 new_path
.extend(env
::split_paths(v
));
110 msvc_changed_path
= true;
118 if !msvc_changed_path
{
119 if let Some(path
) = env
::var_os("PATH") {
120 new_path
.extend(env
::split_paths(&path
));
123 cmd
.env("PATH", env
::join_paths(new_path
).unwrap());
125 // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
126 // to the linker args construction.
127 assert
!(cmd
.get_args().is_empty() || sess
.target
.vendor
== "uwp");
129 LinkerFlavor
::Gcc
=> {
130 Box
::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: false }
)
133 LinkerFlavor
::Ld
if sess
.target
.os
== "l4re" => {
134 Box
::new(L4Bender
::new(cmd
, sess
)) as Box
<dyn Linker
>
136 LinkerFlavor
::Lld(LldFlavor
::Ld
)
137 | LinkerFlavor
::Lld(LldFlavor
::Ld64
)
138 | LinkerFlavor
::Ld
=> {
139 Box
::new(GccLinker { cmd, sess, target_cpu, hinted_static: false, is_ld: true }
)
142 LinkerFlavor
::Lld(LldFlavor
::Link
) | LinkerFlavor
::Msvc
=> {
143 Box
::new(MsvcLinker { cmd, sess }
) as Box
<dyn Linker
>
145 LinkerFlavor
::Lld(LldFlavor
::Wasm
) => Box
::new(WasmLd
::new(cmd
, sess
)) as Box
<dyn Linker
>,
146 LinkerFlavor
::EmCc
=> Box
::new(EmLinker { cmd, sess }
) as Box
<dyn Linker
>,
147 LinkerFlavor
::Bpf
=> Box
::new(BpfLinker { cmd, sess }
) as Box
<dyn Linker
>,
148 LinkerFlavor
::Ptx
=> Box
::new(PtxLinker { cmd, sess }
) as Box
<dyn Linker
>,
152 /// Linker abstraction used by `back::link` to build up the command to invoke a
155 /// This trait is the total list of requirements needed by `back::link` and
156 /// represents the meaning of each option being passed down. This trait is then
157 /// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an
158 /// MSVC linker (e.g., `link.exe`) is being used.
160 fn cmd(&mut self) -> &mut Command
;
161 fn set_output_kind(&mut self, output_kind
: LinkOutputKind
, out_filename
: &Path
);
162 fn link_dylib(&mut self, lib
: &str, verbatim
: bool
, as_needed
: bool
);
163 fn link_rust_dylib(&mut self, lib
: &str, path
: &Path
);
164 fn link_framework(&mut self, framework
: &str, as_needed
: bool
);
165 fn link_staticlib(&mut self, lib
: &str, verbatim
: bool
);
166 fn link_rlib(&mut self, lib
: &Path
);
167 fn link_whole_rlib(&mut self, lib
: &Path
);
168 fn link_whole_staticlib(&mut self, lib
: &str, verbatim
: bool
, search_path
: &[PathBuf
]);
169 fn include_path(&mut self, path
: &Path
);
170 fn framework_path(&mut self, path
: &Path
);
171 fn output_filename(&mut self, path
: &Path
);
172 fn add_object(&mut self, path
: &Path
);
173 fn gc_sections(&mut self, keep_metadata
: bool
);
174 fn no_gc_sections(&mut self);
175 fn full_relro(&mut self);
176 fn partial_relro(&mut self);
177 fn no_relro(&mut self);
178 fn optimize(&mut self);
179 fn pgo_gen(&mut self);
180 fn control_flow_guard(&mut self);
181 fn debuginfo(&mut self, strip
: Strip
, natvis_debugger_visualizers
: &[PathBuf
]);
182 fn no_crt_objects(&mut self);
183 fn no_default_libraries(&mut self);
184 fn export_symbols(&mut self, tmpdir
: &Path
, crate_type
: CrateType
, symbols
: &[String
]);
185 fn subsystem(&mut self, subsystem
: &str);
186 fn linker_plugin_lto(&mut self);
187 fn add_eh_frame_header(&mut self) {}
188 fn add_no_exec(&mut self) {}
189 fn add_as_needed(&mut self) {}
190 fn reset_per_library_state(&mut self) {}
193 impl dyn Linker
+ '_
{
194 pub fn arg(&mut self, arg
: impl AsRef
<OsStr
>) {
198 pub fn args(&mut self, args
: impl IntoIterator
<Item
: AsRef
<OsStr
>>) {
199 self.cmd().args(args
);
202 pub fn take_cmd(&mut self) -> Command
{
203 mem
::replace(self.cmd(), Command
::new(""))
207 pub struct GccLinker
<'a
> {
211 hinted_static
: bool
, // Keeps track of the current hinting mode.
216 impl<'a
> GccLinker
<'a
> {
217 /// Passes an argument directly to the linker.
219 /// When the linker is not ld-like such as when using a compiler as a linker, the argument is
220 /// prepended by `-Wl,`.
221 fn linker_arg(&mut self, arg
: impl AsRef
<OsStr
>) -> &mut Self {
222 self.linker_args(&[arg
]);
226 /// Passes a series of arguments directly to the linker.
228 /// When the linker is ld-like, the arguments are simply appended to the command. When the
229 /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by
230 /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a
231 /// single argument is appended to the command to ensure that the order of the arguments is
232 /// preserved by the compiler.
233 fn linker_args(&mut self, args
: &[impl AsRef
<OsStr
>]) -> &mut Self {
235 args
.into_iter().for_each(|a
| {
239 if !args
.is_empty() {
240 let mut s
= OsString
::from("-Wl");
251 fn takes_hints(&self) -> bool
{
252 // Really this function only returns true if the underlying linker
253 // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We
254 // don't really have a foolproof way to detect that, so rule out some
255 // platforms where currently this is guaranteed to *not* be the case:
257 // * On OSX they have their own linker, not binutils'
258 // * For WebAssembly the only functional linker is LLD, which doesn't
259 // support hint flags
260 !self.sess
.target
.is_like_osx
&& !self.sess
.target
.is_like_wasm
263 // Some platforms take hints about whether a library is static or dynamic.
264 // For those that support this, we ensure we pass the option if the library
265 // was flagged "static" (most defaults are dynamic) to ensure that if
266 // libfoo.a and libfoo.so both exist that the right one is chosen.
267 fn hint_static(&mut self) {
268 if !self.takes_hints() {
271 if !self.hinted_static
{
272 self.linker_arg("-Bstatic");
273 self.hinted_static
= true;
277 fn hint_dynamic(&mut self) {
278 if !self.takes_hints() {
281 if self.hinted_static
{
282 self.linker_arg("-Bdynamic");
283 self.hinted_static
= false;
287 fn push_linker_plugin_lto_args(&mut self, plugin_path
: Option
<&OsStr
>) {
288 if let Some(plugin_path
) = plugin_path
{
289 let mut arg
= OsString
::from("-plugin=");
290 arg
.push(plugin_path
);
291 self.linker_arg(&arg
);
294 let opt_level
= match self.sess
.opts
.optimize
{
295 config
::OptLevel
::No
=> "O0",
296 config
::OptLevel
::Less
=> "O1",
297 config
::OptLevel
::Default
| config
::OptLevel
::Size
| config
::OptLevel
::SizeMin
=> "O2",
298 config
::OptLevel
::Aggressive
=> "O3",
301 if let Some(path
) = &self.sess
.opts
.unstable_opts
.profile_sample_use
{
302 self.linker_arg(&format
!("-plugin-opt=sample-profile={}", path
.display()));
305 &format
!("-plugin-opt={}", opt_level
),
306 &format
!("-plugin-opt=mcpu={}", self.target_cpu
),
310 fn build_dylib(&mut self, out_filename
: &Path
) {
311 // On mac we need to tell the linker to let this library be rpathed
312 if self.sess
.target
.is_like_osx
{
314 self.cmd
.arg("-dynamiclib");
317 self.linker_arg("-dylib");
319 // Note that the `osx_rpath_install_name` option here is a hack
320 // purely to support rustbuild right now, we should get a more
321 // principled solution at some point to force the compiler to pass
322 // the right `-Wl,-install_name` with an `@rpath` in it.
323 if self.sess
.opts
.cg
.rpath
|| self.sess
.opts
.unstable_opts
.osx_rpath_install_name
{
324 let mut rpath
= OsString
::from("@rpath/");
325 rpath
.push(out_filename
.file_name().unwrap());
326 self.linker_args(&[OsString
::from("-install_name"), rpath
]);
329 self.cmd
.arg("-shared");
330 if self.sess
.target
.is_like_windows
{
331 // The output filename already contains `dll_suffix` so
332 // the resulting import library will have a name in the
333 // form of libfoo.dll.a
335 out_filename
.file_name().and_then(|file
| file
.to_str()).map(|file
| {
338 self.sess
.target
.staticlib_prefix
,
340 self.sess
.target
.staticlib_suffix
343 if let Some(implib_name
) = implib_name
{
344 let implib
= out_filename
.parent().map(|dir
| dir
.join(&implib_name
));
345 if let Some(implib
) = implib
{
346 self.linker_arg(&format
!("--out-implib={}", (*implib
).to_str().unwrap()));
354 impl<'a
> Linker
for GccLinker
<'a
> {
355 fn cmd(&mut self) -> &mut Command
{
359 fn set_output_kind(&mut self, output_kind
: LinkOutputKind
, out_filename
: &Path
) {
361 LinkOutputKind
::DynamicNoPicExe
=> {
362 if !self.is_ld
&& self.sess
.target
.linker_is_gnu
{
363 self.cmd
.arg("-no-pie");
366 LinkOutputKind
::DynamicPicExe
=> {
367 // noop on windows w/ gcc & ld, error w/ lld
368 if !self.sess
.target
.is_like_windows
{
369 // `-pie` works for both gcc wrapper and ld.
370 self.cmd
.arg("-pie");
373 LinkOutputKind
::StaticNoPicExe
=> {
374 // `-static` works for both gcc wrapper and ld.
375 self.cmd
.arg("-static");
376 if !self.is_ld
&& self.sess
.target
.linker_is_gnu
{
377 self.cmd
.arg("-no-pie");
380 LinkOutputKind
::StaticPicExe
=> {
382 // Note that combination `-static -pie` doesn't work as expected
383 // for the gcc wrapper, `-static` in that case suppresses `-pie`.
384 self.cmd
.arg("-static-pie");
386 // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing
387 // a static pie, but currently passed because gcc and clang pass them.
388 // The former suppresses the `INTERP` ELF header specifying dynamic linker,
389 // which is otherwise implicitly injected by ld (but not lld).
390 // The latter doesn't change anything, only ensures that everything is pic.
391 self.cmd
.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
394 LinkOutputKind
::DynamicDylib
=> self.build_dylib(out_filename
),
395 LinkOutputKind
::StaticDylib
=> {
396 self.cmd
.arg("-static");
397 self.build_dylib(out_filename
);
399 LinkOutputKind
::WasiReactorExe
=> {
400 self.linker_args(&["--entry", "_initialize"]);
403 // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc,
404 // it switches linking for libc and similar system libraries to static without using
405 // any `#[link]` attributes in the `libc` crate, see #72782 for details.
406 // FIXME: Switch to using `#[link]` attributes in the `libc` crate
407 // similarly to other targets.
408 if self.sess
.target
.os
== "vxworks"
411 LinkOutputKind
::StaticNoPicExe
412 | LinkOutputKind
::StaticPicExe
413 | LinkOutputKind
::StaticDylib
416 self.cmd
.arg("--static-crt");
420 fn link_dylib(&mut self, lib
: &str, verbatim
: bool
, as_needed
: bool
) {
421 if self.sess
.target
.os
== "illumos" && lib
== "c" {
422 // libc will be added via late_link_args on illumos so that it will
423 // appear last in the library search order.
424 // FIXME: This should be replaced by a more complete and generic
425 // mechanism for controlling the order of library arguments passed
430 if self.sess
.target
.is_like_osx
{
431 // FIXME(81490): ld64 doesn't support these flags but macOS 11
432 // has -needed-l{} / -needed_library {}
433 // but we have no way to detect that here.
434 self.sess
.warn("`as-needed` modifier not implemented yet for ld64");
435 } else if self.sess
.target
.linker_is_gnu
&& !self.sess
.target
.is_like_windows
{
436 self.linker_arg("--no-as-needed");
438 self.sess
.warn("`as-needed` modifier not supported for current linker");
442 self.cmd
.arg(format
!("-l{}{}", if verbatim { ":" }
else { "" }
, lib
));
444 if self.sess
.target
.is_like_osx
{
445 // See above FIXME comment
446 } else if self.sess
.target
.linker_is_gnu
&& !self.sess
.target
.is_like_windows
{
447 self.linker_arg("--as-needed");
451 fn link_staticlib(&mut self, lib
: &str, verbatim
: bool
) {
453 self.cmd
.arg(format
!("-l{}{}", if verbatim { ":" }
else { "" }
, lib
));
455 fn link_rlib(&mut self, lib
: &Path
) {
459 fn include_path(&mut self, path
: &Path
) {
460 self.cmd
.arg("-L").arg(path
);
462 fn framework_path(&mut self, path
: &Path
) {
463 self.cmd
.arg("-F").arg(path
);
465 fn output_filename(&mut self, path
: &Path
) {
466 self.cmd
.arg("-o").arg(path
);
468 fn add_object(&mut self, path
: &Path
) {
471 fn full_relro(&mut self) {
472 self.linker_args(&["-zrelro", "-znow"]);
474 fn partial_relro(&mut self) {
475 self.linker_arg("-zrelro");
477 fn no_relro(&mut self) {
478 self.linker_arg("-znorelro");
481 fn link_rust_dylib(&mut self, lib
: &str, _path
: &Path
) {
483 self.cmd
.arg(format
!("-l{}", lib
));
486 fn link_framework(&mut self, framework
: &str, as_needed
: bool
) {
489 // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
490 // flag but we have no way to detect that here.
491 // self.cmd.arg("-needed_framework").arg(framework);
492 self.sess
.warn("`as-needed` modifier not implemented yet for ld64");
494 self.cmd
.arg("-framework").arg(framework
);
497 // Here we explicitly ask that the entire archive is included into the
498 // result artifact. For more details see #15460, but the gist is that
499 // the linker will strip away any unused objects in the archive if we
500 // don't otherwise explicitly reference them. This can occur for
501 // libraries which are just providing bindings, libraries with generic
503 fn link_whole_staticlib(&mut self, lib
: &str, verbatim
: bool
, search_path
: &[PathBuf
]) {
505 let target
= &self.sess
.target
;
506 if !target
.is_like_osx
{
507 self.linker_arg("--whole-archive").cmd
.arg(format
!(
509 if verbatim { ":" }
else { "" }
,
512 self.linker_arg("--no-whole-archive");
514 // -force_load is the macOS equivalent of --whole-archive, but it
515 // involves passing the full path to the library to link.
516 self.linker_arg("-force_load");
517 let lib
= find_native_static_library(lib
, Some(verbatim
), search_path
, &self.sess
);
518 self.linker_arg(&lib
);
522 fn link_whole_rlib(&mut self, lib
: &Path
) {
524 if self.sess
.target
.is_like_osx
{
525 self.linker_arg("-force_load");
526 self.linker_arg(&lib
);
528 self.linker_arg("--whole-archive").cmd
.arg(lib
);
529 self.linker_arg("--no-whole-archive");
533 fn gc_sections(&mut self, keep_metadata
: bool
) {
534 // The dead_strip option to the linker specifies that functions and data
535 // unreachable by the entry point will be removed. This is quite useful
536 // with Rust's compilation model of compiling libraries at a time into
537 // one object file. For example, this brings hello world from 1.7MB to
540 // Note that this is done for both executables and dynamic libraries. We
541 // won't get much benefit from dylibs because LLVM will have already
542 // stripped away as much as it could. This has not been seen to impact
543 // link times negatively.
545 // -dead_strip can't be part of the pre_link_args because it's also used
546 // for partial linking when using multiple codegen units (-r). So we
548 if self.sess
.target
.is_like_osx
{
549 self.linker_arg("-dead_strip");
551 // If we're building a dylib, we don't use --gc-sections because LLVM
552 // has already done the best it can do, and we also don't want to
553 // eliminate the metadata. If we're building an executable, however,
554 // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
556 } else if (self.sess
.target
.linker_is_gnu
|| self.sess
.target
.is_like_wasm
)
559 self.linker_arg("--gc-sections");
563 fn no_gc_sections(&mut self) {
564 if self.sess
.target
.linker_is_gnu
|| self.sess
.target
.is_like_wasm
{
565 self.linker_arg("--no-gc-sections");
569 fn optimize(&mut self) {
570 if !self.sess
.target
.linker_is_gnu
&& !self.sess
.target
.is_like_wasm
{
574 // GNU-style linkers support optimization with -O. GNU ld doesn't
575 // need a numeric argument, but other linkers do.
576 if self.sess
.opts
.optimize
== config
::OptLevel
::Default
577 || self.sess
.opts
.optimize
== config
::OptLevel
::Aggressive
579 self.linker_arg("-O1");
583 fn pgo_gen(&mut self) {
584 if !self.sess
.target
.linker_is_gnu
{
588 // If we're doing PGO generation stuff and on a GNU-like linker, use the
589 // "-u" flag to properly pull in the profiler runtime bits.
591 // This is because LLVM otherwise won't add the needed initialization
592 // for us on Linux (though the extra flag should be harmless if it
595 // See https://reviews.llvm.org/D14033 and https://reviews.llvm.org/D14030.
597 // Though it may be worth to try to revert those changes upstream, since
598 // the overhead of the initialization should be minor.
600 self.cmd
.arg("__llvm_profile_runtime");
603 fn control_flow_guard(&mut self) {}
605 fn debuginfo(&mut self, strip
: Strip
, _
: &[PathBuf
]) {
606 // MacOS linker doesn't support stripping symbols directly anymore.
607 if self.sess
.target
.is_like_osx
{
613 Strip
::Debuginfo
=> {
614 self.linker_arg("--strip-debug");
617 self.linker_arg("--strip-all");
622 fn no_crt_objects(&mut self) {
624 self.cmd
.arg("-nostartfiles");
628 fn no_default_libraries(&mut self) {
630 self.cmd
.arg("-nodefaultlibs");
634 fn export_symbols(&mut self, tmpdir
: &Path
, crate_type
: CrateType
, symbols
: &[String
]) {
635 // Symbol visibility in object files typically takes care of this.
636 if crate_type
== CrateType
::Executable
{
637 let should_export_executable_symbols
=
638 self.sess
.opts
.unstable_opts
.export_executable_symbols
;
639 if self.sess
.target
.override_export_symbols
.is_none()
640 && !should_export_executable_symbols
646 // We manually create a list of exported symbols to ensure we don't expose any more.
647 // The object files have far more public symbols than we actually want to export,
648 // so we hide them all here.
650 if !self.sess
.target
.limit_rdylib_exports
{
654 // FIXME(#99978) hide #[no_mangle] symbols for proc-macros
656 let is_windows
= self.sess
.target
.is_like_windows
;
657 let path
= tmpdir
.join(if is_windows { "list.def" }
else { "list" }
);
659 debug
!("EXPORTED SYMBOLS:");
661 if self.sess
.target
.is_like_osx
{
662 // Write a plain, newline-separated list of symbols
663 let res
: io
::Result
<()> = try
{
664 let mut f
= BufWriter
::new(File
::create(&path
)?
);
667 writeln
!(f
, "_{}", sym
)?
;
670 if let Err(e
) = res
{
671 self.sess
.fatal(&format
!("failed to write lib.def file: {}", e
));
673 } else if is_windows
{
674 let res
: io
::Result
<()> = try
{
675 let mut f
= BufWriter
::new(File
::create(&path
)?
);
677 // .def file similar to MSVC one but without LIBRARY section
678 // because LD doesn't like when it's empty
679 writeln
!(f
, "EXPORTS")?
;
680 for symbol
in symbols
{
681 debug
!(" _{}", symbol
);
682 writeln
!(f
, " {}", symbol
)?
;
685 if let Err(e
) = res
{
686 self.sess
.fatal(&format
!("failed to write list.def file: {}", e
));
689 // Write an LD version script
690 let res
: io
::Result
<()> = try
{
691 let mut f
= BufWriter
::new(File
::create(&path
)?
);
693 if !symbols
.is_empty() {
694 writeln
!(f
, " global:")?
;
697 writeln
!(f
, " {};", sym
)?
;
700 writeln
!(f
, "\n local:\n *;\n}};")?
;
702 if let Err(e
) = res
{
703 self.sess
.fatal(&format
!("failed to write version script: {}", e
));
707 if self.sess
.target
.is_like_osx
{
708 self.linker_args(&[OsString
::from("-exported_symbols_list"), path
.into()]);
709 } else if self.sess
.target
.is_like_solaris
{
710 self.linker_args(&[OsString
::from("-M"), path
.into()]);
713 self.linker_arg(path
);
715 let mut arg
= OsString
::from("--version-script=");
717 self.linker_arg(arg
);
722 fn subsystem(&mut self, subsystem
: &str) {
723 self.linker_arg("--subsystem");
724 self.linker_arg(&subsystem
);
727 fn reset_per_library_state(&mut self) {
728 self.hint_dynamic(); // Reset to default before returning the composed command line.
731 fn linker_plugin_lto(&mut self) {
732 match self.sess
.opts
.cg
.linker_plugin_lto
{
733 LinkerPluginLto
::Disabled
=> {
736 LinkerPluginLto
::LinkerPluginAuto
=> {
737 self.push_linker_plugin_lto_args(None
);
739 LinkerPluginLto
::LinkerPlugin(ref path
) => {
740 self.push_linker_plugin_lto_args(Some(path
.as_os_str()));
745 // Add the `GNU_EH_FRAME` program header which is required to locate unwinding information.
746 // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't,
747 // so we just always add it.
748 fn add_eh_frame_header(&mut self) {
749 self.linker_arg("--eh-frame-hdr");
752 fn add_no_exec(&mut self) {
753 if self.sess
.target
.is_like_windows
{
754 self.linker_arg("--nxcompat");
755 } else if self.sess
.target
.linker_is_gnu
{
756 self.linker_arg("-znoexecstack");
760 fn add_as_needed(&mut self) {
761 if self.sess
.target
.linker_is_gnu
&& !self.sess
.target
.is_like_windows
{
762 self.linker_arg("--as-needed");
763 } else if self.sess
.target
.is_like_solaris
{
764 // -z ignore is the Solaris equivalent to the GNU ld --as-needed option
765 self.linker_args(&["-z", "ignore"]);
770 pub struct MsvcLinker
<'a
> {
775 impl<'a
> Linker
for MsvcLinker
<'a
> {
776 fn cmd(&mut self) -> &mut Command
{
780 fn set_output_kind(&mut self, output_kind
: LinkOutputKind
, out_filename
: &Path
) {
782 LinkOutputKind
::DynamicNoPicExe
783 | LinkOutputKind
::DynamicPicExe
784 | LinkOutputKind
::StaticNoPicExe
785 | LinkOutputKind
::StaticPicExe
=> {}
786 LinkOutputKind
::DynamicDylib
| LinkOutputKind
::StaticDylib
=> {
787 self.cmd
.arg("/DLL");
788 let mut arg
: OsString
= "/IMPLIB:".into();
789 arg
.push(out_filename
.with_extension("dll.lib"));
792 LinkOutputKind
::WasiReactorExe
=> {
793 panic
!("can't link as reactor on non-wasi target");
798 fn link_rlib(&mut self, lib
: &Path
) {
801 fn add_object(&mut self, path
: &Path
) {
805 fn gc_sections(&mut self, _keep_metadata
: bool
) {
806 // MSVC's ICF (Identical COMDAT Folding) link optimization is
807 // slow for Rust and thus we disable it by default when not in
808 // optimization build.
809 if self.sess
.opts
.optimize
!= config
::OptLevel
::No
{
810 self.cmd
.arg("/OPT:REF,ICF");
812 // It is necessary to specify NOICF here, because /OPT:REF
813 // implies ICF by default.
814 self.cmd
.arg("/OPT:REF,NOICF");
818 fn no_gc_sections(&mut self) {
819 self.cmd
.arg("/OPT:NOREF,NOICF");
822 fn link_dylib(&mut self, lib
: &str, verbatim
: bool
, _as_needed
: bool
) {
823 self.cmd
.arg(format
!("{}{}", lib
, if verbatim { "" }
else { ".lib" }
));
826 fn link_rust_dylib(&mut self, lib
: &str, path
: &Path
) {
827 // When producing a dll, the MSVC linker may not actually emit a
828 // `foo.lib` file if the dll doesn't actually export any symbols, so we
829 // check to see if the file is there and just omit linking to it if it's
831 let name
= format
!("{}.dll.lib", lib
);
832 if path
.join(&name
).exists() {
837 fn link_staticlib(&mut self, lib
: &str, verbatim
: bool
) {
838 self.cmd
.arg(format
!("{}{}", lib
, if verbatim { "" }
else { ".lib" }
));
841 fn full_relro(&mut self) {
845 fn partial_relro(&mut self) {
849 fn no_relro(&mut self) {
853 fn no_crt_objects(&mut self) {
857 fn no_default_libraries(&mut self) {
858 self.cmd
.arg("/NODEFAULTLIB");
861 fn include_path(&mut self, path
: &Path
) {
862 let mut arg
= OsString
::from("/LIBPATH:");
867 fn output_filename(&mut self, path
: &Path
) {
868 let mut arg
= OsString
::from("/OUT:");
873 fn framework_path(&mut self, _path
: &Path
) {
874 bug
!("frameworks are not supported on windows")
876 fn link_framework(&mut self, _framework
: &str, _as_needed
: bool
) {
877 bug
!("frameworks are not supported on windows")
880 fn link_whole_staticlib(&mut self, lib
: &str, verbatim
: bool
, _search_path
: &[PathBuf
]) {
881 self.cmd
.arg(format
!("/WHOLEARCHIVE:{}{}", lib
, if verbatim { "" }
else { ".lib" }
));
883 fn link_whole_rlib(&mut self, path
: &Path
) {
884 let mut arg
= OsString
::from("/WHOLEARCHIVE:");
888 fn optimize(&mut self) {
889 // Needs more investigation of `/OPT` arguments
892 fn pgo_gen(&mut self) {
893 // Nothing needed here.
896 fn control_flow_guard(&mut self) {
897 self.cmd
.arg("/guard:cf");
900 fn debuginfo(&mut self, strip
: Strip
, natvis_debugger_visualizers
: &[PathBuf
]) {
903 // This will cause the Microsoft linker to generate a PDB file
904 // from the CodeView line tables in the object files.
905 self.cmd
.arg("/DEBUG");
907 // This will cause the Microsoft linker to embed .natvis info into the PDB file
908 let natvis_dir_path
= self.sess
.sysroot
.join("lib\\rustlib\\etc");
909 if let Ok(natvis_dir
) = fs
::read_dir(&natvis_dir_path
) {
910 for entry
in natvis_dir
{
913 let path
= entry
.path();
914 if path
.extension() == Some("natvis".as_ref()) {
915 let mut arg
= OsString
::from("/NATVIS:");
922 .warn(&format
!("error enumerating natvis directory: {}", err
));
928 // This will cause the Microsoft linker to embed .natvis info for all crates into the PDB file
929 for path
in natvis_debugger_visualizers
{
930 let mut arg
= OsString
::from("/NATVIS:");
935 Strip
::Debuginfo
| Strip
::Symbols
=> {
936 self.cmd
.arg("/DEBUG:NONE");
941 // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
942 // export symbols from a dynamic library. When building a dynamic library,
943 // however, we're going to want some symbols exported, so this function
944 // generates a DEF file which lists all the symbols.
946 // The linker will read this `*.def` file and export all the symbols from
947 // the dynamic library. Note that this is not as simple as just exporting
948 // all the symbols in the current crate (as specified by `codegen.reachable`)
949 // but rather we also need to possibly export the symbols of upstream
950 // crates. Upstream rlibs may be linked statically to this dynamic library,
951 // in which case they may continue to transitively be used and hence need
952 // their symbols exported.
953 fn export_symbols(&mut self, tmpdir
: &Path
, crate_type
: CrateType
, symbols
: &[String
]) {
954 // Symbol visibility takes care of this typically
955 if crate_type
== CrateType
::Executable
{
956 let should_export_executable_symbols
=
957 self.sess
.opts
.unstable_opts
.export_executable_symbols
;
958 if !should_export_executable_symbols
{
963 let path
= tmpdir
.join("lib.def");
964 let res
: io
::Result
<()> = try
{
965 let mut f
= BufWriter
::new(File
::create(&path
)?
);
967 // Start off with the standard module name header and then go
968 // straight to exports.
969 writeln
!(f
, "LIBRARY")?
;
970 writeln
!(f
, "EXPORTS")?
;
971 for symbol
in symbols
{
972 debug
!(" _{}", symbol
);
973 writeln
!(f
, " {}", symbol
)?
;
976 if let Err(e
) = res
{
977 self.sess
.fatal(&format
!("failed to write lib.def file: {}", e
));
979 let mut arg
= OsString
::from("/DEF:");
984 fn subsystem(&mut self, subsystem
: &str) {
985 // Note that previous passes of the compiler validated this subsystem,
986 // so we just blindly pass it to the linker.
987 self.cmd
.arg(&format
!("/SUBSYSTEM:{}", subsystem
));
989 // Windows has two subsystems we're interested in right now, the console
990 // and windows subsystems. These both implicitly have different entry
991 // points (starting symbols). The console entry point starts with
992 // `mainCRTStartup` and the windows entry point starts with
993 // `WinMainCRTStartup`. These entry points, defined in system libraries,
994 // will then later probe for either `main` or `WinMain`, respectively to
995 // start the application.
997 // In Rust we just always generate a `main` function so we want control
998 // to always start there, so we force the entry point on the windows
999 // subsystem to be `mainCRTStartup` to get everything booted up
1002 // For more information see RFC #1665
1003 if subsystem
== "windows" {
1004 self.cmd
.arg("/ENTRY:mainCRTStartup");
1008 fn linker_plugin_lto(&mut self) {
1012 fn add_no_exec(&mut self) {
1013 self.cmd
.arg("/NXCOMPAT");
1017 pub struct EmLinker
<'a
> {
1022 impl<'a
> Linker
for EmLinker
<'a
> {
1023 fn cmd(&mut self) -> &mut Command
{
1027 fn set_output_kind(&mut self, _output_kind
: LinkOutputKind
, _out_filename
: &Path
) {}
1029 fn include_path(&mut self, path
: &Path
) {
1030 self.cmd
.arg("-L").arg(path
);
1033 fn link_staticlib(&mut self, lib
: &str, _verbatim
: bool
) {
1034 self.cmd
.arg("-l").arg(lib
);
1037 fn output_filename(&mut self, path
: &Path
) {
1038 self.cmd
.arg("-o").arg(path
);
1041 fn add_object(&mut self, path
: &Path
) {
1045 fn link_dylib(&mut self, lib
: &str, verbatim
: bool
, _as_needed
: bool
) {
1046 // Emscripten always links statically
1047 self.link_staticlib(lib
, verbatim
);
1050 fn link_whole_staticlib(&mut self, lib
: &str, verbatim
: bool
, _search_path
: &[PathBuf
]) {
1052 self.link_staticlib(lib
, verbatim
);
1055 fn link_whole_rlib(&mut self, lib
: &Path
) {
1057 self.link_rlib(lib
);
1060 fn link_rust_dylib(&mut self, lib
: &str, _path
: &Path
) {
1061 self.link_dylib(lib
, false, true);
1064 fn link_rlib(&mut self, lib
: &Path
) {
1065 self.add_object(lib
);
1068 fn full_relro(&mut self) {
1072 fn partial_relro(&mut self) {
1076 fn no_relro(&mut self) {
1080 fn framework_path(&mut self, _path
: &Path
) {
1081 bug
!("frameworks are not supported on Emscripten")
1084 fn link_framework(&mut self, _framework
: &str, _as_needed
: bool
) {
1085 bug
!("frameworks are not supported on Emscripten")
1088 fn gc_sections(&mut self, _keep_metadata
: bool
) {
1092 fn no_gc_sections(&mut self) {
1096 fn optimize(&mut self) {
1097 // Emscripten performs own optimizations
1098 self.cmd
.arg(match self.sess
.opts
.optimize
{
1099 OptLevel
::No
=> "-O0",
1100 OptLevel
::Less
=> "-O1",
1101 OptLevel
::Default
=> "-O2",
1102 OptLevel
::Aggressive
=> "-O3",
1103 OptLevel
::Size
=> "-Os",
1104 OptLevel
::SizeMin
=> "-Oz",
1108 fn pgo_gen(&mut self) {
1109 // noop, but maybe we need something like the gnu linker?
1112 fn control_flow_guard(&mut self) {}
1114 fn debuginfo(&mut self, _strip
: Strip
, _
: &[PathBuf
]) {
1115 // Preserve names or generate source maps depending on debug info
1116 self.cmd
.arg(match self.sess
.opts
.debuginfo
{
1117 DebugInfo
::None
=> "-g0",
1118 DebugInfo
::Limited
=> "--profiling-funcs",
1119 DebugInfo
::Full
=> "-g",
1123 fn no_crt_objects(&mut self) {}
1125 fn no_default_libraries(&mut self) {
1126 self.cmd
.arg("-nodefaultlibs");
1129 fn export_symbols(&mut self, _tmpdir
: &Path
, _crate_type
: CrateType
, symbols
: &[String
]) {
1130 debug
!("EXPORTED SYMBOLS:");
1134 let mut arg
= OsString
::from("EXPORTED_FUNCTIONS=");
1135 let encoded
= serde_json
::to_string(
1136 &symbols
.iter().map(|sym
| "_".to_owned() + sym
).collect
::<Vec
<_
>>(),
1139 debug
!("{}", encoded
);
1146 fn subsystem(&mut self, _subsystem
: &str) {
1150 fn linker_plugin_lto(&mut self) {
1155 pub struct WasmLd
<'a
> {
1160 impl<'a
> WasmLd
<'a
> {
1161 fn new(mut cmd
: Command
, sess
: &'a Session
) -> WasmLd
<'a
> {
1162 // If the atomics feature is enabled for wasm then we need a whole bunch
1165 // * `--shared-memory` - the link won't even succeed without this, flags
1166 // the one linear memory as `shared`
1168 // * `--max-memory=1G` - when specifying a shared memory this must also
1169 // be specified. We conservatively choose 1GB but users should be able
1170 // to override this with `-C link-arg`.
1172 // * `--import-memory` - it doesn't make much sense for memory to be
1173 // exported in a threaded module because typically you're
1174 // sharing memory and instantiating the module multiple times. As a
1175 // result if it were exported then we'd just have no sharing.
1177 // * `--export=__wasm_init_memory` - when using `--passive-segments` the
1178 // linker will synthesize this function, and so we need to make sure
1179 // that our usage of `--export` below won't accidentally cause this
1180 // function to get deleted.
1182 // * `--export=*tls*` - when `#[thread_local]` symbols are used these
1183 // symbols are how the TLS segments are initialized and configured.
1184 if sess
.target_features
.contains(&sym
::atomics
) {
1185 cmd
.arg("--shared-memory");
1186 cmd
.arg("--max-memory=1073741824");
1187 cmd
.arg("--import-memory");
1188 cmd
.arg("--export=__wasm_init_memory");
1189 cmd
.arg("--export=__wasm_init_tls");
1190 cmd
.arg("--export=__tls_size");
1191 cmd
.arg("--export=__tls_align");
1192 cmd
.arg("--export=__tls_base");
1194 WasmLd { cmd, sess }
1198 impl<'a
> Linker
for WasmLd
<'a
> {
1199 fn cmd(&mut self) -> &mut Command
{
1203 fn set_output_kind(&mut self, output_kind
: LinkOutputKind
, _out_filename
: &Path
) {
1205 LinkOutputKind
::DynamicNoPicExe
1206 | LinkOutputKind
::DynamicPicExe
1207 | LinkOutputKind
::StaticNoPicExe
1208 | LinkOutputKind
::StaticPicExe
=> {}
1209 LinkOutputKind
::DynamicDylib
| LinkOutputKind
::StaticDylib
=> {
1210 self.cmd
.arg("--no-entry");
1212 LinkOutputKind
::WasiReactorExe
=> {
1213 self.cmd
.arg("--entry");
1214 self.cmd
.arg("_initialize");
1219 fn link_dylib(&mut self, lib
: &str, _verbatim
: bool
, _as_needed
: bool
) {
1220 self.cmd
.arg("-l").arg(lib
);
1223 fn link_staticlib(&mut self, lib
: &str, _verbatim
: bool
) {
1224 self.cmd
.arg("-l").arg(lib
);
1227 fn link_rlib(&mut self, lib
: &Path
) {
1231 fn include_path(&mut self, path
: &Path
) {
1232 self.cmd
.arg("-L").arg(path
);
1235 fn framework_path(&mut self, _path
: &Path
) {
1236 panic
!("frameworks not supported")
1239 fn output_filename(&mut self, path
: &Path
) {
1240 self.cmd
.arg("-o").arg(path
);
1243 fn add_object(&mut self, path
: &Path
) {
1247 fn full_relro(&mut self) {}
1249 fn partial_relro(&mut self) {}
1251 fn no_relro(&mut self) {}
1253 fn link_rust_dylib(&mut self, lib
: &str, _path
: &Path
) {
1254 self.cmd
.arg("-l").arg(lib
);
1257 fn link_framework(&mut self, _framework
: &str, _as_needed
: bool
) {
1258 panic
!("frameworks not supported")
1261 fn link_whole_staticlib(&mut self, lib
: &str, _verbatim
: bool
, _search_path
: &[PathBuf
]) {
1262 self.cmd
.arg("-l").arg(lib
);
1265 fn link_whole_rlib(&mut self, lib
: &Path
) {
1269 fn gc_sections(&mut self, _keep_metadata
: bool
) {
1270 self.cmd
.arg("--gc-sections");
1273 fn no_gc_sections(&mut self) {
1274 self.cmd
.arg("--no-gc-sections");
1277 fn optimize(&mut self) {
1278 self.cmd
.arg(match self.sess
.opts
.optimize
{
1279 OptLevel
::No
=> "-O0",
1280 OptLevel
::Less
=> "-O1",
1281 OptLevel
::Default
=> "-O2",
1282 OptLevel
::Aggressive
=> "-O3",
1283 // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2`
1285 OptLevel
::Size
=> "-O2",
1286 OptLevel
::SizeMin
=> "-O2",
1290 fn pgo_gen(&mut self) {}
1292 fn debuginfo(&mut self, strip
: Strip
, _
: &[PathBuf
]) {
1295 Strip
::Debuginfo
=> {
1296 self.cmd
.arg("--strip-debug");
1299 self.cmd
.arg("--strip-all");
1304 fn control_flow_guard(&mut self) {}
1306 fn no_crt_objects(&mut self) {}
1308 fn no_default_libraries(&mut self) {}
1310 fn export_symbols(&mut self, _tmpdir
: &Path
, _crate_type
: CrateType
, symbols
: &[String
]) {
1311 for sym
in symbols
{
1312 self.cmd
.arg("--export").arg(&sym
);
1315 // LLD will hide these otherwise-internal symbols since it only exports
1316 // symbols explicitly passed via the `--export` flags above and hides all
1317 // others. Various bits and pieces of tooling use this, so be sure these
1318 // symbols make their way out of the linker as well.
1319 self.cmd
.arg("--export=__heap_base");
1320 self.cmd
.arg("--export=__data_end");
1323 fn subsystem(&mut self, _subsystem
: &str) {}
1325 fn linker_plugin_lto(&mut self) {
1326 // Do nothing for now
1330 /// Linker shepherd script for L4Re (Fiasco)
1331 pub struct L4Bender
<'a
> {
1334 hinted_static
: bool
,
1337 impl<'a
> Linker
for L4Bender
<'a
> {
1338 fn link_dylib(&mut self, _lib
: &str, _verbatim
: bool
, _as_needed
: bool
) {
1339 bug
!("dylibs are not supported on L4Re");
1341 fn link_staticlib(&mut self, lib
: &str, _verbatim
: bool
) {
1343 self.cmd
.arg(format
!("-PC{}", lib
));
1345 fn link_rlib(&mut self, lib
: &Path
) {
1349 fn include_path(&mut self, path
: &Path
) {
1350 self.cmd
.arg("-L").arg(path
);
1352 fn framework_path(&mut self, _
: &Path
) {
1353 bug
!("frameworks are not supported on L4Re");
1355 fn output_filename(&mut self, path
: &Path
) {
1356 self.cmd
.arg("-o").arg(path
);
1359 fn add_object(&mut self, path
: &Path
) {
1363 fn full_relro(&mut self) {
1364 self.cmd
.arg("-zrelro");
1365 self.cmd
.arg("-znow");
1368 fn partial_relro(&mut self) {
1369 self.cmd
.arg("-zrelro");
1372 fn no_relro(&mut self) {
1373 self.cmd
.arg("-znorelro");
1376 fn cmd(&mut self) -> &mut Command
{
1380 fn set_output_kind(&mut self, _output_kind
: LinkOutputKind
, _out_filename
: &Path
) {}
1382 fn link_rust_dylib(&mut self, _
: &str, _
: &Path
) {
1383 panic
!("Rust dylibs not supported");
1386 fn link_framework(&mut self, _framework
: &str, _as_needed
: bool
) {
1387 bug
!("frameworks not supported on L4Re");
1390 fn link_whole_staticlib(&mut self, lib
: &str, _verbatim
: bool
, _search_path
: &[PathBuf
]) {
1392 self.cmd
.arg("--whole-archive").arg(format
!("-l{}", lib
));
1393 self.cmd
.arg("--no-whole-archive");
1396 fn link_whole_rlib(&mut self, lib
: &Path
) {
1398 self.cmd
.arg("--whole-archive").arg(lib
).arg("--no-whole-archive");
1401 fn gc_sections(&mut self, keep_metadata
: bool
) {
1403 self.cmd
.arg("--gc-sections");
1407 fn no_gc_sections(&mut self) {
1408 self.cmd
.arg("--no-gc-sections");
1411 fn optimize(&mut self) {
1412 // GNU-style linkers support optimization with -O. GNU ld doesn't
1413 // need a numeric argument, but other linkers do.
1414 if self.sess
.opts
.optimize
== config
::OptLevel
::Default
1415 || self.sess
.opts
.optimize
== config
::OptLevel
::Aggressive
1417 self.cmd
.arg("-O1");
1421 fn pgo_gen(&mut self) {}
1423 fn debuginfo(&mut self, strip
: Strip
, _
: &[PathBuf
]) {
1426 Strip
::Debuginfo
=> {
1427 self.cmd().arg("--strip-debug");
1430 self.cmd().arg("--strip-all");
1435 fn no_default_libraries(&mut self) {
1436 self.cmd
.arg("-nostdlib");
1439 fn export_symbols(&mut self, _
: &Path
, _
: CrateType
, _
: &[String
]) {
1440 // ToDo, not implemented, copy from GCC
1441 self.sess
.warn("exporting symbols not implemented yet for L4Bender");
1445 fn subsystem(&mut self, subsystem
: &str) {
1446 self.cmd
.arg(&format
!("--subsystem {}", subsystem
));
1449 fn reset_per_library_state(&mut self) {
1450 self.hint_static(); // Reset to default before returning the composed command line.
1453 fn linker_plugin_lto(&mut self) {}
1455 fn control_flow_guard(&mut self) {}
1457 fn no_crt_objects(&mut self) {}
1460 impl<'a
> L4Bender
<'a
> {
1461 pub fn new(cmd
: Command
, sess
: &'a Session
) -> L4Bender
<'a
> {
1462 L4Bender { cmd: cmd, sess: sess, hinted_static: false }
1465 fn hint_static(&mut self) {
1466 if !self.hinted_static
{
1467 self.cmd
.arg("-static");
1468 self.hinted_static
= true;
1473 fn for_each_exported_symbols_include_dep
<'tcx
>(
1475 crate_type
: CrateType
,
1476 mut callback
: impl FnMut(ExportedSymbol
<'tcx
>, SymbolExportInfo
, CrateNum
),
1478 for &(symbol
, info
) in tcx
.exported_symbols(LOCAL_CRATE
).iter() {
1479 callback(symbol
, info
, LOCAL_CRATE
);
1482 let formats
= tcx
.dependency_formats(());
1483 let deps
= formats
.iter().find_map(|(t
, list
)| (*t
== crate_type
).then_some(list
)).unwrap();
1485 for (index
, dep_format
) in deps
.iter().enumerate() {
1486 let cnum
= CrateNum
::new(index
+ 1);
1487 // For each dependency that we are linking to statically ...
1488 if *dep_format
== Linkage
::Static
{
1489 for &(symbol
, info
) in tcx
.exported_symbols(cnum
).iter() {
1490 callback(symbol
, info
, cnum
);
1496 pub(crate) fn exported_symbols(tcx
: TyCtxt
<'_
>, crate_type
: CrateType
) -> Vec
<String
> {
1497 if let Some(ref exports
) = tcx
.sess
.target
.override_export_symbols
{
1498 return exports
.iter().map(ToString
::to_string
).collect();
1501 let mut symbols
= Vec
::new();
1503 let export_threshold
= symbol_export
::crates_export_threshold(&[crate_type
]);
1504 for_each_exported_symbols_include_dep(tcx
, crate_type
, |symbol
, info
, cnum
| {
1505 if info
.level
.is_below_threshold(export_threshold
) {
1506 symbols
.push(symbol_export
::symbol_name_for_instance_in_crate(tcx
, symbol
, cnum
));
1513 pub(crate) fn linked_symbols(
1515 crate_type
: CrateType
,
1516 ) -> Vec
<(String
, SymbolExportKind
)> {
1518 CrateType
::Executable
| CrateType
::Cdylib
| CrateType
::Dylib
=> (),
1519 CrateType
::Staticlib
| CrateType
::ProcMacro
| CrateType
::Rlib
=> {
1524 let mut symbols
= Vec
::new();
1526 let export_threshold
= symbol_export
::crates_export_threshold(&[crate_type
]);
1527 for_each_exported_symbols_include_dep(tcx
, crate_type
, |symbol
, info
, cnum
| {
1528 if info
.level
.is_below_threshold(export_threshold
) || info
.used
{
1530 symbol_export
::linking_symbol_name_for_instance_in_crate(tcx
, symbol
, cnum
),
1539 /// Much simplified and explicit CLI for the NVPTX linker. The linker operates
1540 /// with bitcode and uses LLVM backend to generate a PTX assembly.
1541 pub struct PtxLinker
<'a
> {
1546 impl<'a
> Linker
for PtxLinker
<'a
> {
1547 fn cmd(&mut self) -> &mut Command
{
1551 fn set_output_kind(&mut self, _output_kind
: LinkOutputKind
, _out_filename
: &Path
) {}
1553 fn link_rlib(&mut self, path
: &Path
) {
1554 self.cmd
.arg("--rlib").arg(path
);
1557 fn link_whole_rlib(&mut self, path
: &Path
) {
1558 self.cmd
.arg("--rlib").arg(path
);
1561 fn include_path(&mut self, path
: &Path
) {
1562 self.cmd
.arg("-L").arg(path
);
1565 fn debuginfo(&mut self, _strip
: Strip
, _
: &[PathBuf
]) {
1566 self.cmd
.arg("--debug");
1569 fn add_object(&mut self, path
: &Path
) {
1570 self.cmd
.arg("--bitcode").arg(path
);
1573 fn optimize(&mut self) {
1574 match self.sess
.lto() {
1575 Lto
::Thin
| Lto
::Fat
| Lto
::ThinLocal
=> {
1576 self.cmd
.arg("-Olto");
1583 fn output_filename(&mut self, path
: &Path
) {
1584 self.cmd
.arg("-o").arg(path
);
1587 fn link_dylib(&mut self, _lib
: &str, _verbatim
: bool
, _as_needed
: bool
) {
1588 panic
!("external dylibs not supported")
1591 fn link_rust_dylib(&mut self, _lib
: &str, _path
: &Path
) {
1592 panic
!("external dylibs not supported")
1595 fn link_staticlib(&mut self, _lib
: &str, _verbatim
: bool
) {
1596 panic
!("staticlibs not supported")
1599 fn link_whole_staticlib(&mut self, _lib
: &str, _verbatim
: bool
, _search_path
: &[PathBuf
]) {
1600 panic
!("staticlibs not supported")
1603 fn framework_path(&mut self, _path
: &Path
) {
1604 panic
!("frameworks not supported")
1607 fn link_framework(&mut self, _framework
: &str, _as_needed
: bool
) {
1608 panic
!("frameworks not supported")
1611 fn full_relro(&mut self) {}
1613 fn partial_relro(&mut self) {}
1615 fn no_relro(&mut self) {}
1617 fn gc_sections(&mut self, _keep_metadata
: bool
) {}
1619 fn no_gc_sections(&mut self) {}
1621 fn pgo_gen(&mut self) {}
1623 fn no_crt_objects(&mut self) {}
1625 fn no_default_libraries(&mut self) {}
1627 fn control_flow_guard(&mut self) {}
1629 fn export_symbols(&mut self, _tmpdir
: &Path
, _crate_type
: CrateType
, _symbols
: &[String
]) {}
1631 fn subsystem(&mut self, _subsystem
: &str) {}
1633 fn linker_plugin_lto(&mut self) {}
1636 pub struct BpfLinker
<'a
> {
1641 impl<'a
> Linker
for BpfLinker
<'a
> {
1642 fn cmd(&mut self) -> &mut Command
{
1646 fn set_output_kind(&mut self, _output_kind
: LinkOutputKind
, _out_filename
: &Path
) {}
1648 fn link_rlib(&mut self, path
: &Path
) {
1652 fn link_whole_rlib(&mut self, path
: &Path
) {
1656 fn include_path(&mut self, path
: &Path
) {
1657 self.cmd
.arg("-L").arg(path
);
1660 fn debuginfo(&mut self, _strip
: Strip
, _
: &[PathBuf
]) {
1661 self.cmd
.arg("--debug");
1664 fn add_object(&mut self, path
: &Path
) {
1668 fn optimize(&mut self) {
1669 self.cmd
.arg(match self.sess
.opts
.optimize
{
1670 OptLevel
::No
=> "-O0",
1671 OptLevel
::Less
=> "-O1",
1672 OptLevel
::Default
=> "-O2",
1673 OptLevel
::Aggressive
=> "-O3",
1674 OptLevel
::Size
=> "-Os",
1675 OptLevel
::SizeMin
=> "-Oz",
1679 fn output_filename(&mut self, path
: &Path
) {
1680 self.cmd
.arg("-o").arg(path
);
1683 fn link_dylib(&mut self, _lib
: &str, _verbatim
: bool
, _as_needed
: bool
) {
1684 panic
!("external dylibs not supported")
1687 fn link_rust_dylib(&mut self, _lib
: &str, _path
: &Path
) {
1688 panic
!("external dylibs not supported")
1691 fn link_staticlib(&mut self, _lib
: &str, _verbatim
: bool
) {
1692 panic
!("staticlibs not supported")
1695 fn link_whole_staticlib(&mut self, _lib
: &str, _verbatim
: bool
, _search_path
: &[PathBuf
]) {
1696 panic
!("staticlibs not supported")
1699 fn framework_path(&mut self, _path
: &Path
) {
1700 panic
!("frameworks not supported")
1703 fn link_framework(&mut self, _framework
: &str, _as_needed
: bool
) {
1704 panic
!("frameworks not supported")
1707 fn full_relro(&mut self) {}
1709 fn partial_relro(&mut self) {}
1711 fn no_relro(&mut self) {}
1713 fn gc_sections(&mut self, _keep_metadata
: bool
) {}
1715 fn no_gc_sections(&mut self) {}
1717 fn pgo_gen(&mut self) {}
1719 fn no_crt_objects(&mut self) {}
1721 fn no_default_libraries(&mut self) {}
1723 fn control_flow_guard(&mut self) {}
1725 fn export_symbols(&mut self, tmpdir
: &Path
, _crate_type
: CrateType
, symbols
: &[String
]) {
1726 let path
= tmpdir
.join("symbols");
1727 let res
: io
::Result
<()> = try
{
1728 let mut f
= BufWriter
::new(File
::create(&path
)?
);
1729 for sym
in symbols
{
1730 writeln
!(f
, "{}", sym
)?
;
1733 if let Err(e
) = res
{
1734 self.sess
.fatal(&format
!("failed to write symbols file: {}", e
));
1736 self.cmd
.arg("--export-symbols").arg(&path
);
1740 fn subsystem(&mut self, _subsystem
: &str) {}
1742 fn linker_plugin_lto(&mut self) {}