about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-05-11 14:41:27 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-05-19 10:53:06 -0700
commitaf56e2efde5cd82564e32598889d25d798c02722 (patch)
tree108dd33084ff05b73137ea05aee3ef658940ffe0
parent37659a1803e398a5e374968aee5aabe541632021 (diff)
downloadrust-af56e2efde5cd82564e32598889d25d798c02722.tar.gz
rust-af56e2efde5cd82564e32598889d25d798c02722.zip
rustc_back: Tweak the MSVC target spec
This change primarily changes the default ar utility used by MSVC-targeting
compilers as `llvm-ar`, adding comments along the way as to why.
-rw-r--r--src/librustc_back/target/mod.rs20
-rw-r--r--src/librustc_back/target/windows_msvc_base.rs38
-rw-r--r--src/librustc_back/target/x86_64_pc_windows_msvc.rs5
-rw-r--r--src/librustc_trans/back/link.rs10
4 files changed, 60 insertions, 13 deletions
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index a3cb357dc05..ceac37513ee 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -93,6 +93,8 @@ pub struct Target {
 pub struct TargetOptions {
     /// Linker to invoke. Defaults to "cc".
     pub linker: String,
+    /// Archive utility to use when managing archives. Defaults to "ar".
+    pub ar: String,
     /// Linker arguments that are unconditionally passed *before* any
     /// user-defined libraries.
     pub pre_link_args: Vec<String>,
@@ -154,22 +156,24 @@ pub struct TargetOptions {
     pub linker_is_gnu: bool,
     /// Whether the linker support rpaths or not. Defaults to false.
     pub has_rpath: bool,
-    /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM will emit references
-    /// to the functions that compiler-rt provides.
+    /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM
+    /// will emit references to the functions that compiler-rt provides.
     pub no_compiler_rt: bool,
-    /// Dynamically linked executables can be compiled as position independent if the default
-    /// relocation model of position independent code is not changed. This is a requirement to take
-    /// advantage of ASLR, as otherwise the functions in the executable are not randomized and can
-    /// be used during an exploit of a vulnerability in any code.
+    /// Dynamically linked executables can be compiled as position independent
+    /// if the default relocation model of position independent code is not
+    /// changed. This is a requirement to take advantage of ASLR, as otherwise
+    /// the functions in the executable are not randomized and can be used
+    /// during an exploit of a vulnerability in any code.
     pub position_independent_executables: bool,
 }
 
 impl Default for TargetOptions {
-    /// Create a set of "sane defaults" for any target. This is still incomplete, and if used for
-    /// compilation, will certainly not work.
+    /// Create a set of "sane defaults" for any target. This is still
+    /// incomplete, and if used for compilation, will certainly not work.
     fn default() -> TargetOptions {
         TargetOptions {
             linker: "cc".to_string(),
+            ar: "ar".to_string(),
             pre_link_args: Vec::new(),
             post_link_args: Vec::new(),
             cpu: "generic".to_string(),
diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs
index f4f25ea8569..30d74c80735 100644
--- a/src/librustc_back/target/windows_msvc_base.rs
+++ b/src/librustc_back/target/windows_msvc_base.rs
@@ -14,7 +14,38 @@ use std::default::Default;
 pub fn opts() -> TargetOptions {
     TargetOptions {
         function_sections: true,
-        linker: "link".to_string(),
+        linker: "link.exe".to_string(),
+        // When taking a look at the value of this `ar` field, one might expect
+        // `lib.exe` to be the value here! The `lib.exe` program is the default
+        // tool for managing `.lib` archives on Windows, but unfortunately the
+        // compiler cannot use it.
+        //
+        // To recap, we use `ar` here to manage rlibs (which are just archives).
+        // LLVM does not expose bindings for modifying archives so we have to
+        // invoke this utility for write operations (e.g. deleting files, adding
+        // files, etc). Normally archives only have object files within them,
+        // but the compiler also uses archives for storing metadata and
+        // compressed bytecode, so we don't exactly fall within "normal use
+        // cases".
+        //
+        // MSVC's `lib.exe` tool by default will choke when adding a non-object
+        // file to an archive, which we do on a regular basis, making it
+        // inoperable for us. Luckily, however, LLVM has already rewritten `ar`
+        // in the form of `llvm-ar` which is built by default when we build
+        // LLVM. This tool, unlike `lib.exe`, works just fine with non-object
+        // files, so we use it instead.
+        //
+        // Note that there's a few caveats associated with this:
+        //
+        // * This still requires that the *linker* (the consumer of rlibs) will
+        //   ignore non-object files. Thankfully `link.exe` on Windows does
+        //   indeed ignore non-object files in archives.
+        // * This requires `llvm-ar.exe` to be distributed with the compiler
+        //   itself, but we already make sure of this elsewhere.
+        //
+        // Perhaps one day we won't even need this tool at all and we'll just be
+        // able to make library calls into LLVM!
+        ar: "llvm-ar.exe".to_string(),
         dynamic_linking: true,
         executables: true,
         dll_prefix: "".to_string(),
@@ -25,7 +56,10 @@ pub fn opts() -> TargetOptions {
         morestack: false,
         is_like_windows: true,
         is_like_msvc: true,
-        pre_link_args: Vec::new(),
+        pre_link_args: vec![
+            "/NOLOGO".to_string(),
+            "/NXCOMPAT".to_string(),
+        ],
 
         .. Default::default()
     }
diff --git a/src/librustc_back/target/x86_64_pc_windows_msvc.rs b/src/librustc_back/target/x86_64_pc_windows_msvc.rs
index aac1afbb97c..f7c3ca4b3f6 100644
--- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs
+++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs
@@ -15,7 +15,10 @@ pub fn target() -> Target {
     base.cpu = "x86-64".to_string();
 
     Target {
-        // FIXME: Test this. Copied from linux (#2398)
+        // This is currently in sync with the specification for
+        // x86_64-pc-windows-gnu but there's a comment in that file questioning
+        // whether this is valid or not. Sounds like the two should stay in sync
+        // at least for now.
         data_layout: "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-\
                       f32:32:32-f64:64:64-v64:64:64-v128:128:128-a:0:64-\
                       s0:64:64-f80:128:128-n8:16:32:64-S128".to_string(),
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index e748f8b44cb..c6a59ff30a6 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -365,6 +365,12 @@ pub fn get_cc_prog(sess: &Session) -> String {
     }
 }
 
+pub fn get_ar_prog(sess: &Session) -> String {
+    sess.opts.cg.ar.clone().unwrap_or_else(|| {
+        sess.target.target.options.ar.clone()
+    })
+}
+
 pub fn remove(sess: &Session, path: &Path) {
     match fs::remove_file(path) {
         Ok(..) => {}
@@ -547,7 +553,7 @@ fn link_rlib<'a>(sess: &'a Session,
         lib_search_paths: archive_search_paths(sess),
         slib_prefix: sess.target.target.options.staticlib_prefix.clone(),
         slib_suffix: sess.target.target.options.staticlib_suffix.clone(),
-        maybe_ar_prog: sess.opts.cg.ar.clone()
+        ar_prog: get_ar_prog(sess),
     };
     let mut ab = ArchiveBuilder::create(config);
     ab.add_file(obj_filename).unwrap();
@@ -1181,7 +1187,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
                     lib_search_paths: archive_search_paths(sess),
                     slib_prefix: sess.target.target.options.staticlib_prefix.clone(),
                     slib_suffix: sess.target.target.options.staticlib_suffix.clone(),
-                    maybe_ar_prog: sess.opts.cg.ar.clone()
+                    ar_prog: get_ar_prog(sess),
                 };
                 let mut archive = Archive::open(config);
                 archive.remove_file(&format!("{}.o", name));