Change:
lld-wrapper is unhappy. I tried this code: Instead, this happened: <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summaryBacktrace</summary<p</p</detailsNote that this worked for months. This is a regression for me.
Is this issue related to ?
I found no traces of the last working nightly.
Is this issue related to It's certainly somehow related because didn't exist before that, but I don't know how it can happen, is in fact passed as snipped posted in the original message shows.
Do you need more information?
Do you need more information? Yes, output of lld-wrapper with inserted here (You don't need whole compiler build to rebuild lld-wrapper, it's a single-file standalone program, it can be built with directly or with , and then temporarily put into the directory.)
Note that main:rs73 is the failure case.
I see. The command line is to long so it's moved to a temporary file and passed with . Neither lld-wrapper nor original (flavorless) lld support specifying the flavor inside the file. Due to the way in which and work for naked LLD never gets into the file, we should do something similar with too.
I don't know whether rustc has utilities for handling response files
Ok, it's actually clang that packs the command line into a , not rustc, so we cannot control or predict when it happens. That's pretty bad. I guess we'll have to partially revert and use something based on file names, like
Fixed in Sorry for the delay, I should have fixed this two months ago. could you test the fix on Darwin?

Discussion:
if let LinkerFlavor::Gcc = flavor { match ld_impl { LdImpl::Lld => { <del> let tools_path = sess.get_tools_search_paths(false); let gcc_ld_dir = 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.arg({ let mut arg = OsString::from("-B"); arg.push(gcc_ld_dir); arg }); cmd.arg(format!("-Wl,-rustc-lld-flavor={}", sess.target.lld_flavor.as_str())); </del> <ins> // Implement the "self-contained" part of -Zgcc-ld // by adding rustc distribution directories to the tool search path. for path in sess.get_tools_search_paths(false) { cmd.arg({ let mut arg = OsString::from("-B"); arg.push(path.join("gcc-ld")); arg }); } // Implement the "linker flavor" part of -Zgcc-ld // by asking cc to use some kind of lld. cmd.arg("-fuse-ld=lld"); if sess.target.lld_flavor != LldFlavor::Ld { // Tell clang to use a non-default LLD flavor. // Gcc doesn't understand the target option, but we currently assume // that gcc is not used for Apple and Wasm targets (#97402). cmd.arg(format!("--target={}", sess.target.llvm_target)); } </ins> } } } else {

compiler: build_compiler, target: target_compiler.host, }); <del> builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe("ld", target_compiler.host))); </del> <ins> for name in crate::LLD_FILE_NAMES { builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe(name, target_compiler.host))); } </ins> } if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {

let gcc_lld_src_dir = src_dir.join("gcc-ld"); let gcc_lld_dst_dir = dst_dir.join("gcc-ld"); t!(fs::create_dir(&gcc_lld_dst_dir)); <del> let exe_name = exe("ld", compiler.host); builder.copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name)); </del> <ins> for name in crate::LLD_FILE_NAMES { let exe_name = exe(name, compiler.host); builder .copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name)); } </ins> } // Man pages

"opt",           // used to optimize LLVM bytecode ]; <ins> /// LLD file names for all flavors. const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"]; </ins> pub const VERSION: usize = 2; /// Extra --check-cfg to add when building

//! make gcc/clang pass `-flavor <flavor>` as the first two arguments in the linker invocation //! and since Windows does not support symbolic links for files this wrapper is used in place of a //! symbolic link. It execs `../rust-lld -flavor <flavor>` by propagating the flavor argument <del> //! passed to the wrapper as the first two arguments. On Windows it spawns a `..rust-lld.exe` //! child process. </del> <ins> //! obtained from the wrapper's name as the first two arguments. //! On Windows it spawns a `..rust-lld.exe` child process. </ins> use std::fmt::Display; use std::path::{Path, PathBuf};

rust_lld_path } <ins> /// Extract LLD flavor name from the lld-wrapper executable name. fn get_lld_flavor(current_exe_path: &Path) -> Result<&'static str, String> { let stem = current_exe_path.file_stem(); Ok(match stem.and_then(|s| s.to_str()) { Some("ld.lld") => "gnu", Some("ld64.lld") => "darwin", Some("lld-link") => "link", Some("wasm-ld") => "wasm", _ => return Err(format!("{:?}", stem)), }) } </ins> /// Returns the command for invoking rust-lld with the correct flavor. <del> /// LLD only accepts the flavor argument at the first two arguments, so move it there. </del> <ins> /// LLD only accepts the flavor argument at the first two arguments, so pass it there. </ins> /// /// Exits on error. fn get_rust_lld_command(current_exe_path: &Path) -> process::Command { let rust_lld_path = get_rust_lld_path(current_exe_path); let mut command = process::Command::new(rust_lld_path); <del> let mut flavor = None; let args = env::args_os() .skip(1) .filter(|arg| match arg.to_str().and_then(|s| s.strip_prefix("-rustc-lld-flavor=")) { Some(suffix) => { flavor = Some(suffix.to_string()); false } None => true, }) .collect::<Vec<_>>(); </del> <ins> let flavor = get_lld_flavor(current_exe_path).unwrap_or_exit_with("executable has unexpected name"); </ins> command.arg("-flavor"); <del> command.arg(flavor.unwrap_or_exit_with("-rustc-lld-flavor=<flavor> is not passed")); command.args(args); </del> <ins> command.arg(flavor); command.args(env::args_os().skip(1)); </ins> command }