From: Shiz Date: Fri, 21 Apr 2017 01:04:46 +0200 Subject: [PATCH] Support fully static linking on *nix targets It adds the proper linker argument for static result objects to `Linker` and implements them for `GnuLinker` and `MsvcLinker`. Additionally, when statically linking, all the objects are linked in a group (-Wl,-( and -Wl,-) on GNU-compatible linkers) to resolve dependency and order issues that may normally arise. For `MsvcLinker`, this is a no-op as it already exhibits this behavior by default. Finally, if no linking preference is given for native libraries (`NativeLibraryKind::NativeUnknown`), they are linked statically if full static linking is requested, instead of dynamically as before. --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -951,17 +951,12 @@ // list can't depend on items higher up in the list. For example nothing can // depend on what we just generated (e.g. that'd be a circular dependency). // Upstream rust libraries are not allowed to depend on our local native - // libraries as that would violate the structure of the DAG, in that - // scenario they are required to link to them as well in a shared fashion. - // - // Note that upstream rust libraries may contain native dependencies as - // well, but they also can't depend on what we just started to add to the - // link line. And finally upstream native libraries can't depend on anything - // in this DAG so far because they're only dylibs and dylibs can only depend - // on other dylibs (e.g. other native deps). + // libraries as that would violate the structure of the DAG. + cmd.start_group(); add_local_native_libraries(cmd, sess, trans); add_upstream_rust_crates(cmd, sess, trans, crate_type, tmpdir); add_upstream_native_libraries(cmd, sess, trans, crate_type); + cmd.end_group(); // # Telling the linker what we're doing @@ -983,13 +983,13 @@ let relevant_libs = sess.cstore.used_libraries().into_iter().filter(|l| { relevant_lib(sess, l) }); let search_path = archive_search_paths(sess); for lib in relevant_libs { match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), + NativeLibraryKind::NativeUnknown => if sess.crt_static() { cmd.link_staticlib(&lib.name.as_str()) } else { 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 => cmd.link_whole_staticlib(&lib.name.as_str(), &search_path) } --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -116,6 +116,8 @@ pub trait Linker { 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; + fn start_group(&mut self); + fn end_group(&mut self); } pub struct GccLinker<'a> { @@ -178,6 +180,8 @@ impl<'a> Linker for GccLinker<'a> { 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 start_group(&mut self) { self.cmd.arg("-Wl,-("); } + fn end_group(&mut self) { self.cmd.arg("-Wl,-)"); } fn partial_relro(&mut self) { self.linker_arg("-z,relro"); } fn full_relro(&mut self) { self.linker_arg("-z,relro,-z,now"); } fn build_static_executable(&mut self) { self.cmd.arg("-static"); } @@ -577,6 +581,15 @@ impl<'a> Linker for MsvcLinker<'a> { } } + + fn start_group(&mut self) { + // Not needed + } + + fn end_group(&mut self) { + // Not needed + } + fn finalize(&mut self) -> Command { let mut cmd = Command::new(""); ::std::mem::swap(&mut cmd, &mut self.cmd); @@ -727,6 +740,14 @@ impl<'a> Linker for EmLinker<'a> { // noop } + fn start_group(&mut self) { + self.cmd.arg("-Wl,-("); + } + + fn end_group(&mut self) { + self.cmd.arg("-Wl,-)"); + } + fn finalize(&mut self) -> Command { let mut cmd = Command::new(""); ::std::mem::swap(&mut cmd, &mut self.cmd);