rustc_trans: Abstract linker support behind a trait
This trait will be used to correctly build a command line for link.exe with MSVC and may perhaps one day be used to generate a command line for `lld`, but this commit currently just refactors the bindings used to call `ld`.
This commit is contained in:
parent
4cc025d83c
commit
2d5e5777fd
3 changed files with 237 additions and 142 deletions
|
|
@ -9,9 +9,9 @@
|
|||
// except according to those terms.
|
||||
|
||||
use super::archive::{Archive, ArchiveBuilder, ArchiveConfig, METADATA_FILENAME};
|
||||
use super::archive;
|
||||
use super::rpath;
|
||||
use super::linker::{Linker, GnuLinker};
|
||||
use super::rpath::RPathConfig;
|
||||
use super::rpath;
|
||||
use super::svh::Svh;
|
||||
use session::config;
|
||||
use session::config::NoDebugInfo;
|
||||
|
|
@ -29,7 +29,6 @@ use util::sha2::{Digest, Sha256};
|
|||
use util::fs::fix_windows_verbatim_for_gcc;
|
||||
use rustc_back::tempdir::TempDir;
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{self, PathExt};
|
||||
use std::io::{self, Read, Write};
|
||||
use std::mem;
|
||||
|
|
@ -801,10 +800,13 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
|
|||
cmd.arg(root.join(obj));
|
||||
}
|
||||
|
||||
link_args(&mut cmd, sess, dylib, tmpdir.path(),
|
||||
trans, obj_filename, out_filename);
|
||||
if !sess.target.target.options.no_compiler_rt {
|
||||
cmd.arg("-lcompiler-rt");
|
||||
{
|
||||
let mut linker = GnuLinker { cmd: &mut cmd, sess: &sess };
|
||||
link_args(&mut linker, sess, dylib, tmpdir.path(),
|
||||
trans, obj_filename, out_filename);
|
||||
if !sess.target.target.options.no_compiler_rt {
|
||||
linker.link_staticlib("compiler-rt");
|
||||
}
|
||||
}
|
||||
for obj in &sess.target.target.options.post_link_objects {
|
||||
cmd.arg(root.join(obj));
|
||||
|
|
@ -858,7 +860,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
|
|||
}
|
||||
}
|
||||
|
||||
fn link_args(cmd: &mut Command,
|
||||
fn link_args(cmd: &mut Linker,
|
||||
sess: &Session,
|
||||
dylib: bool,
|
||||
tmpdir: &Path,
|
||||
|
|
@ -873,10 +875,10 @@ fn link_args(cmd: &mut Command,
|
|||
// target descriptor
|
||||
let t = &sess.target.target;
|
||||
|
||||
cmd.arg("-L").arg(&fix_windows_verbatim_for_gcc(&lib_path));
|
||||
|
||||
cmd.arg("-o").arg(out_filename).arg(obj_filename);
|
||||
cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path));
|
||||
|
||||
cmd.output_filename(out_filename);
|
||||
cmd.add_object(obj_filename);
|
||||
|
||||
// Stack growth requires statically linking a __morestack function. Note
|
||||
// that this is listed *before* all other libraries. Due to the usage of the
|
||||
|
|
@ -895,89 +897,44 @@ fn link_args(cmd: &mut Command,
|
|||
// will include the __morestack symbol 100% of the time, always resolving
|
||||
// references to it even if the object above didn't use it.
|
||||
if t.options.morestack {
|
||||
if t.options.is_like_osx {
|
||||
let morestack = lib_path.join("libmorestack.a");
|
||||
|
||||
let mut v = OsString::from("-Wl,-force_load,");
|
||||
v.push(&morestack);
|
||||
cmd.arg(&v);
|
||||
} else {
|
||||
cmd.args(&["-Wl,--whole-archive", "-lmorestack", "-Wl,--no-whole-archive"]);
|
||||
}
|
||||
cmd.link_whole_staticlib("morestack", &[lib_path]);
|
||||
}
|
||||
|
||||
// When linking a dynamic library, we put the metadata into a section of the
|
||||
// executable. This metadata is in a separate object file from the main
|
||||
// object file, so we link that in here.
|
||||
if dylib {
|
||||
cmd.arg(&obj_filename.with_extension("metadata.o"));
|
||||
cmd.add_object(&obj_filename.with_extension("metadata.o"));
|
||||
}
|
||||
|
||||
if t.options.is_like_osx {
|
||||
// The dead_strip option to the linker specifies that functions and data
|
||||
// unreachable by the entry point will be removed. This is quite useful
|
||||
// with Rust's compilation model of compiling libraries at a time into
|
||||
// one object file. For example, this brings hello world from 1.7MB to
|
||||
// 458K.
|
||||
//
|
||||
// Note that this is done for both executables and dynamic libraries. We
|
||||
// won't get much benefit from dylibs because LLVM will have already
|
||||
// stripped away as much as it could. This has not been seen to impact
|
||||
// link times negatively.
|
||||
//
|
||||
// -dead_strip can't be part of the pre_link_args because it's also used
|
||||
// for partial linking when using multiple codegen units (-r). So we
|
||||
// insert it here.
|
||||
cmd.arg("-Wl,-dead_strip");
|
||||
}
|
||||
|
||||
// If we're building a dylib, we don't use --gc-sections because LLVM has
|
||||
// already done the best it can do, and we also don't want to eliminate the
|
||||
// metadata. If we're building an executable, however, --gc-sections drops
|
||||
// the size of hello world from 1.8MB to 597K, a 67% reduction.
|
||||
if !dylib && !t.options.is_like_osx {
|
||||
cmd.arg("-Wl,--gc-sections");
|
||||
}
|
||||
// Try to strip as much out of the generated object by removing unused
|
||||
// sections if possible. See more comments in linker.rs
|
||||
cmd.gc_sections(dylib);
|
||||
|
||||
let used_link_args = sess.cstore.get_used_link_args().borrow();
|
||||
|
||||
if t.options.position_independent_executables {
|
||||
if !dylib && t.options.position_independent_executables {
|
||||
let empty_vec = Vec::new();
|
||||
let empty_str = String::new();
|
||||
let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
|
||||
let mut args = args.iter().chain(used_link_args.iter());
|
||||
if !dylib
|
||||
&& (t.options.relocation_model == "pic"
|
||||
|| *sess.opts.cg.relocation_model.as_ref()
|
||||
.unwrap_or(&empty_str) == "pic")
|
||||
let relocation_model = sess.opts.cg.relocation_model.as_ref()
|
||||
.unwrap_or(&empty_str);
|
||||
if (t.options.relocation_model == "pic" || *relocation_model == "pic")
|
||||
&& !args.any(|x| *x == "-static") {
|
||||
cmd.arg("-pie");
|
||||
cmd.position_independent_executable();
|
||||
}
|
||||
}
|
||||
|
||||
if t.options.linker_is_gnu {
|
||||
// GNU-style linkers support optimization with -O. GNU ld doesn't need a
|
||||
// numeric argument, but other linkers do.
|
||||
if sess.opts.optimize == config::Default ||
|
||||
sess.opts.optimize == config::Aggressive {
|
||||
cmd.arg("-Wl,-O1");
|
||||
}
|
||||
}
|
||||
// Pass optimization flags down to the linker.
|
||||
cmd.optimize();
|
||||
|
||||
// We want to prevent the compiler from accidentally leaking in any system
|
||||
// libraries, so we explicitly ask gcc to not link to any libraries by
|
||||
// default. Note that this does not happen for windows because windows pulls
|
||||
// in some large number of libraries and I couldn't quite figure out which
|
||||
// subset we wanted.
|
||||
if !t.options.is_like_windows {
|
||||
cmd.arg("-nodefaultlibs");
|
||||
}
|
||||
|
||||
// Mark all dynamic libraries and executables as compatible with ASLR
|
||||
// FIXME #17098: ASLR breaks gdb
|
||||
if t.options.is_like_windows && sess.opts.debuginfo == NoDebugInfo {
|
||||
// cmd.arg("-Wl,--dynamicbase");
|
||||
}
|
||||
cmd.no_default_libraries();
|
||||
|
||||
// Take careful note of the ordering of the arguments we pass to the linker
|
||||
// here. Linkers will assume that things on the left depend on things to the
|
||||
|
|
@ -1019,18 +976,7 @@ fn link_args(cmd: &mut Command,
|
|||
// # Telling the linker what we're doing
|
||||
|
||||
if dylib {
|
||||
// On mac we need to tell the linker to let this library be rpathed
|
||||
if sess.target.target.options.is_like_osx {
|
||||
cmd.args(&["-dynamiclib", "-Wl,-dylib"]);
|
||||
|
||||
if sess.opts.cg.rpath {
|
||||
let mut v = OsString::from("-Wl,-install_name,@rpath/");
|
||||
v.push(out_filename.file_name().unwrap());
|
||||
cmd.arg(&v);
|
||||
}
|
||||
} else {
|
||||
cmd.arg("-shared");
|
||||
}
|
||||
cmd.build_dylib(out_filename);
|
||||
}
|
||||
|
||||
// FIXME (#2397): At some point we want to rpath our guesses as to
|
||||
|
|
@ -1059,9 +1005,10 @@ fn link_args(cmd: &mut Command,
|
|||
|
||||
// Finally add all the linker arguments provided on the command line along
|
||||
// with any #[link_args] attributes found inside the crate
|
||||
let empty = Vec::new();
|
||||
cmd.args(&sess.opts.cg.link_args.as_ref().unwrap_or(&empty));
|
||||
cmd.args(&used_link_args[..]);
|
||||
if let Some(ref args) = sess.opts.cg.link_args {
|
||||
cmd.args(args);
|
||||
}
|
||||
cmd.args(&used_link_args);
|
||||
}
|
||||
|
||||
// # Native library linking
|
||||
|
|
@ -1075,21 +1022,15 @@ fn link_args(cmd: &mut Command,
|
|||
// Also note that the native libraries linked here are only the ones located
|
||||
// in the current crate. Upstream crates with native library dependencies
|
||||
// may have their native library pulled in above.
|
||||
fn add_local_native_libraries(cmd: &mut Command, sess: &Session) {
|
||||
fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
|
||||
sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, k| {
|
||||
match k {
|
||||
PathKind::Framework => { cmd.arg("-F").arg(path); }
|
||||
_ => { cmd.arg("-L").arg(&fix_windows_verbatim_for_gcc(path)); }
|
||||
PathKind::Framework => { cmd.framework_path(path); }
|
||||
_ => { cmd.include_path(&fix_windows_verbatim_for_gcc(path)); }
|
||||
}
|
||||
FileDoesntMatch
|
||||
});
|
||||
|
||||
// Some platforms take hints about whether a library is static or dynamic.
|
||||
// For those that support this, we ensure we pass the option if the library
|
||||
// was flagged "static" (most defaults are dynamic) to ensure that if
|
||||
// libfoo.a and libfoo.so both exist that the right one is chosen.
|
||||
let takes_hints = !sess.target.target.options.is_like_osx;
|
||||
|
||||
let libs = sess.cstore.get_used_libraries();
|
||||
let libs = libs.borrow();
|
||||
|
||||
|
|
@ -1100,46 +1041,29 @@ fn add_local_native_libraries(cmd: &mut Command, sess: &Session) {
|
|||
kind != cstore::NativeStatic
|
||||
});
|
||||
|
||||
// Platforms that take hints generally also support the --whole-archive
|
||||
// flag. We need to pass this flag when linking static native libraries to
|
||||
// ensure the entire library is included.
|
||||
//
|
||||
// For more details see #15460, but the gist is that the linker will strip
|
||||
// away any unused objects in the archive if we don't otherwise explicitly
|
||||
// reference them. This can occur for libraries which are just providing
|
||||
// bindings, libraries with generic functions, etc.
|
||||
if takes_hints {
|
||||
cmd.arg("-Wl,--whole-archive").arg("-Wl,-Bstatic");
|
||||
}
|
||||
// Some platforms take hints about whether a library is static or dynamic.
|
||||
// For those that support this, we ensure we pass the option if the library
|
||||
// was flagged "static" (most defaults are dynamic) to ensure that if
|
||||
// libfoo.a and libfoo.so both exist that the right one is chosen.
|
||||
cmd.hint_static();
|
||||
|
||||
let search_path = archive_search_paths(sess);
|
||||
for l in staticlibs {
|
||||
if takes_hints {
|
||||
cmd.arg(&format!("-l{}", l));
|
||||
} else {
|
||||
// -force_load is the OSX equivalent of --whole-archive, but it
|
||||
// involves passing the full path to the library to link.
|
||||
let lib = archive::find_library(&l[..],
|
||||
&sess.target.target.options.staticlib_prefix,
|
||||
&sess.target.target.options.staticlib_suffix,
|
||||
&search_path[..],
|
||||
&sess.diagnostic().handler);
|
||||
let mut v = OsString::from("-Wl,-force_load,");
|
||||
v.push(&lib);
|
||||
cmd.arg(&v);
|
||||
}
|
||||
}
|
||||
if takes_hints {
|
||||
cmd.arg("-Wl,--no-whole-archive").arg("-Wl,-Bdynamic");
|
||||
// Here we explicitly ask that the entire archive is included into the
|
||||
// result artifact. For more details see #15460, but the gist is that
|
||||
// the linker will strip away any unused objects in the archive if we
|
||||
// don't otherwise explicitly reference them. This can occur for
|
||||
// libraries which are just providing bindings, libraries with generic
|
||||
// functions, etc.
|
||||
cmd.link_whole_staticlib(l, &search_path);
|
||||
}
|
||||
|
||||
cmd.hint_dynamic();
|
||||
|
||||
for &(ref l, kind) in others {
|
||||
match kind {
|
||||
cstore::NativeUnknown => {
|
||||
cmd.arg(&format!("-l{}", l));
|
||||
}
|
||||
cstore::NativeFramework => {
|
||||
cmd.arg("-framework").arg(&l[..]);
|
||||
}
|
||||
cstore::NativeUnknown => cmd.link_dylib(l),
|
||||
cstore::NativeFramework => cmd.link_framework(l),
|
||||
cstore::NativeStatic => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
@ -1150,7 +1074,7 @@ fn add_local_native_libraries(cmd: &mut Command, sess: &Session) {
|
|||
// Rust crates are not considered at all when creating an rlib output. All
|
||||
// dependencies will be linked when producing the final output (instead of
|
||||
// the intermediate rlib version)
|
||||
fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
|
||||
fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
|
||||
dylib: bool, tmpdir: &Path,
|
||||
trans: &CrateTranslation) {
|
||||
// All of the heavy lifting has previously been accomplished by the
|
||||
|
|
@ -1201,7 +1125,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
|
|||
}
|
||||
|
||||
// Adds the static "rlib" versions of all crates to the command line.
|
||||
fn add_static_crate(cmd: &mut Command, sess: &Session, tmpdir: &Path,
|
||||
fn add_static_crate(cmd: &mut Linker, sess: &Session, tmpdir: &Path,
|
||||
cratepath: &Path) {
|
||||
// When performing LTO on an executable output, all of the
|
||||
// bytecode from the upstream libraries has already been
|
||||
|
|
@ -1263,16 +1187,16 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
|
|||
archive.remove_file(&format!("{}.o", name));
|
||||
let files = archive.files();
|
||||
if files.iter().any(|s| s.ends_with(".o")) {
|
||||
cmd.arg(&dst);
|
||||
cmd.link_rlib(&dst);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cmd.arg(&fix_windows_verbatim_for_gcc(cratepath));
|
||||
cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
|
||||
}
|
||||
}
|
||||
|
||||
// Same thing as above, but for dynamic crates instead of static crates.
|
||||
fn add_dynamic_crate(cmd: &mut Command, sess: &Session, cratepath: &Path) {
|
||||
fn add_dynamic_crate(cmd: &mut Linker, sess: &Session, cratepath: &Path) {
|
||||
// If we're performing LTO, then it should have been previously required
|
||||
// that all upstream rust dependencies were available in an rlib format.
|
||||
assert!(!sess.lto());
|
||||
|
|
@ -1280,10 +1204,10 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
|
|||
// Just need to tell the linker about where the library lives and
|
||||
// what its name is
|
||||
if let Some(dir) = cratepath.parent() {
|
||||
cmd.arg("-L").arg(&fix_windows_verbatim_for_gcc(dir));
|
||||
cmd.include_path(&fix_windows_verbatim_for_gcc(dir));
|
||||
}
|
||||
let filestem = cratepath.file_stem().unwrap().to_str().unwrap();
|
||||
cmd.arg(&format!("-l{}", unlib(&sess.target, filestem)));
|
||||
cmd.link_dylib(&unlib(&sess.target, filestem));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1305,7 +1229,7 @@ fn add_upstream_rust_crates(cmd: &mut Command, sess: &Session,
|
|||
// generic function calls a native function, then the generic function must
|
||||
// be instantiated in the target crate, meaning that the native symbol must
|
||||
// also be resolved in the target crate.
|
||||
fn add_upstream_native_libraries(cmd: &mut Command, sess: &Session) {
|
||||
fn add_upstream_native_libraries(cmd: &mut Linker, sess: &Session) {
|
||||
// Be sure to use a topological sorting of crates because there may be
|
||||
// interdependencies between native libraries. When passing -nodefaultlibs,
|
||||
// for example, almost all native libraries depend on libc, so we have to
|
||||
|
|
@ -1320,13 +1244,8 @@ fn add_upstream_native_libraries(cmd: &mut Command, sess: &Session) {
|
|||
let libs = csearch::get_native_libraries(&sess.cstore, cnum);
|
||||
for &(kind, ref lib) in &libs {
|
||||
match kind {
|
||||
cstore::NativeUnknown => {
|
||||
cmd.arg(&format!("-l{}", *lib));
|
||||
}
|
||||
cstore::NativeFramework => {
|
||||
cmd.arg("-framework");
|
||||
cmd.arg(&lib[..]);
|
||||
}
|
||||
cstore::NativeUnknown => cmd.link_dylib(lib),
|
||||
cstore::NativeFramework => cmd.link_framework(lib),
|
||||
cstore::NativeStatic => {
|
||||
sess.bug("statics shouldn't be propagated");
|
||||
}
|
||||
|
|
|
|||
175
src/librustc_trans/back/linker.rs
Normal file
175
src/librustc_trans/back/linker.rs
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::ffi::OsString;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use rustc_back::archive;
|
||||
use session::Session;
|
||||
use session::config;
|
||||
|
||||
/// Linker abstraction used by back::link to build up the command to invoke a
|
||||
/// linker.
|
||||
///
|
||||
/// This trait is the total list of requirements needed by `back::link` and
|
||||
/// represents the meaning of each option being passed down. This trait is then
|
||||
/// used to dispatch on whether a GNU-like linker (generally `ld.exe`) or an
|
||||
/// MSVC linker (e.g. `link.exe`) is being used.
|
||||
pub trait Linker {
|
||||
fn link_dylib(&mut self, lib: &str);
|
||||
fn link_framework(&mut self, framework: &str);
|
||||
fn link_staticlib(&mut self, lib: &str);
|
||||
fn link_rlib(&mut self, lib: &Path);
|
||||
fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]);
|
||||
fn include_path(&mut self, path: &Path);
|
||||
fn framework_path(&mut self, path: &Path);
|
||||
fn output_filename(&mut self, path: &Path);
|
||||
fn add_object(&mut self, path: &Path);
|
||||
fn gc_sections(&mut self, is_dylib: bool);
|
||||
fn position_independent_executable(&mut self);
|
||||
fn optimize(&mut self);
|
||||
fn no_default_libraries(&mut self);
|
||||
fn build_dylib(&mut self, out_filename: &Path);
|
||||
fn args(&mut self, args: &[String]);
|
||||
fn hint_static(&mut self);
|
||||
fn hint_dynamic(&mut self);
|
||||
fn whole_archives(&mut self);
|
||||
fn no_whole_archives(&mut self);
|
||||
}
|
||||
|
||||
pub struct GnuLinker<'a> {
|
||||
pub cmd: &'a mut Command,
|
||||
pub sess: &'a Session,
|
||||
}
|
||||
|
||||
impl<'a> GnuLinker<'a> {
|
||||
fn takes_hints(&self) -> bool {
|
||||
!self.sess.target.target.options.is_like_osx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Linker for GnuLinker<'a> {
|
||||
fn link_dylib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); }
|
||||
fn link_staticlib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); }
|
||||
fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
|
||||
fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); }
|
||||
fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); }
|
||||
fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
|
||||
fn add_object(&mut self, path: &Path) { self.cmd.arg(path); }
|
||||
fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); }
|
||||
fn args(&mut self, args: &[String]) { self.cmd.args(args); }
|
||||
|
||||
fn link_framework(&mut self, framework: &str) {
|
||||
self.cmd.arg("-framework").arg(framework);
|
||||
}
|
||||
|
||||
fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
|
||||
let target = &self.sess.target.target;
|
||||
if !target.options.is_like_osx {
|
||||
self.cmd.arg("-Wl,--whole-archive")
|
||||
.arg("-l").arg(lib)
|
||||
.arg("-Wl,--no-whole-archive");
|
||||
} else {
|
||||
// -force_load is the OSX equivalent of --whole-archive, but it
|
||||
// involves passing the full path to the library to link.
|
||||
let mut v = OsString::from("-Wl,-force_load,");
|
||||
v.push(&archive::find_library(lib,
|
||||
&target.options.staticlib_prefix,
|
||||
&target.options.staticlib_suffix,
|
||||
search_path,
|
||||
&self.sess.diagnostic().handler));
|
||||
self.cmd.arg(&v);
|
||||
}
|
||||
}
|
||||
|
||||
fn gc_sections(&mut self, is_dylib: bool) {
|
||||
// The dead_strip option to the linker specifies that functions and data
|
||||
// unreachable by the entry point will be removed. This is quite useful
|
||||
// with Rust's compilation model of compiling libraries at a time into
|
||||
// one object file. For example, this brings hello world from 1.7MB to
|
||||
// 458K.
|
||||
//
|
||||
// Note that this is done for both executables and dynamic libraries. We
|
||||
// won't get much benefit from dylibs because LLVM will have already
|
||||
// stripped away as much as it could. This has not been seen to impact
|
||||
// link times negatively.
|
||||
//
|
||||
// -dead_strip can't be part of the pre_link_args because it's also used
|
||||
// for partial linking when using multiple codegen units (-r). So we
|
||||
// insert it here.
|
||||
if self.sess.target.target.options.is_like_osx {
|
||||
self.cmd.arg("-Wl,-dead_strip");
|
||||
|
||||
// If we're building a dylib, we don't use --gc-sections because LLVM
|
||||
// has already done the best it can do, and we also don't want to
|
||||
// eliminate the metadata. If we're building an executable, however,
|
||||
// --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
|
||||
// reduction.
|
||||
} else if !is_dylib {
|
||||
self.cmd.arg("-Wl,--gc-sections");
|
||||
}
|
||||
}
|
||||
|
||||
fn optimize(&mut self) {
|
||||
if !self.sess.target.target.options.linker_is_gnu { return }
|
||||
|
||||
// GNU-style linkers support optimization with -O. GNU ld doesn't
|
||||
// need a numeric argument, but other linkers do.
|
||||
if self.sess.opts.optimize == config::Default ||
|
||||
self.sess.opts.optimize == config::Aggressive {
|
||||
self.cmd.arg("-Wl,-O1");
|
||||
}
|
||||
}
|
||||
|
||||
fn no_default_libraries(&mut self) {
|
||||
// Unfortunately right now passing -nodefaultlibs to gcc on windows
|
||||
// doesn't work so hot (in terms of native dependencies). This if
|
||||
// statement should hopefully be removed one day though!
|
||||
if !self.sess.target.target.options.is_like_windows {
|
||||
self.cmd.arg("-nodefaultlibs");
|
||||
}
|
||||
}
|
||||
|
||||
fn build_dylib(&mut self, out_filename: &Path) {
|
||||
// On mac we need to tell the linker to let this library be rpathed
|
||||
if self.sess.target.target.options.is_like_osx {
|
||||
self.cmd.args(&["-dynamiclib", "-Wl,-dylib"]);
|
||||
|
||||
if self.sess.opts.cg.rpath {
|
||||
let mut v = OsString::from("-Wl,-install_name,@rpath/");
|
||||
v.push(out_filename.file_name().unwrap());
|
||||
self.cmd.arg(&v);
|
||||
}
|
||||
} else {
|
||||
self.cmd.arg("-shared");
|
||||
}
|
||||
}
|
||||
|
||||
fn whole_archives(&mut self) {
|
||||
if !self.takes_hints() { return }
|
||||
self.cmd.arg("-Wl,--whole-archive");
|
||||
}
|
||||
|
||||
fn no_whole_archives(&mut self) {
|
||||
if !self.takes_hints() { return }
|
||||
self.cmd.arg("-Wl,--no-whole-archive");
|
||||
}
|
||||
|
||||
fn hint_static(&mut self) {
|
||||
if !self.takes_hints() { return }
|
||||
self.cmd.arg("-Wl,-Bstatic");
|
||||
}
|
||||
|
||||
fn hint_dynamic(&mut self) {
|
||||
if !self.takes_hints() { return }
|
||||
self.cmd.arg("-Wl,-Bdynamic");
|
||||
}
|
||||
}
|
||||
|
|
@ -74,6 +74,7 @@ pub mod back {
|
|||
pub use rustc_back::x86;
|
||||
pub use rustc_back::x86_64;
|
||||
|
||||
pub mod linker;
|
||||
pub mod link;
|
||||
pub mod lto;
|
||||
pub mod write;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue