Skip to content

Commit

Permalink
Auto merge of rust-lang#122460 - jieyouxu:rmake-example-refactor, r=N…
Browse files Browse the repository at this point in the history
…ilstrieb

Rework rmake support library API

### Take 1: Strongly-typed API

Context: rust-lang#122448 (comment)

> My 2 cents: from my experience with writing similar "test DSLs", I would suggest to create these helpers as soon as possible in the process (basically the first time someone needs them, not only after N similar usages), and basically treat any imperative code in these high-level tests as a maintenance burden, basically making them as declarative as possible. Otherwise it might be a bit annoying to keep refactoring the tests later once such helpers are available.
>
> I would even discourage the arg method and create explicit methods for setting things like unpretty, the output file etc., but this might be more controversial, as it will make the invoked command-line arguments more opaque.

cc `@Kobzol` for the testing DSL suggestion.

Example:

```rs
let output = Rustc::new()
    .input_file("main.rs")
    .emit(&[EmitKind::Metadata])
    .extern_("stable", &stable_path)
    .output();
```

### Take 2: xshell-based macro API

Example:

```rs
let sh = Shell::new()?;
let stable_path = stable_path.to_string_lossy();
let output = cmd!(sh, "rustc main.rs --emit=metadata --extern stable={stable_path}").output()?;
```

### Take 3: Weakly-typed API with a few helper methods

```rs
let output = Rustc::new()
    .input("main.rs")
    .emit("metadata")
    .extern_("stable", &stable_path)
    .output();
```
  • Loading branch information
bors committed Mar 27, 2024
2 parents d5db7fb + 1f2178b commit 0157da4
Show file tree
Hide file tree
Showing 19 changed files with 404 additions and 282 deletions.
189 changes: 12 additions & 177 deletions src/tools/run-make-support/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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) -> ! {
Expand All @@ -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
}
67 changes: 67 additions & 0 deletions src/tools/run-make-support/src/run.rs
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit 0157da4

Please sign in to comment.