From 0afc774e9dc3d000ecd3df05d14cfe0304908fbe Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 29 Jun 2024 08:05:53 +0300 Subject: [PATCH 1/2] unify `bin_helpers` and `dylib` utility modules Signed-off-by: onur-ozkan --- src/bootstrap/src/utils/dylib.rs | 40 ------------- src/bootstrap/src/utils/mod.rs | 2 +- .../{bin_helpers.rs => shared_helpers.rs} | 59 +++++++++++++++++-- 3 files changed, 54 insertions(+), 47 deletions(-) delete mode 100644 src/bootstrap/src/utils/dylib.rs rename src/bootstrap/src/utils/{bin_helpers.rs => shared_helpers.rs} (50%) diff --git a/src/bootstrap/src/utils/dylib.rs b/src/bootstrap/src/utils/dylib.rs deleted file mode 100644 index 90bcff59a64..00000000000 --- a/src/bootstrap/src/utils/dylib.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! Various utilities for working with dylib paths. - -/// Returns the environment variable which the dynamic library lookup path -/// resides in for this platform. -pub fn dylib_path_var() -> &'static str { - if cfg!(target_os = "windows") { - "PATH" - } else if cfg!(target_vendor = "apple") { - "DYLD_LIBRARY_PATH" - } else if cfg!(target_os = "haiku") { - "LIBRARY_PATH" - } else if cfg!(target_os = "aix") { - "LIBPATH" - } else { - "LD_LIBRARY_PATH" - } -} - -/// Parses the `dylib_path_var()` environment variable, returning a list of -/// paths that are members of this lookup path. -pub fn dylib_path() -> Vec { - let var = match std::env::var_os(dylib_path_var()) { - Some(v) => v, - None => return vec![], - }; - std::env::split_paths(&var).collect() -} - -/// Given an executable called `name`, return the filename for the -/// executable for a particular target. -#[allow(dead_code)] -pub fn exe(name: &str, target: &str) -> String { - if target.contains("windows") { - format!("{name}.exe") - } else if target.contains("uefi") { - format!("{name}.efi") - } else { - name.to_string() - } -} diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs index cb535f0e163..53b41f15780 100644 --- a/src/bootstrap/src/utils/mod.rs +++ b/src/bootstrap/src/utils/mod.rs @@ -6,11 +6,11 @@ pub(crate) mod cc_detect; pub(crate) mod change_tracker; pub(crate) mod channel; -pub(crate) mod dylib; pub(crate) mod exec; pub(crate) mod helpers; pub(crate) mod job; #[cfg(feature = "build-metrics")] pub(crate) mod metrics; pub(crate) mod render_tests; +pub(crate) mod shared_helpers; pub(crate) mod tarball; diff --git a/src/bootstrap/src/utils/bin_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs similarity index 50% rename from src/bootstrap/src/utils/bin_helpers.rs rename to src/bootstrap/src/utils/shared_helpers.rs index 5fbbe0bde0e..8ec7116f6ca 100644 --- a/src/bootstrap/src/utils/bin_helpers.rs +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -1,18 +1,65 @@ -//! This file is meant to be included directly from bootstrap shims to avoid a -//! dependency on the bootstrap library. This reduces the binary size and -//! improves compilation time by reducing the linking time. +//! This module serves two purposes: +//! 1. It is part of the `utils` module and used in other parts of bootstrap. +//! 2. It is embedded inside bootstrap shims to avoid a dependency on the bootstrap library. +//! Therefore, this module should never use any other bootstrap module. This reduces binary +//! size and improves compilation time by minimizing linking time. + +#![allow(dead_code)] use std::env; +use std::ffi::OsString; use std::fs::OpenOptions; use std::io::Write; use std::process::Command; use std::str::FromStr; +#[cfg(test)] +mod tests; + +/// Returns the environment variable which the dynamic library lookup path +/// resides in for this platform. +pub fn dylib_path_var() -> &'static str { + if cfg!(target_os = "windows") { + "PATH" + } else if cfg!(target_vendor = "apple") { + "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" + } else if cfg!(target_os = "aix") { + "LIBPATH" + } else { + "LD_LIBRARY_PATH" + } +} + +/// Parses the `dylib_path_var()` environment variable, returning a list of +/// paths that are members of this lookup path. +pub fn dylib_path() -> Vec { + let var = match std::env::var_os(dylib_path_var()) { + Some(v) => v, + None => return vec![], + }; + std::env::split_paths(&var).collect() +} + +/// Given an executable called `name`, return the filename for the +/// executable for a particular target. +#[allow(dead_code)] +pub fn exe(name: &str, target: &str) -> String { + if target.contains("windows") { + format!("{name}.exe") + } else if target.contains("uefi") { + format!("{name}.efi") + } else { + name.to_string() + } +} + /// Parses the value of the "RUSTC_VERBOSE" environment variable and returns it as a `usize`. /// If it was not defined, returns 0 by default. /// /// Panics if "RUSTC_VERBOSE" is defined with the value that is not an unsigned integer. -pub(crate) fn parse_rustc_verbose() -> usize { +pub fn parse_rustc_verbose() -> usize { match env::var("RUSTC_VERBOSE") { Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"), Err(_) => 0, @@ -22,7 +69,7 @@ pub(crate) fn parse_rustc_verbose() -> usize { /// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`. /// /// If "RUSTC_STAGE" was not set, the program will be terminated with 101. -pub(crate) fn parse_rustc_stage() -> String { +pub fn parse_rustc_stage() -> String { env::var("RUSTC_STAGE").unwrap_or_else(|_| { // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead. eprintln!("rustc shim: FATAL: RUSTC_STAGE was not set"); @@ -35,7 +82,7 @@ pub(crate) fn parse_rustc_stage() -> String { /// /// Before writing it, replaces user-specific values to create generic dumps for cross-environment /// comparisons. -pub(crate) fn maybe_dump(dump_name: String, cmd: &Command) { +pub fn maybe_dump(dump_name: String, cmd: &Command) { if let Ok(dump_dir) = env::var("DUMP_BOOTSTRAP_SHIMS") { let dump_file = format!("{dump_dir}/{dump_name}"); From 9098474dadaa7a6034652313bd4914ddbcf764c5 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Sat, 29 Jun 2024 08:06:26 +0300 Subject: [PATCH 2/2] create `shared_helpers::parse_value_from_args` Signed-off-by: onur-ozkan --- src/bootstrap/src/bin/rustc.rs | 27 +++++++++--------- src/bootstrap/src/bin/rustdoc.rs | 20 ++++++------- src/bootstrap/src/utils/helpers.rs | 4 +-- src/bootstrap/src/utils/shared_helpers.rs | 17 ++++++++++- .../src/utils/shared_helpers/tests.rs | 28 +++++++++++++++++++ 5 files changed, 69 insertions(+), 27 deletions(-) create mode 100644 src/bootstrap/src/utils/shared_helpers/tests.rs diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index d2274199177..009e62469b4 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -20,26 +20,24 @@ use std::process::{Child, Command}; use std::time::Instant; -use dylib_util::{dylib_path, dylib_path_var, exe}; +use shared_helpers::{ + dylib_path, dylib_path_var, exe, maybe_dump, parse_rustc_stage, parse_rustc_verbose, + parse_value_from_args, +}; -#[path = "../utils/bin_helpers.rs"] -mod bin_helpers; - -#[path = "../utils/dylib.rs"] -mod dylib_util; +#[path = "../utils/shared_helpers.rs"] +mod shared_helpers; fn main() { let orig_args = env::args_os().skip(1).collect::>(); let mut args = orig_args.clone(); - let arg = - |name| orig_args.windows(2).find(|args| args[0] == name).and_then(|args| args[1].to_str()); - let stage = bin_helpers::parse_rustc_stage(); - let verbose = bin_helpers::parse_rustc_verbose(); + let stage = parse_rustc_stage(); + let verbose = parse_rustc_verbose(); // Detect whether or not we're a build script depending on whether --target // is passed (a bit janky...) - let target = arg("--target"); + let target = parse_value_from_args(&orig_args, "--target"); let version = args.iter().find(|w| &**w == "-vV"); // Use a different compiler for build scripts, since there may not yet be a @@ -102,7 +100,7 @@ fn main() { cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); // Get the name of the crate we're compiling, if any. - let crate_name = arg("--crate-name"); + let crate_name = parse_value_from_args(&orig_args, "--crate-name"); if let Some(crate_name) = crate_name { if let Some(target) = env::var_os("RUSTC_TIME") { @@ -143,10 +141,11 @@ fn main() { cmd.arg("-C").arg("panic=abort"); } + let crate_type = parse_value_from_args(&orig_args, "--crate-type"); // `-Ztls-model=initial-exec` must not be applied to proc-macros, see // issue https://github.com/rust-lang/rust/issues/100530 if env::var("RUSTC_TLS_MODEL_INITIAL_EXEC").is_ok() - && arg("--crate-type") != Some("proc-macro") + && crate_type != Some("proc-macro") && !matches!(crate_name, Some("proc_macro2" | "quote" | "syn" | "synstructure")) { cmd.arg("-Ztls-model=initial-exec"); @@ -251,7 +250,7 @@ fn main() { eprintln!("{prefix} libdir: {libdir:?}"); } - bin_helpers::maybe_dump(format!("stage{stage}-rustc"), &cmd); + maybe_dump(format!("stage{stage}-rustc"), &cmd); let start = Instant::now(); let (child, status) = { diff --git a/src/bootstrap/src/bin/rustdoc.rs b/src/bootstrap/src/bin/rustdoc.rs index b4d1415189c..ba6b0c2dbda 100644 --- a/src/bootstrap/src/bin/rustdoc.rs +++ b/src/bootstrap/src/bin/rustdoc.rs @@ -6,19 +6,19 @@ use std::path::PathBuf; use std::process::Command; -use dylib_util::{dylib_path, dylib_path_var}; +use shared_helpers::{ + dylib_path, dylib_path_var, maybe_dump, parse_rustc_stage, parse_rustc_verbose, + parse_value_from_args, +}; -#[path = "../utils/bin_helpers.rs"] -mod bin_helpers; - -#[path = "../utils/dylib.rs"] -mod dylib_util; +#[path = "../utils/shared_helpers.rs"] +mod shared_helpers; fn main() { let args = env::args_os().skip(1).collect::>(); - let stage = bin_helpers::parse_rustc_stage(); - let verbose = bin_helpers::parse_rustc_verbose(); + let stage = parse_rustc_stage(); + let verbose = parse_rustc_verbose(); let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set"); let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set"); @@ -26,7 +26,7 @@ fn main() { // Detect whether or not we're a build script depending on whether --target // is passed (a bit janky...) - let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str()); + let target = parse_value_from_args(&args, "--target"); let mut dylib_path = dylib_path(); dylib_path.insert(0, PathBuf::from(libdir.clone())); @@ -62,7 +62,7 @@ fn main() { cmd.arg("-Zunstable-options"); cmd.arg("--check-cfg=cfg(bootstrap)"); - bin_helpers::maybe_dump(format!("stage{stage}-rustdoc"), &cmd); + maybe_dump(format!("stage{stage}-rustdoc"), &cmd); if verbose > 1 { eprintln!( diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 59b29eedb79..9fed7de6814 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -18,7 +18,7 @@ use crate::core::config::{Config, TargetSelection}; use crate::LldMode; -pub use crate::utils::dylib::{dylib_path, dylib_path_var}; +pub use crate::utils::shared_helpers::{dylib_path, dylib_path_var}; #[cfg(test)] mod tests; @@ -50,7 +50,7 @@ macro_rules! t { pub use t; pub fn exe(name: &str, target: TargetSelection) -> String { - crate::utils::dylib::exe(name, &target.triple) + crate::utils::shared_helpers::exe(name, &target.triple) } /// Returns `true` if the file name given looks like a dynamic library. diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs index 8ec7116f6ca..7150c84313c 100644 --- a/src/bootstrap/src/utils/shared_helpers.rs +++ b/src/bootstrap/src/utils/shared_helpers.rs @@ -44,7 +44,6 @@ pub fn dylib_path() -> Vec { /// Given an executable called `name`, return the filename for the /// executable for a particular target. -#[allow(dead_code)] pub fn exe(name: &str, target: &str) -> String { if target.contains("windows") { format!("{name}.exe") @@ -95,3 +94,19 @@ pub fn maybe_dump(dump_name: String, cmd: &Command) { file.write_all(cmd_dump.as_bytes()).expect("Unable to write file"); } } + +/// Finds `key` and returns its value from the given list of arguments `args`. +pub fn parse_value_from_args<'a>(args: &'a [OsString], key: &str) -> Option<&'a str> { + let mut args = args.iter(); + while let Some(arg) = args.next() { + let arg = arg.to_str().unwrap(); + + if let Some(value) = arg.strip_prefix(&format!("{key}=")) { + return Some(value); + } else if arg == key { + return args.next().map(|v| v.to_str().unwrap()); + } + } + + None +} diff --git a/src/bootstrap/src/utils/shared_helpers/tests.rs b/src/bootstrap/src/utils/shared_helpers/tests.rs new file mode 100644 index 00000000000..da7924276f7 --- /dev/null +++ b/src/bootstrap/src/utils/shared_helpers/tests.rs @@ -0,0 +1,28 @@ +use super::parse_value_from_args; + +#[test] +fn test_parse_value_from_args() { + let args = vec![ + "--stage".into(), + "1".into(), + "--version".into(), + "2".into(), + "--target".into(), + "x86_64-unknown-linux".into(), + ]; + + assert_eq!(parse_value_from_args(args.as_slice(), "--stage").unwrap(), "1"); + assert_eq!(parse_value_from_args(args.as_slice(), "--version").unwrap(), "2"); + assert_eq!(parse_value_from_args(args.as_slice(), "--target").unwrap(), "x86_64-unknown-linux"); + assert!(parse_value_from_args(args.as_slice(), "random-key").is_none()); + + let args = vec![ + "app-name".into(), + "--key".into(), + "value".into(), + "random-value".into(), + "--sysroot=/x/y/z".into(), + ]; + assert_eq!(parse_value_from_args(args.as_slice(), "--key").unwrap(), "value"); + assert_eq!(parse_value_from_args(args.as_slice(), "--sysroot").unwrap(), "/x/y/z"); +}