diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index cb56e3f9e8a19..6c9ec9e7b0dae 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -5,7 +5,7 @@ use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::CrateNum; use rustc_middle::middle::cstore::{DllImport, LibSource}; use rustc_middle::middle::dependency_format::Linkage; -use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, Strip}; +use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; use rustc_session::config::{OutputFilenames, OutputType, PrintRequest}; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::search_paths::PathKind; @@ -1927,6 +1927,8 @@ fn add_order_independent_options( out_filename: &Path, tmpdir: &Path, ) { + add_gcc_ld_path(cmd, sess, flavor); + add_apple_sdk(cmd, sess, flavor); add_link_script(cmd, sess, tmpdir, crate_type); @@ -2528,3 +2530,30 @@ fn get_apple_sdk_root(sdk_name: &str) -> Result { Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)), } } + +fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { + if let Some(ld_impl) = sess.opts.debugging_opts.gcc_ld { + if let LinkerFlavor::Gcc = flavor { + match ld_impl { + LdImpl::Lld => { + let tools_path = + sess.host_filesearch(PathKind::All).get_tools_search_paths(false); + let lld_path = tools_path + .into_iter() + .map(|p| p.join("gcc-ld")) + .find(|p| { + p.join(if sess.host.is_like_windows { "ld.exe" } else { "ld" }).exists() + }) + .unwrap_or_else(|| sess.fatal("rust-lld (as ld) not found")); + cmd.cmd().arg({ + let mut arg = OsString::from("-B"); + arg.push(lld_path); + arg + }); + } + } + } else { + sess.fatal("option `-Z gcc-ld` is used even though linker flavor is not gcc"); + } + } +} diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 5752258268384..2b547f8be9228 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2417,6 +2417,7 @@ impl PpMode { /// we have an opt-in scheme here, so one is hopefully forced to think about /// how the hash should be calculated when adding a new command-line argument. crate mod dep_tracking { + use super::LdImpl; use super::{ CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto, LtoCli, OptLevel, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath, @@ -2497,6 +2498,7 @@ crate mod dep_tracking { SymbolManglingVersion, SourceFileHashAlgorithm, TrimmedDefPaths, + Option, ); impl DepTrackingHash for (T1, T2) diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 58a53b3de6eb0..1946bfd78cc38 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -370,6 +370,7 @@ mod desc { pub const parse_wasi_exec_model: &str = "either `command` or `reactor`"; pub const parse_split_debuginfo: &str = "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)"; + pub const parse_gcc_ld: &str = "one of: no value, `lld`"; } mod parse { @@ -864,6 +865,15 @@ mod parse { } true } + + crate fn parse_gcc_ld(slot: &mut Option, v: Option<&str>) -> bool { + match v { + None => *slot = None, + Some("lld") => *slot = Some(LdImpl::Lld), + _ => return false, + } + true + } } options! { @@ -1067,6 +1077,7 @@ options! { "set the optimization fuel quota for a crate"), function_sections: Option = (None, parse_opt_bool, [TRACKED], "whether each function should go in its own section"), + gcc_ld: Option = (None, parse_gcc_ld, [TRACKED], "implementation of ld used by cc"), graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED], "use dark-themed colors in graphviz output (default: no)"), graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED], @@ -1321,3 +1332,8 @@ pub enum WasiExecModel { Command, Reactor, } + +#[derive(Clone, Copy, Hash)] +pub enum LdImpl { + Lld, +} diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index ed311e273b19c..112a6ea939869 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1108,6 +1108,13 @@ impl Step for Assemble { let src_exe = exe("lld", target_compiler.host); let dst_exe = exe("rust-lld", target_compiler.host); builder.copy(&lld_install.join("bin").join(&src_exe), &libdir_bin.join(&dst_exe)); + // for `-Z gcc-ld=lld` + let gcc_ld_dir = libdir_bin.join("gcc-ld"); + t!(fs::create_dir(&gcc_ld_dir)); + builder.copy( + &lld_install.join("bin").join(&src_exe), + &gcc_ld_dir.join(exe("ld", target_compiler.host)), + ); } // Similarly, copy `llvm-dwp` into libdir for Split DWARF. Only copy it when the LLVM diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index aee3c8324bc11..71ed0af4a7c04 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -402,6 +402,10 @@ impl Step for Rustc { if builder.config.lld_enabled { let exe = exe("rust-lld", compiler.host); builder.copy(&src_dir.join(&exe), &dst_dir.join(&exe)); + // for `-Z gcc-ld=lld` + let gcc_lld_dir = dst_dir.join("gcc-ld"); + t!(fs::create_dir(&gcc_lld_dir)); + builder.copy(&src_dir.join(&exe), &gcc_lld_dir.join(&exe)); } // Copy over llvm-dwp if it's there diff --git a/src/test/run-make/issue-71519/Makefile b/src/test/run-make/issue-71519/Makefile new file mode 100644 index 0000000000000..636665ec1d0c2 --- /dev/null +++ b/src/test/run-make/issue-71519/Makefile @@ -0,0 +1,6 @@ +-include ../../run-make-fulldeps/tools.mk + +# needs-rust-lld +all: + RUSTC_LOG=rustc_codegen_ssa::back::link=info $(RUSTC) -Z gcc-ld=lld -C link-args=-Wl,-v main.rs 2> $(TMPDIR)/output.txt + $(CGREP) -e "^LLD [0-9]+\.[0-9]+\.[0-9]+" < $(TMPDIR)/output.txt diff --git a/src/test/run-make/issue-71519/main.rs b/src/test/run-make/issue-71519/main.rs new file mode 100644 index 0000000000000..f8d09e8975330 --- /dev/null +++ b/src/test/run-make/issue-71519/main.rs @@ -0,0 +1,4 @@ +// test linking using cc with rust-lld injected into search path as ld +// see rust-lang/rust#71519 for more info + +fn main() {} diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 983934d129a2e..3b620ab65ab94 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -50,6 +50,15 @@ impl EarlyProps { let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target); + // for `-Z gcc-ld=lld` + let has_rust_lld = config + .compile_lib_path + .join("rustlib") + .join(&config.target) + .join("bin") + .join("gcc-ld") + .join(if config.host.contains("windows") { "ld.exe" } else { "ld" }) + .exists(); iter_header(testfile, None, rdr, &mut |ln| { // we should check if any only- exists and if it exists @@ -136,6 +145,10 @@ impl EarlyProps { if config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln) { props.ignore = true; } + + if !has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld") { + props.ignore = true; + } } if let Some(s) = config.parse_aux_build(ln) {