diff options
| author | Hans Kratz <hans@appfour.com> | 2021-09-25 15:25:08 +0200 |
|---|---|---|
| committer | Hans Kratz <hans@appfour.com> | 2021-10-07 16:59:13 +0200 |
| commit | 6162fc0c809477529875b294a8ce37ff8737356c (patch) | |
| tree | 0f6c8a48e5949f3bb1b9810967dc913d5244e975 /src/tools/lld-wrapper | |
| parent | ca8078d7b2e40c24a39e5fe2a910afef4c91ebfc (diff) | |
Add wrapper for -Z gcc-ld=lld to invoke rust-lld with the correct flavor
The wrapper is installed as `ld` and `ld64` in the `lib\rustlib\<host_target>\bin\gcc-ld` directory and its sole purpose is to invoke `rust-lld` in the parent directory with the correct flavor.
Diffstat (limited to 'src/tools/lld-wrapper')
| -rw-r--r-- | src/tools/lld-wrapper/Cargo.toml | 11 | ||||
| -rw-r--r-- | src/tools/lld-wrapper/src/main.rs | 125 |
2 files changed, 136 insertions, 0 deletions
diff --git a/src/tools/lld-wrapper/Cargo.toml b/src/tools/lld-wrapper/Cargo.toml new file mode 100644 index 00000000000..66a586fd6c3 --- /dev/null +++ b/src/tools/lld-wrapper/Cargo.toml @@ -0,0 +1,11 @@ +[package] +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 new file mode 100644 index 00000000000..1601bf1b34e --- /dev/null +++ b/src/tools/lld-wrapper/src/main.rs @@ -0,0 +1,125 @@ +//! Script to invoke the bundled rust-lld with the correct flavor. The flavor is selected by +//! feature. +//! +//! lld supports multiple command line interfaces. If `-flavor <flavor>` are passed as the first +//! two arguments the `<flavor>` command line interface is used to process the remaining arguments. +//! If no `-flavor` argument is present the flavor is determined by the executable name. +//! +//! 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 <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 +//! symblic 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` +//! 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; + +trait ResultExt<T, E> { + fn unwrap_or_exit_with(self, context: &str) -> T; +} + +impl<T, E> ResultExt<T, E> for Result<T, E> +where + E: Display, +{ + fn unwrap_or_exit_with(self, context: &str) -> T { + match self { + Ok(t) => t, + Err(e) => { + eprintln!("lld-wrapper: {}: {}", context, e); + process::exit(1); + } + } + } +} + +trait OptionExt<T> { + fn unwrap_or_exit_with(self, context: &str) -> T; +} + +impl<T> OptionExt<T> for Option<T> { + fn unwrap_or_exit_with(self, context: &str) -> T { + match self { + Some(t) => t, + None => { + eprintln!("lld-wrapper: {}", context); + process::exit(1); + } + } + } +} + +/// Returns the path to rust-lld in the parent directory. +/// +/// Exits if the parent directory cannot be determined. +fn get_rust_lld_path(current_exe_path: &Path) -> PathBuf { + let mut rust_lld_exe_name = "rust-lld".to_owned(); + rust_lld_exe_name.push_str(env::consts::EXE_SUFFIX); + let mut rust_lld_path = current_exe_path + .parent() + .unwrap_or_exit_with("directory containing current executable could not be determined") + .parent() + .unwrap_or_exit_with("parent directory could not be determined") + .to_owned(); + rust_lld_path.push(rust_lld_exe_name); + rust_lld_path +} + +/// Returns the command for invoking rust-lld with the correct flavor. +/// +/// 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); + command.arg("-flavor"); + command.arg(FLAVOR); + command.args(env::args_os().skip(1)); + command +} + +#[cfg(unix)] +fn exec_lld(mut command: process::Command) { + use std::os::unix::prelude::CommandExt; + Result::<(), _>::Err(command.exec()).unwrap_or_exit_with("could not exec rust-lld"); + unreachable!("lld-wrapper: after exec without error"); +} + +#[cfg(not(unix))] +fn exec_lld(mut command: process::Command) { + // 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); + } + } + } +} + +fn main() { + let current_exe_path = + env::current_exe().unwrap_or_exit_with("could not get the path of the current executable"); + + exec_lld(get_rust_lld_command(current_exe_path.as_ref())); +} |
