From: Shiz <hi@shiz.me>
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);
