]> git.lizzy.rs Git - rust.git/commitdiff
try to infer linker flavor from linker name and vice versa
authorJorge Aparicio <jorge@japaric.io>
Fri, 6 Jul 2018 05:41:42 +0000 (00:41 -0500)
committerJorge Aparicio <jorge@japaric.io>
Thu, 9 Aug 2018 21:08:36 +0000 (16:08 -0500)
src/librustc/session/mod.rs
src/librustc_codegen_llvm/back/link.rs
src/librustc_codegen_llvm/back/linker.rs
src/librustc_codegen_llvm/back/write.rs

index 9a3ce50fcbdce90afe83140e8a1d03e178b19b6a..58df8f336be9606872b66e77d6307bf916aa1fce 100644 (file)
@@ -42,7 +42,7 @@
 use syntax_pos::{MultiSpan, Span};
 use util::profiling::SelfProfiler;
 
-use rustc_target::spec::{LinkerFlavor, PanicStrategy};
+use rustc_target::spec::PanicStrategy;
 use rustc_target::spec::{Target, TargetTriple};
 use rustc_data_structures::flock;
 use jobserver::Client;
@@ -607,13 +607,6 @@ pub fn panic_strategy(&self) -> PanicStrategy {
             .panic
             .unwrap_or(self.target.target.options.panic_strategy)
     }
