diff options
| author | bors <bors@rust-lang.org> | 2018-08-20 01:12:58 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-08-20 01:12:58 +0000 |
| commit | d2048b6db375299b681d4f4728b8e7cad9f74d5f (patch) | |
| tree | fe497e08e2a0843f20d7e014154ae5c2a443e7f5 /src/librustc_codegen_llvm/back | |
| parent | 6bf6d50a6ff7685b4aa09172d9d09f03f250da9d (diff) | |
| parent | a6f4ae864eb9a99117f7475325bf9ffb2c8e8b90 (diff) | |
| download | rust-d2048b6db375299b681d4f4728b8e7cad9f74d5f.tar.gz rust-d2048b6db375299b681d4f4728b8e7cad9f74d5f.zip | |
Auto merge of #52101 - japaric:linker-flavor, r=alexcrichton
try to infer linker flavor from linker name and vice versa This is a second take on PR #50359 that implements the logic proposed in https://github.com/rust-lang/rust/pull/50359#pullrequestreview-116663121 With this change it would become possible to link `thumb*` binaries using GNU's LD on stable as `-C linker=arm-none-eabi-ld` would be enough to change both the linker and the linker flavor from their default values of `arm-none-eabi-gcc` and `gcc`. To link `thumb*` binaries using rustc's LLD on stable `-Z linker-flavor` would need to be stabilized as `-C linker=rust-lld -Z linker-flavor=ld.lld` are both required to change the linker and the linker flavor, but this PR doesn't propose that. We would probably need some sort of stability guarantee around `rust-lld`'s name and availability to make linking with rustc's LLD truly stable. With this change it would also be possible to link `thumb*` binaries using a system installed LLD on stable using the `-C linker=ld.lld` flag (provided that `ld.lld` is a symlink to the system installed LLD). r? @alexcrichton
Diffstat (limited to 'src/librustc_codegen_llvm/back')
| -rw-r--r-- | src/librustc_codegen_llvm/back/link.rs | 115 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/back/linker.rs | 5 | ||||
| -rw-r--r-- | src/librustc_codegen_llvm/back/write.rs | 4 |
3 files changed, 88 insertions, 36 deletions
diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index 37c99932f56..34ddfa94552 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -53,7 +53,9 @@ pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default // 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) { + let msvc_tool = windows_registry::find_tool(&sess.opts.target_triple.triple(), "link.exe"); + // 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 @@ -62,36 +64,19 @@ 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| { - if let Some(linker) = linker.to_str() { - if cfg!(windows) && linker.ends_with(".bat") { - return Command::bat_script(linker) - } - } - match sess.linker_flavor() { + let mut cmd = match linker.to_str() { + Some(linker) if cfg!(windows) && linker.ends_with(".bat") => Command::bat_script(linker), + _ => match flavor { LinkerFlavor::Lld(f) => Command::lld(linker, f), + LinkerFlavor::Msvc + if sess.opts.cg.linker.is_none() && sess.target.target.options.linker.is_none() => + { + Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker)) + }, _ => 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) @@ -118,7 +103,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) { @@ -608,6 +593,69 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) { } } +pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { + fn infer_from( + sess: &Session, + linker: Option<PathBuf>, + flavor: Option<LinkerFlavor>, + ) -> Option<(PathBuf, LinkerFlavor)> { + match (linker, flavor) { + (Some(linker), Some(flavor)) => Some((linker, flavor)), + // only the linker flavor is known; use the default linker for the selected flavor + (None, Some(flavor)) => Some((PathBuf::from(match flavor { + LinkerFlavor::Em => if cfg!(windows) { "emcc.bat" } else { "emcc" }, + LinkerFlavor::Gcc => "cc", + LinkerFlavor::Ld => "ld", + LinkerFlavor::Msvc => "link.exe", + LinkerFlavor::Lld(_) => "lld", + }), flavor)), + (Some(linker), None) => { + let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| { + sess.fatal("couldn't extract file stem from specified linker"); + }).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 if stem == "lld" || stem == "rust-lld" { + LinkerFlavor::Lld(sess.target.target.options.lld_flavor) + } else { + // fall back to the value in the target spec + sess.target.target.linker_flavor + }; + + Some((linker, flavor)) + }, + (None, None) => None, + } + } + + // linker and linker flavor specified via command line have precedence over what the target + // specification specifies + if let Some(ret) = infer_from( + sess, + sess.opts.cg.linker.clone(), + sess.opts.debugging_opts.linker_flavor, + ) { + return ret; + } + + if let Some(ret) = infer_from( + sess, + sess.target.target.options.linker.clone().map(PathBuf::from), + Some(sess.target.target.linker_flavor), + ) { + return ret; + } + + bug!("Not enough information provided to determine how to invoke the linker"); +} + // Create a dynamic library or executable // // This will invoke the system linker/cc to create the resulting file. This @@ -618,10 +666,10 @@ 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) = linker_and_flavor(sess); // 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) { @@ -662,8 +710,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(); } @@ -735,7 +783,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") && @@ -984,6 +1032,7 @@ fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: & } fn link_args(cmd: &mut dyn Linker, + flavor: LinkerFlavor, sess: &Session, crate_type: config::CrateType, tmpdir: &Path, @@ -1068,7 +1117,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(); } } diff --git a/src/librustc_codegen_llvm/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs index 6311ab7c74c..a429e8f2d81 100644 --- a/src/librustc_codegen_llvm/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -44,8 +44,9 @@ impl 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 { diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index b62836ec255..462a2c9f028 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -1502,7 +1502,9 @@ 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); + let (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, |
