From 1f2178b9e7b43f4efe549e19889eafeec9061e8c Mon Sep 17 00:00:00 2001 From: "许杰友 Jieyou Xu (Joe)" Date: Wed, 13 Mar 2024 21:52:23 +0000 Subject: Rework rmake support library to have a weakly-typed API with helper methods --- src/tools/run-make-support/src/lib.rs | 189 ++---------------------------- src/tools/run-make-support/src/run.rs | 67 +++++++++++ src/tools/run-make-support/src/rustc.rs | 147 +++++++++++++++++++++++ src/tools/run-make-support/src/rustdoc.rs | 80 +++++++++++++ 4 files changed, 306 insertions(+), 177 deletions(-) create mode 100644 src/tools/run-make-support/src/run.rs create mode 100644 src/tools/run-make-support/src/rustc.rs create mode 100644 src/tools/run-make-support/src/rustdoc.rs (limited to 'src/tools') diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 419b04231b5..7975677286d 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -1,19 +1,21 @@ +pub mod run; +pub mod rustc; +pub mod rustdoc; + use std::env; -use std::path::{Path, PathBuf}; -use std::process::{Command, Output}; +use std::path::PathBuf; +use std::process::Output; pub use object; pub use wasmparser; -pub fn out_dir() -> PathBuf { - env::var_os("TMPDIR").unwrap().into() -} +pub use run::{run, run_fail}; +pub use rustc::{aux_build, rustc, Rustc}; +pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; -fn setup_common_build_cmd(command: &str) -> Command { - let rustc = env::var(command).unwrap(); - let mut cmd = Command::new(rustc); - cmd.arg("--out-dir").arg(out_dir()).arg("-L").arg(out_dir()); - cmd +/// Path of `TMPDIR` (a temporary build directory, not under `/tmp`). +pub fn tmp_dir() -> PathBuf { + env::var_os("TMPDIR").unwrap().into() } fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! { @@ -24,170 +26,3 @@ fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> ! eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap()); std::process::exit(1) } - -pub fn rustc() -> RustcInvocationBuilder { - RustcInvocationBuilder::new() -} - -pub fn aux_build() -> AuxBuildInvocationBuilder { - AuxBuildInvocationBuilder::new() -} - -pub fn rustdoc() -> Rustdoc { - Rustdoc::new() -} - -#[derive(Debug)] -pub struct RustcInvocationBuilder { - cmd: Command, -} - -impl RustcInvocationBuilder { - fn new() -> Self { - let cmd = setup_common_build_cmd("RUSTC"); - Self { cmd } - } - - pub fn arg(&mut self, arg: &str) -> &mut RustcInvocationBuilder { - self.cmd.arg(arg); - self - } - - pub fn args(&mut self, args: &[&str]) -> &mut RustcInvocationBuilder { - self.cmd.args(args); - self - } - - #[track_caller] - pub fn run(&mut self) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let output = self.cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); - } - output - } -} - -#[derive(Debug)] -pub struct AuxBuildInvocationBuilder { - cmd: Command, -} - -impl AuxBuildInvocationBuilder { - fn new() -> Self { - let mut cmd = setup_common_build_cmd("RUSTC"); - cmd.arg("--crate-type=lib"); - Self { cmd } - } - - pub fn arg(&mut self, arg: &str) -> &mut AuxBuildInvocationBuilder { - self.cmd.arg(arg); - self - } - - #[track_caller] - pub fn run(&mut self) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let output = self.cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); - } - output - } -} - -#[derive(Debug)] -pub struct Rustdoc { - cmd: Command, -} - -impl Rustdoc { - fn new() -> Self { - let cmd = setup_common_build_cmd("RUSTDOC"); - Self { cmd } - } - - pub fn arg(&mut self, arg: &str) -> &mut Self { - self.cmd.arg(arg); - self - } - - #[track_caller] - pub fn run(&mut self) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let output = self.cmd.output().unwrap(); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); - } - output - } -} - -fn run_common(bin_name: &str) -> (Command, Output) { - let target = env::var("TARGET").unwrap(); - - let bin_name = - if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() }; - - let mut bin_path = PathBuf::new(); - bin_path.push(env::var("TMPDIR").unwrap()); - bin_path.push(&bin_name); - let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); - let mut cmd = Command::new(bin_path); - cmd.env(&ld_lib_path_envvar, { - let mut paths = vec![]; - paths.push(PathBuf::from(env::var("TMPDIR").unwrap())); - for p in env::split_paths(&env::var("TARGET_RPATH_ENV").unwrap()) { - paths.push(p.to_path_buf()); - } - for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) { - paths.push(p.to_path_buf()); - } - env::join_paths(paths.iter()).unwrap() - }); - - if target.contains("windows") { - let mut paths = vec![]; - for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) { - paths.push(p.to_path_buf()); - } - paths.push(Path::new(&std::env::var("TARGET_RPATH_DIR").unwrap()).to_path_buf()); - cmd.env("PATH", env::join_paths(paths.iter()).unwrap()); - } - - let output = cmd.output().unwrap(); - (cmd, output) -} - -/// Run a built binary and make sure it succeeds. -#[track_caller] -pub fn run(bin_name: &str) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let (cmd, output) = run_common(bin_name); - if !output.status.success() { - handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); - } - output -} - -/// Run a built binary and make sure it fails. -#[track_caller] -pub fn run_fail(bin_name: &str) -> Output { - let caller_location = std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let (cmd, output) = run_common(bin_name); - if output.status.success() { - handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); - } - output -} diff --git a/src/tools/run-make-support/src/run.rs b/src/tools/run-make-support/src/run.rs new file mode 100644 index 00000000000..42dcf54da22 --- /dev/null +++ b/src/tools/run-make-support/src/run.rs @@ -0,0 +1,67 @@ +use std::env; +use std::path::{Path, PathBuf}; +use std::process::{Command, Output}; + +use super::handle_failed_output; + +fn run_common(bin_name: &str) -> (Command, Output) { + let target = env::var("TARGET").unwrap(); + + let bin_name = + if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() }; + + let mut bin_path = PathBuf::new(); + bin_path.push(env::var("TMPDIR").unwrap()); + bin_path.push(&bin_name); + let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); + let mut cmd = Command::new(bin_path); + cmd.env(&ld_lib_path_envvar, { + let mut paths = vec![]; + paths.push(PathBuf::from(env::var("TMPDIR").unwrap())); + for p in env::split_paths(&env::var("TARGET_RPATH_ENV").unwrap()) { + paths.push(p.to_path_buf()); + } + for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) { + paths.push(p.to_path_buf()); + } + env::join_paths(paths.iter()).unwrap() + }); + + if target.contains("windows") { + let mut paths = vec![]; + for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) { + paths.push(p.to_path_buf()); + } + paths.push(Path::new(&std::env::var("TARGET_RPATH_DIR").unwrap()).to_path_buf()); + cmd.env("PATH", env::join_paths(paths.iter()).unwrap()); + } + + let output = cmd.output().unwrap(); + (cmd, output) +} + +/// Run a built binary and make sure it succeeds. +#[track_caller] +pub fn run(bin_name: &str) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let (cmd, output) = run_common(bin_name); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); + } + output +} + +/// Run a built binary and make sure it fails. +#[track_caller] +pub fn run_fail(bin_name: &str) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let (cmd, output) = run_common(bin_name); + if output.status.success() { + handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number); + } + output +} diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs new file mode 100644 index 00000000000..d0ab8df42d2 --- /dev/null +++ b/src/tools/run-make-support/src/rustc.rs @@ -0,0 +1,147 @@ +use std::env; +use std::path::Path; +use std::process::{Command, Output}; + +use crate::{handle_failed_output, tmp_dir}; + +/// Construct a new `rustc` invocation. +pub fn rustc() -> Rustc { + Rustc::new() +} + +/// Construct a new `rustc` aux-build invocation. +pub fn aux_build() -> Rustc { + Rustc::new_aux_build() +} + +/// A `rustc` invocation builder. +#[derive(Debug)] +pub struct Rustc { + cmd: Command, +} + +fn setup_common() -> Command { + let rustc = env::var("RUSTC").unwrap(); + let mut cmd = Command::new(rustc); + cmd.arg("--out-dir").arg(tmp_dir()).arg("-L").arg(tmp_dir()); + cmd +} + +impl Rustc { + // `rustc` invocation constructor methods + + /// Construct a new `rustc` invocation. + pub fn new() -> Self { + let cmd = setup_common(); + Self { cmd } + } + + /// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`). + pub fn new_aux_build() -> Self { + let mut cmd = setup_common(); + cmd.arg("--crate-type=lib"); + Self { cmd } + } + + // Argument provider methods + + /// Configure the compilation environment. + pub fn cfg(&mut self, s: &str) -> &mut Self { + self.cmd.arg("--cfg"); + self.cmd.arg(s); + self + } + + /// Specify default optimization level `-O` (alias for `-C opt-level=2`). + pub fn opt(&mut self) -> &mut Self { + self.cmd.arg("-O"); + self + } + + /// Specify type(s) of output files to generate. + pub fn emit(&mut self, kinds: &str) -> &mut Self { + self.cmd.arg(format!("--emit={kinds}")); + self + } + + /// Specify where an external library is located. + pub fn extern_>(&mut self, crate_name: &str, path: P) -> &mut Self { + assert!( + !crate_name.contains(|c: char| c.is_whitespace() || c == '\\' || c == '/'), + "crate name cannot contain whitespace or path separators" + ); + + let path = path.as_ref().to_string_lossy(); + + self.cmd.arg("--extern"); + self.cmd.arg(format!("{crate_name}={path}")); + + self + } + + /// Specify path to the input file. + pub fn input>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } + + /// Specify target triple. + pub fn target(&mut self, target: &str) -> &mut Self { + assert!(!target.contains(char::is_whitespace), "target triple cannot contain spaces"); + self.cmd.arg(format!("--target={target}")); + self + } + + /// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. + /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z ` or `-C ` + /// is passed (note the space). + pub fn arg(&mut self, arg: &str) -> &mut Self { + assert!( + !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")), + "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`" + ); + self.cmd.arg(arg); + self + } + + /// Generic command arguments provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. + /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z ` or `-C ` + /// is passed (note the space). + pub fn args(&mut self, args: &[&str]) -> &mut Self { + for arg in args { + assert!( + !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")), + "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`" + ); + } + + self.cmd.args(args); + self + } + + // Command inspection, output and running helper methods + + /// Get the [`Output`][std::process::Output] of the finished `rustc` process. + pub fn output(&mut self) -> Output { + self.cmd.output().unwrap() + } + + /// Run the constructed `rustc` command and assert that it is successfully run. + #[track_caller] + pub fn run(&mut self) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); + } + output + } + + /// Inspect what the underlying [`Command`] is up to the current construction. + pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self { + f(&self.cmd); + self + } +} diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs new file mode 100644 index 00000000000..9607ff02f96 --- /dev/null +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -0,0 +1,80 @@ +use std::env; +use std::path::Path; +use std::process::{Command, Output}; + +use crate::handle_failed_output; + +/// Construct a plain `rustdoc` invocation with no flags set. +pub fn bare_rustdoc() -> Rustdoc { + Rustdoc::bare() +} + +/// Construct a new `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set. +pub fn rustdoc() -> Rustdoc { + Rustdoc::new() +} + +#[derive(Debug)] +pub struct Rustdoc { + cmd: Command, +} + +fn setup_common() -> Command { + let rustdoc = env::var("RUSTDOC").unwrap(); + Command::new(rustdoc) +} + +impl Rustdoc { + /// Construct a bare `rustdoc` invocation. + pub fn bare() -> Self { + let cmd = setup_common(); + Self { cmd } + } + + /// Construct a `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set. + pub fn new() -> Self { + let mut cmd = setup_common(); + let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap(); + cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy())); + Self { cmd } + } + + /// Specify path to the input file. + pub fn input>(&mut self, path: P) -> &mut Self { + self.cmd.arg(path.as_ref()); + self + } + + /// Specify output directory. + pub fn out_dir>(&mut self, path: P) -> &mut Self { + self.cmd.arg("--out-dir").arg(path.as_ref()); + self + } + + /// Given a `path`, pass `@{path}` to `rustdoc` as an + /// [arg file](https://doc.rust-lang.org/rustdoc/command-line-arguments.html#path-load-command-line-flags-from-a-path). + pub fn arg_file>(&mut self, path: P) -> &mut Self { + self.cmd.arg(format!("@{}", path.as_ref().display())); + self + } + + /// Fallback argument provider. Consider adding meaningfully named methods instead of using + /// this method. + pub fn arg(&mut self, arg: &str) -> &mut Self { + self.cmd.arg(arg); + self + } + + /// Run the build `rustdoc` command and assert that the run is successful. + #[track_caller] + pub fn run(&mut self) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if !output.status.success() { + handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); + } + output + } +} -- cgit 1.4.1-3-g733a5