-    pub fn linker_flavor(&self) -> LinkerFlavor {
-        self.opts
-            .debugging_opts
-            .linker_flavor
-            .unwrap_or(self.target.target.linker_flavor)
-    }
-
     pub fn fewer_names(&self) -> bool {
         let more_names = self.opts
             .output_types
index 50d41d76986fbc4c6c4e2918b37d7591fdebc469..0317dead6c0d6e7a5aed73b19f6393cdc41155e6 100644 (file)
@@ -60,7 +60,7 @@
 // The third parameter is for env vars, used on windows to set up the
 // path for MSVC to find its DLLs, and gcc to find its bundled
 // toolchain
-pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
+pub fn get_linker(sess: &Session, linker: &Path, flavor: LinkerFlavor) -> (PathBuf, Command) {
     // If our linker looks like a batch script on Windows then to execute this
     // we'll need to spawn `cmd` explicitly. This is primarily done to handle
     // emscripten where the linker is `emcc.bat` and needs to be spawned as
@@ -69,36 +69,21 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
     // This worked historically but is needed manually since #42436 (regression
     // was tagged as #42791) and some more info can be found on #44443 for
     // emscripten itself.
-    let cmd = |linker: &Path| {
+    let mut cmd = (|| {
         if let Some(linker) = linker.to_str() {
             if cfg!(windows) && linker.ends_with(".bat") {
                 return Command::bat_script(linker)
             }
         }
-        match sess.linker_flavor() {
+        match flavor {
             LinkerFlavor::Lld(f) => Command::lld(linker, f),
             _ => Command::new(linker),
 
         }
-    };
+    })();
 
     let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe");
 
-    let linker_path = sess.opts.cg.linker.as_ref().map(|s| &**s)
-        .or(sess.target.target.options.linker.as_ref().map(|s| s.as_ref()))
-        .unwrap_or(match sess.linker_flavor() {
-            LinkerFlavor::Msvc => {
-                msvc_tool.as_ref().map(|t| t.path()).unwrap_or("link.exe".as_ref())
-            }
-            LinkerFlavor::Em if cfg!(windows) => "emcc.bat".as_ref(),
-            LinkerFlavor::Em => "emcc".as_ref(),
-            LinkerFlavor::Gcc => "cc".as_ref(),
-            LinkerFlavor::Ld => "ld".as_ref(),
-            LinkerFlavor::Lld(_) => "lld".as_ref(),
-        });
-
-    let mut cmd = cmd(linker_path);
-
     // The compiler's sysroot often has some bundled tools, so add it to the
     // PATH for the child.
     let mut new_path = sess.host_filesearch(PathKind::All)
@@ -125,7 +110,7 @@ pub fn get_linker(sess: &Session) -> (PathBuf, Command) {
     }
     cmd.env("PATH", env::join_paths(new_path).unwrap());
 
-    (linker_path.to_path_buf(), cmd)
+    (linker.to_path_buf(), cmd)
 }
 
 pub fn remove(sess: &Session, path: &Path) {
@@ -615,6 +600,71 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) {
     }
 }
 
+pub fn linker_and_flavor(sess: &Session) -> Result<(PathBuf, LinkerFlavor), ()> {
+    fn from<F>(
+        sess: &Session,
+        linker: Option<PathBuf>,
+        flavor: Option<LinkerFlavor>,
+        otherwise: F,
+    ) -> Result<(PathBuf, LinkerFlavor), ()>
+    where
+        F: FnOnce() -> Result<(PathBuf, LinkerFlavor), ()>
+    {
+        match (linker, flavor) {
+            (Some(linker), Some(flavor)) => Ok((linker, flavor)),
+            // only the linker flavor is known; use the default linker for the selected flavor
+            (None, Some(flavor)) => Ok((PathBuf::from(match flavor {
+                LinkerFlavor::Em => "emcc",
+                LinkerFlavor::Gcc => "gcc",
+                LinkerFlavor::Ld => "ld",
+                LinkerFlavor::Msvc => "link.exe",
+                LinkerFlavor::Lld(_) => "lld",
+            }), flavor)),
+            // infer the linker flavor from the linker name
+            (Some(linker), None) => {
+                let stem = linker.file_stem().and_then(|stem| stem.to_str()).ok_or_else(|| {
+                    sess
+                        .struct_err(&format!("couldn't extract file stem from specified linker"))
+                        .emit();
+                })?.to_owned();
+
+                let flavor = if stem == "emcc" {
+                    LinkerFlavor::Em
+                } else if stem == "gcc" || stem.ends_with("-gcc") {
+                    LinkerFlavor::Gcc
+                } else if stem == "ld" || stem == "ld.lld" || stem.ends_with("-ld") {
+                    LinkerFlavor::Ld
+                } else if stem == "link" || stem == "lld-link" {
+                    LinkerFlavor::Msvc
+                } else {
+                    sess
+                        .struct_err(&format!("couldn't infer linker flavor from specified linker"))
+                        .emit();
+                    return Err(());
+                };
+
+                Ok((linker, flavor))
+            },
+            (None, None) => otherwise(),
+        }
+    }
+
+    // linker and linker flavor specified via command line have precedence over what the target
+    // specification specifies
+    from(sess, sess.opts.cg.linker.clone(), sess.opts.debugging_opts.linker_flavor, || {
+        from(
+            sess,
+            sess.target.target.options.linker.clone().map(PathBuf::from),
+            Some(sess.target.target.linker_flavor),
+            || {
+                sess
+                    .struct_err(&format!("no linker or linker flavor information provided"))
+                    .emit();
+                Err(())
+            })
+    })
+}
+
 // Create a dynamic library or executable
 //
 // This will invoke the system linker/cc to create the resulting file. This
@@ -625,10 +675,15 @@ fn link_natively(sess: &Session,
                  codegen_results: &CodegenResults,
                  tmpdir: &Path) {
     info!("preparing {:?} to {:?}", crate_type, out_filename);
-    let flavor = sess.linker_flavor();
+    let (linker, flavor) = if let Ok((linker, flavor)) = linker_and_flavor(sess) {
+        (linker, flavor)
+    } else {
+        sess.abort_if_errors();
+        return;
+    };
 
     // The invocations of cc share some flags across platforms
-    let (pname, mut cmd) = get_linker(sess);
+    let (pname, mut cmd) = get_linker(sess, &linker, flavor);
 
     let root = sess.target_filesearch(PathKind::Native).get_lib_path();
     if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
@@ -669,8 +724,8 @@ fn link_natively(sess: &Session,
     }
 
     {
-        let mut linker = codegen_results.linker_info.to_linker(cmd, &sess);
-        link_args(&mut *linker, sess, crate_type, tmpdir,
+        let mut linker = codegen_results.linker_info.to_linker(cmd, &sess, flavor);
+        link_args(&mut *linker, flavor, sess, crate_type, tmpdir,
                   out_filename, codegen_results);
         cmd = linker.finalize();
     }
@@ -742,7 +797,7 @@ fn link_natively(sess: &Session,
         // linking executables as pie. Different versions of gcc seem to use
         // different quotes in the error message so don't check for them.
         if sess.target.target.options.linker_is_gnu &&
-           sess.linker_flavor() != LinkerFlavor::Ld &&
+           flavor != LinkerFlavor::Ld &&
            (out.contains("unrecognized command line option") ||
             out.contains("unknown argument")) &&
            out.contains("-no-pie") &&
@@ -991,6 +1046,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 }
 
 fn link_args(cmd: &mut dyn Linker,
+             flavor: LinkerFlavor,
              sess: &Session,
              crate_type: config::CrateType,
              tmpdir: &Path,
@@ -1075,7 +1131,7 @@ fn link_args(cmd: &mut dyn Linker,
             // independent executables by default. We have to pass -no-pie to
             // explicitly turn that off. Not applicable to ld.
             if sess.target.target.options.linker_is_gnu
-                && sess.linker_flavor() != LinkerFlavor::Ld {
+                && flavor != LinkerFlavor::Ld {
                 cmd.no_position_independent_executable();
             }
         }
index e0a30ef5dbc9abe10befecbda24285ef84a394fd..efa4b4d52079edbf8cb2326be8dfc056c43a6c52 100644 (file)
@@ -44,8 +44,9 @@ pub fn new(tcx: TyCtxt) -> LinkerInfo {
 
     pub fn to_linker<'a>(&'a self,
                          cmd: Command,
-                         sess: &'a Session) -> Box<dyn Linker+'a> {
-        match sess.linker_flavor() {
+                         sess: &'a Session,
+                         flavor: LinkerFlavor) -> Box<dyn Linker+'a> {
+        match flavor {
             LinkerFlavor::Lld(LldFlavor::Link) |
             LinkerFlavor::Msvc => {
                 Box::new(MsvcLinker {
index 640e1c1f3d4f112cdb18158e3b9e73a4d5ecefab..e5e837d05de389198a440bb6727d6f05e6479617 100644 (file)
@@ -1503,12 +1503,17 @@ fn start_executing_work(tcx: TyCtxt,
 
     let assembler_cmd = if modules_config.no_integrated_as {
         // HACK: currently we use linker (gcc) as our assembler
-        let (name, mut cmd) = get_linker(sess);
-        cmd.args(&sess.target.target.options.asm_args);
-        Some(Arc::new(AssemblerCommand {
-            name,
-            cmd,
-        }))
+        if let Ok((linker, flavor)) = link::linker_and_flavor(sess) {
+            let (name, mut cmd) = get_linker(sess, &linker, flavor);
+            cmd.args(&sess.target.target.options.asm_args);
+            Some(Arc::new(AssemblerCommand {
+                name,
+                cmd,
+            }))
+        } else {
+            sess.abort_if_errors();
+            None
+        }
     } else {
         None
     };