}
{
- let mut linker = trans.linker_info.to_linker(&mut cmd, &sess);
+ let mut linker = trans.linker_info.to_linker(cmd, &sess);
link_args(&mut *linker, sess, crate_type, tmpdir,
objects, out_filename, outputs, trans);
+ cmd = linker.finalize();
}
cmd.args(&sess.target.target.options.late_link_args);
for obj in &sess.target.target.options.post_link_objects {
}
});
- let pair = sess.cstore.used_libraries().into_iter().filter(|l| {
+ let relevant_libs = sess.cstore.used_libraries().into_iter().filter(|l| {
relevant_lib(sess, l)
- }).partition(|lib| {
- lib.kind == NativeLibraryKind::NativeStatic
});
- let (staticlibs, others): (Vec<_>, Vec<_>) = pair;
-
- // 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 {
- // 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.name.as_str(), &search_path);
- }
-
- cmd.hint_dynamic();
-
- for lib in others {
+ for lib in relevant_libs {
match lib.kind {
NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()),
NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()),
NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()),
- NativeLibraryKind::NativeStatic => bug!(),
+ NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(),
+ &search_path)
}
}
}
}
pub fn to_linker(&'a self,
- cmd: &'a mut Command,
+ cmd: Command,
sess: &'a Session) -> Box<Linker+'a> {
if sess.target.target.options.is_like_msvc {
Box::new(MsvcLinker {
Box::new(GnuLinker {
cmd: cmd,
sess: sess,
- info: self
+ info: self,
+ hinted_static: false,
}) as Box<Linker>
}
}
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);
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
fn subsystem(&mut self, subsystem: &str);
+ // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
+ fn finalize(&mut self) -> Command;
}
pub struct GnuLinker<'a> {
- cmd: &'a mut Command,
+ cmd: Command,
sess: &'a Session,
- info: &'a LinkerInfo
+ info: &'a LinkerInfo,
+ hinted_static: bool, // Keeps track of the current hinting mode.
}
impl<'a> GnuLinker<'a> {
fn takes_hints(&self) -> bool {
!self.sess.target.target.options.is_like_osx
}
+
+ // 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.
+ fn hint_static(&mut self) {
+ if !self.takes_hints() { return }
+ if !self.hinted_static {
+ self.cmd.arg("-Wl,-Bstatic");
+ self.hinted_static = true;
+ }
+ }
+
+ fn hint_dynamic(&mut self) {
+ if !self.takes_hints() { return }
+ if self.hinted_static {
+ self.cmd.arg("-Wl,-Bdynamic");
+ self.hinted_static = false;
+ }
+ }
}
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 link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); }
+ fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); }
+ fn link_rlib(&mut self, lib: &Path) { self.hint_static(); 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 args(&mut self, args: &[String]) { self.cmd.args(args); }
fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
+ self.hint_dynamic();
self.cmd.arg("-l").arg(lib);
}
fn link_framework(&mut self, framework: &str) {
+ self.hint_dynamic();
self.cmd.arg("-framework").arg(framework);
}
+ // 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.
fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
+ self.hint_static();
let target = &self.sess.target.target;
if !target.options.is_like_osx {
self.cmd.arg("-Wl,--whole-archive")
}
fn link_whole_rlib(&mut self, lib: &Path) {
+ self.hint_static();
if self.sess.target.target.options.is_like_osx {
let mut v = OsString::from("-Wl,-force_load,");
v.push(lib);
}
}
- 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");
- }
-
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
// If we're compiling a dylib, then we let symbol visibility in object
// files to take care of whether they're exported or not.
fn subsystem(&mut self, subsystem: &str) {
self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem));
}
+
+ fn finalize(&mut self) -> Command {
+ self.hint_dynamic(); // Reset to default before returning the composed command line.
+ let mut cmd = Command::new("");
+ ::std::mem::swap(&mut cmd, &mut self.cmd);
+ cmd
+ }
}
pub struct MsvcLinker<'a> {
- cmd: &'a mut Command,
+ cmd: Command,
sess: &'a Session,
info: &'a LinkerInfo
}
self.cmd.arg("/DEBUG");
}
- fn whole_archives(&mut self) {
- // hints not supported?
- }
- fn no_whole_archives(&mut self) {
- // hints not supported?
- }
-
- // On windows static libraries are of the form `foo.lib` and dynamic
- // libraries are not linked against directly, but rather through their
- // import libraries also called `foo.lib`. As a result there's no
- // possibility for a native library to appear both dynamically and
- // statically in the same folder so we don't have to worry about hints like
- // we do on Unix platforms.
- fn hint_static(&mut self) {}
- fn hint_dynamic(&mut self) {}
-
// Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
// export symbols from a dynamic library. When building a dynamic library,
// however, we're going to want some symbols exported, so this function
self.cmd.arg("/ENTRY:mainCRTStartup");
}
}
+
+ fn finalize(&mut self) -> Command {
+ let mut cmd = Command::new("");
+ ::std::mem::swap(&mut cmd, &mut self.cmd);
+ cmd
+ }
}
pub struct EmLinker<'a> {
- cmd: &'a mut Command,
+ cmd: Command,
sess: &'a Session,
info: &'a LinkerInfo
}
bug!("building dynamic library is unsupported on Emscripten")
}
- fn whole_archives(&mut self) {
- // noop
- }
-
- fn no_whole_archives(&mut self) {
- // noop
- }
-
- fn hint_static(&mut self) {
- // noop
- }
-
- fn hint_dynamic(&mut self) {
- // noop
- }
-
fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
let symbols = &self.info.exports[&crate_type];
fn subsystem(&mut self, _subsystem: &str) {
// noop
}
+
+ fn finalize(&mut self) -> Command {
+ let mut cmd = Command::new("");
+ ::std::mem::swap(&mut cmd, &mut self.cmd);
+ cmd
+ }
}
fn exported_symbols(scx: &SharedCrateContext,