From 2984bf674f5f1839c19002f4fd032eacc98596c9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 24 May 2022 23:29:15 +0300 Subject: [PATCH] Simplify implementation of `-Z gcc-ld` - The logic is now unified for all targets (wasm targets should also be supported now) - Additional "symlink" files like `ld64` are eliminated - lld-wrapper is used for propagating the correct lld flavor - Cleanup "unwrap or exit" logic in lld-wrapper --- .../rustc_codegen_ssa/src/back/command.rs | 7 +- compiler/rustc_codegen_ssa/src/back/link.rs | 45 +++------ compiler/rustc_target/src/spec/mod.rs | 17 ++-- src/bootstrap/compile.rs | 13 +-- src/bootstrap/dist.rs | 7 +- src/bootstrap/tool.rs | 3 +- src/tools/lld-wrapper/Cargo.toml | 6 -- src/tools/lld-wrapper/src/main.rs | 95 ++++++++----------- 8 files changed, 71 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index 17071ba1b5bf3..6c29692bd3bfe 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -105,12 +105,7 @@ impl Command { } Program::Lld(ref p, flavor) => { let mut c = process::Command::new(p); - c.arg("-flavor").arg(match flavor { - LldFlavor::Wasm => "wasm", - LldFlavor::Ld => "gnu", - LldFlavor::Link => "link", - LldFlavor::Ld64 => "darwin", - }); + c.arg("-flavor").arg(flavor.as_str()); if let LldFlavor::Wasm = flavor { // LLVM expects host-specific formatting for @file // arguments, but we always generate posix formatted files diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 04ec1e7f3c1af..00f85852493b2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2698,37 +2698,20 @@ fn add_gcc_ld_path(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let LinkerFlavor::Gcc = flavor { match ld_impl { LdImpl::Lld => { - if sess.target.lld_flavor == LldFlavor::Ld64 { - let tools_path = sess.get_tools_search_paths(false); - let ld64_exe = tools_path - .into_iter() - .map(|p| p.join("gcc-ld")) - .map(|p| { - p.join(if sess.host.is_like_windows { "ld64.exe" } else { "ld64" }) - }) - .find(|p| p.exists()) - .unwrap_or_else(|| sess.fatal("rust-lld (as ld64) not found")); - cmd.cmd().arg({ - let mut arg = OsString::from("-fuse-ld="); - arg.push(ld64_exe); - arg - }); - } else { - let tools_path = sess.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 - }); - } + 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())); } } } else { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 832eeec3e8b27..6dd245b047cbe 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -108,6 +108,15 @@ pub enum LldFlavor { } impl LldFlavor { + pub fn as_str(&self) -> &'static str { + match self { + LldFlavor::Wasm => "wasm", + LldFlavor::Ld64 => "darwin", + LldFlavor::Ld => "gnu", + LldFlavor::Link => "link", + } + } + fn from_str(s: &str) -> Option { Some(match s { "darwin" => LldFlavor::Ld64, @@ -121,13 +130,7 @@ impl LldFlavor { impl ToJson for LldFlavor { fn to_json(&self) -> Json { - match *self { - LldFlavor::Ld64 => "darwin", - LldFlavor::Ld => "gnu", - LldFlavor::Link => "link", - LldFlavor::Wasm => "wasm", - } - .to_json() + self.as_str().to_json() } } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 0b430f64e1edc..b35eba21e6bd6 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -1164,14 +1164,11 @@ impl Step for Assemble { // for `-Z gcc-ld=lld` let gcc_ld_dir = libdir_bin.join("gcc-ld"); t!(fs::create_dir(&gcc_ld_dir)); - for flavor in ["ld", "ld64"] { - let lld_wrapper_exe = builder.ensure(crate::tool::LldWrapper { - compiler: build_compiler, - target: target_compiler.host, - flavor_feature: flavor, - }); - builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe(flavor, target_compiler.host))); - } + let lld_wrapper_exe = builder.ensure(crate::tool::LldWrapper { + compiler: build_compiler, + target: target_compiler.host, + }); + builder.copy(&lld_wrapper_exe, &gcc_ld_dir.join(exe("ld", target_compiler.host))); } if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) { diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 0be11e3fb467e..cc10d67c551db 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -407,11 +407,8 @@ impl Step for Rustc { 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)); - for flavor in ["ld", "ld64"] { - let exe_name = exe(flavor, compiler.host); - builder - .copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name)); - } + let exe_name = exe("ld", compiler.host); + builder.copy(&gcc_lld_src_dir.join(&exe_name), &gcc_lld_dst_dir.join(&exe_name)); } // Man pages diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 3b30e6de12a63..2f4d07d77a51f 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -656,7 +656,6 @@ impl Step for Cargo { pub struct LldWrapper { pub compiler: Compiler, pub target: TargetSelection, - pub flavor_feature: &'static str, } impl Step for LldWrapper { @@ -676,7 +675,7 @@ impl Step for LldWrapper { path: "src/tools/lld-wrapper", is_optional_tool: false, source_type: SourceType::InTree, - extra_features: vec![self.flavor_feature.to_owned()], + extra_features: Vec::new(), }) .expect("expected to build -- essential tool"); diff --git a/src/tools/lld-wrapper/Cargo.toml b/src/tools/lld-wrapper/Cargo.toml index 66a586fd6c35e..bf5138b16d5bd 100644 --- a/src/tools/lld-wrapper/Cargo.toml +++ b/src/tools/lld-wrapper/Cargo.toml @@ -3,9 +3,3 @@ name = "lld-wrapper" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" - -[dependencies] - -[features] -ld = [] -ld64 = [] \ No newline at end of file diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs index 8d19a054a1d25..90bd24a75e064 100644 --- a/src/tools/lld-wrapper/src/main.rs +++ b/src/tools/lld-wrapper/src/main.rs @@ -1,5 +1,4 @@ -//! Script to invoke the bundled rust-lld with the correct flavor. The flavor is selected by -//! feature. +//! Script to invoke the bundled rust-lld with the correct flavor. //! //! lld supports multiple command line interfaces. If `-flavor ` are passed as the first //! two arguments the `` command line interface is used to process the remaining arguments. @@ -8,59 +7,33 @@ //! In Rust with `-Z gcc-ld=lld` we have gcc or clang invoke rust-lld. Since there is no way to //! make gcc/clang pass `-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 ld` if the feature `ld` is enabled and -//! `../rust-lld -flavor ld64` if `ld64` is enabled. On Windows it spawns a `..\rust-lld.exe` +//! symbolic link. It execs `../rust-lld -flavor ` by propagating the flavor argument +//! passed to the wrapper as the first two arguments. On Windows it spawns a `..\rust-lld.exe` //! child process. -#[cfg(not(any(feature = "ld", feature = "ld64")))] -compile_error!("One of the features ld and ld64 must be enabled."); - -#[cfg(all(feature = "ld", feature = "ld64"))] -compile_error!("Only one of the feature ld or ld64 can be enabled."); - -#[cfg(feature = "ld")] -const FLAVOR: &str = "ld"; - -#[cfg(feature = "ld64")] -const FLAVOR: &str = "ld64"; - -use std::env; use std::fmt::Display; use std::path::{Path, PathBuf}; -use std::process; +use std::{env, process}; -trait ResultExt { +trait UnwrapOrExitWith { fn unwrap_or_exit_with(self, context: &str) -> T; } -impl ResultExt for Result -where - E: Display, -{ +impl UnwrapOrExitWith for Option { fn unwrap_or_exit_with(self, context: &str) -> T { - match self { - Ok(t) => t, - Err(e) => { - eprintln!("lld-wrapper: {}: {}", context, e); - process::exit(1); - } - } + self.unwrap_or_else(|| { + eprintln!("lld-wrapper: {}", context); + process::exit(1); + }) } } -trait OptionExt { - fn unwrap_or_exit_with(self, context: &str) -> T; -} - -impl OptionExt for Option { +impl UnwrapOrExitWith for Result { fn unwrap_or_exit_with(self, context: &str) -> T { - match self { - Some(t) => t, - None => { - eprintln!("lld-wrapper: {}", context); - process::exit(1); - } - } + self.unwrap_or_else(|err| { + eprintln!("lld-wrapper: {}: {}", context, err); + process::exit(1); + }) } } @@ -81,14 +54,28 @@ fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf { } /// Returns the command for invoking rust-lld with the correct flavor. +/// LLD only accepts the flavor argument at the first two arguments, so move it there. /// /// 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); + + 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::>(); + command.arg("-flavor"); - command.arg(FLAVOR); - command.args(env::args_os().skip(1)); + command.arg(flavor.unwrap_or_exit_with("-rustc-lld-flavor= is not passed")); + command.args(args); command } @@ -101,20 +88,14 @@ fn exec_lld(mut command: process::Command) { #[cfg(not(unix))] fn exec_lld(mut command: process::Command) { - // Windows has no exec(), spawn a child process and wait for it + // Windows has no exec(), spawn a child process and wait for it. let exit_status = command.status().unwrap_or_exit_with("error running rust-lld child process"); - if !exit_status.success() { - match exit_status.code() { - Some(code) => { - // return the original lld exit code - process::exit(code) - } - None => { - eprintln!("lld-wrapper: rust-lld child process exited with error: {}", exit_status,); - process::exit(1); - } - } - } + let code = exit_status + .code() + .ok_or(exit_status) + .unwrap_or_exit_with("rust-lld child process exited with error"); + // Return the original lld exit code. + process::exit(code); } fn main() {