Skip to content

Commit 4e8753b

Browse files
committed
Rework rmake support library to have a weakly-typed API with helper methods
1 parent c3b05c6 commit 4e8753b

File tree

15 files changed

+240
-163
lines changed

15 files changed

+240
-163
lines changed

src/tools/run-make-support/src/lib.rs

+96-91
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
pub mod run;
2+
13
use std::env;
24
use std::path::{Path, PathBuf};
35
use std::process::{Command, Output};
46

57
pub use object;
68
pub use wasmparser;
79

10+
pub use run::{run, run_fail};
11+
812
pub fn out_dir() -> PathBuf {
913
env::var_os("TMPDIR").unwrap().into()
1014
}
@@ -25,65 +29,122 @@ fn handle_failed_output(cmd: &str, output: Output, caller_line_number: u32) -> !
2529
std::process::exit(1)
2630
}
2731

28-
pub fn rustc() -> RustcInvocationBuilder {
29-
RustcInvocationBuilder::new()
32+
/// Construct a new `rustc` invocation.
33+
pub fn rustc() -> Rustc {
34+
Rustc::new()
3035
}
3136

32-
pub fn aux_build() -> AuxBuildInvocationBuilder {
33-
AuxBuildInvocationBuilder::new()
37+
/// Construct a new `rustc` aux-build invocation.
38+
pub fn aux_build() -> Rustc {
39+
Rustc::new_aux_build()
3440
}
3541

42+
/// A `rustc` invocation builder.
3643
#[derive(Debug)]
37-
pub struct RustcInvocationBuilder {
44+
pub struct Rustc {
3845
cmd: Command,
3946
}
4047

41-
impl RustcInvocationBuilder {
42-
fn new() -> Self {
48+
impl Rustc {
49+
// `rustc` invocation constructor methods
50+
51+
/// Construct a new `rustc` invocation.
52+
pub fn new() -> Self {
4353
let cmd = setup_common_build_cmd();
4454
Self { cmd }
4555
}
4656

47-
pub fn arg(&mut self, arg: &str) -> &mut RustcInvocationBuilder {
48-
self.cmd.arg(arg);
57+
/// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`).
58+
pub fn new_aux_build() -> Self {
59+
let mut cmd = setup_common_build_cmd();
60+
cmd.arg("--crate-type=lib");
61+
Self { cmd }
62+
}
63+
64+
// Argument provider methods
65+
66+
/// Configure the compilation environment.
67+
pub fn cfg(&mut self, s: &str) -> &mut Self {
68+
self.cmd.arg("--cfg");
69+
self.cmd.arg(s);
4970
self
5071
}
5172

52-
pub fn args(&mut self, args: &[&str]) -> &mut RustcInvocationBuilder {
53-
self.cmd.args(args);
73+
/// Specify default optimization level `-O` (alias for `-C opt-level=2`).
74+
pub fn opt(&mut self) -> &mut Self {
75+
self.cmd.arg("-O");
5476
self
5577
}
5678

57-
#[track_caller]
58-
pub fn run(&mut self) -> Output {
59-
let caller_location = std::panic::Location::caller();
60-
let caller_line_number = caller_location.line();
79+
/// Specify type(s) of output files to generate.
80+
pub fn emit(&mut self, kinds: &str) -> &mut Self {
81+
self.cmd.arg(format!("--emit={kinds}"));
82+
self
83+
}
6184

62-
let output = self.cmd.output().unwrap();
63-
if !output.status.success() {
64-
handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
65-
}
66-
output
85+
/// Specify where an external library is located.
86+
pub fn extern_<P: AsRef<Path>>(&mut self, crate_name: &str, path: P) -> &mut Self {
87+
assert!(
88+
!crate_name.contains(|c: char| c.is_whitespace() || c == '\\' || c == '/'),
89+
"crate name cannot contain whitespace or path separators"
90+
);
91+
92+
let path = path.as_ref().to_string_lossy();
93+
94+
self.cmd.arg("--extern");
95+
self.cmd.arg(format!("{crate_name}={path}"));
96+
97+
self
6798
}
68-
}
6999

70-
#[derive(Debug)]
71-
pub struct AuxBuildInvocationBuilder {
72-
cmd: Command,
73-
}
100+
/// Specify path to the input file.
101+
pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
102+
self.cmd.arg(path.as_ref());
103+
self
104+
}
74105

75-
impl AuxBuildInvocationBuilder {
76-
fn new() -> Self {
77-
let mut cmd = setup_common_build_cmd();
78-
cmd.arg("--crate-type=lib");
79-
Self { cmd }
106+
/// Specify target triple.
107+
pub fn target(&mut self, target: &str) -> &mut Self {
108+
assert!(!target.contains(char::is_whitespace), "target triple cannot contain spaces");
109+
self.cmd.arg(format!("--target={target}"));
110+
self
80111
}
81112

82-
pub fn arg(&mut self, arg: &str) -> &mut AuxBuildInvocationBuilder {
113+
/// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
114+
/// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>`
115+
/// is passed (note the space).
116+
pub fn arg(&mut self, arg: &str) -> &mut Self {
117+
assert!(
118+
!(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")),
119+
"use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`"
120+
);
83121
self.cmd.arg(arg);
84122
self
85123
}
86124

125+
/// Generic command arguments provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
126+
/// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>`
127+
/// is passed (note the space).
128+
pub fn args(&mut self, args: &[&str]) -> &mut Self {
129+
for arg in args {
130+
assert!(
131+
!(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")),
132+
"use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`"
133+
);
134+
}
135+
136+
self.cmd.args(args);
137+
self
138+
}
139+
140+
// Command inspection, output and running helper methods
141+
142+
/// Get the [`Output`][std::process::Output] of the finished `rustc` process.
143+
pub fn output(&mut self) -> Output {
144+
self.cmd.output().unwrap()
145+
}
146+
147+
/// Run the constructed `rustc` command and assert that it is successfully run.
87148
#[track_caller]
88149
pub fn run(&mut self) -> Output {
89150
let caller_location = std::panic::Location::caller();
@@ -95,66 +156,10 @@ impl AuxBuildInvocationBuilder {
95156
}
96157
output
97158
}
98-
}
99-
100-
fn run_common(bin_name: &str) -> (Command, Output) {
101-
let target = env::var("TARGET").unwrap();
102-
103-
let bin_name =
104-
if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() };
105-
106-
let mut bin_path = PathBuf::new();
107-
bin_path.push(env::var("TMPDIR").unwrap());
108-
bin_path.push(&bin_name);
109-
let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap();
110-
let mut cmd = Command::new(bin_path);
111-
cmd.env(&ld_lib_path_envvar, {
112-
let mut paths = vec![];
113-
paths.push(PathBuf::from(env::var("TMPDIR").unwrap()));
114-
for p in env::split_paths(&env::var("TARGET_RPATH_ENV").unwrap()) {
115-
paths.push(p.to_path_buf());
116-
}
117-
for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) {
118-
paths.push(p.to_path_buf());
119-
}
120-
env::join_paths(paths.iter()).unwrap()
121-
});
122159

123-
if target.contains("windows") {
124-
let mut paths = vec![];
125-
for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) {
126-
paths.push(p.to_path_buf());
127-
}
128-
paths.push(Path::new(&std::env::var("TARGET_RPATH_DIR").unwrap()).to_path_buf());
129-
cmd.env("PATH", env::join_paths(paths.iter()).unwrap());
130-
}
131-
132-
let output = cmd.output().unwrap();
133-
(cmd, output)
134-
}
135-
136-
/// Run a built binary and make sure it succeeds.
137-
#[track_caller]
138-
pub fn run(bin_name: &str) -> Output {
139-
let caller_location = std::panic::Location::caller();
140-
let caller_line_number = caller_location.line();
141-
142-
let (cmd, output) = run_common(bin_name);
143-
if !output.status.success() {
144-
handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
145-
}
146-
output
147-
}
148-
149-
/// Run a built binary and make sure it fails.
150-
#[track_caller]
151-
pub fn run_fail(bin_name: &str) -> Output {
152-
let caller_location = std::panic::Location::caller();
153-
let caller_line_number = caller_location.line();
154-
155-
let (cmd, output) = run_common(bin_name);
156-
if output.status.success() {
157-
handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
160+
/// Inspect what the underlying [`Command`] is up to the current construction.
161+
pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self {
162+
f(&self.cmd);
163+
self
158164
}
159-
output
160165
}

src/tools/run-make-support/src/run.rs

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use std::env;
2+
use std::path::{Path, PathBuf};
3+
use std::process::{Command, Output};
4+
5+
use super::handle_failed_output;
6+
7+
fn run_common(bin_name: &str) -> (Command, Output) {
8+
let target = env::var("TARGET").unwrap();
9+
10+
let bin_name =
11+
if target.contains("windows") { format!("{}.exe", bin_name) } else { bin_name.to_owned() };
12+
13+
let mut bin_path = PathBuf::new();
14+
bin_path.push(env::var("TMPDIR").unwrap());
15+
bin_path.push(&bin_name);
16+
let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap();
17+
let mut cmd = Command::new(bin_path);
18+
cmd.env(&ld_lib_path_envvar, {
19+
let mut paths = vec![];
20+
paths.push(PathBuf::from(env::var("TMPDIR").unwrap()));
21+
for p in env::split_paths(&env::var("TARGET_RPATH_ENV").unwrap()) {
22+
paths.push(p.to_path_buf());
23+
}
24+
for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) {
25+
paths.push(p.to_path_buf());
26+
}
27+
env::join_paths(paths.iter()).unwrap()
28+
});
29+
30+
if target.contains("windows") {
31+
let mut paths = vec![];
32+
for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) {
33+
paths.push(p.to_path_buf());
34+
}
35+
paths.push(Path::new(&std::env::var("TARGET_RPATH_DIR").unwrap()).to_path_buf());
36+
cmd.env("PATH", env::join_paths(paths.iter()).unwrap());
37+
}
38+
39+
let output = cmd.output().unwrap();
40+
(cmd, output)
41+
}
42+
43+
/// Run a built binary and make sure it succeeds.
44+
#[track_caller]
45+
pub fn run(bin_name: &str) -> Output {
46+
let caller_location = std::panic::Location::caller();
47+
let caller_line_number = caller_location.line();
48+
49+
let (cmd, output) = run_common(bin_name);
50+
if !output.status.success() {
51+
handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
52+
}
53+
output
54+
}
55+
56+
/// Run a built binary and make sure it fails.
57+
#[track_caller]
58+
pub fn run_fail(bin_name: &str) -> Output {
59+
let caller_location = std::panic::Location::caller();
60+
let caller_line_number = caller_location.line();
61+
62+
let (cmd, output) = run_common(bin_name);
63+
if output.status.success() {
64+
handle_failed_output(&format!("{:#?}", cmd), output, caller_line_number);
65+
}
66+
output
67+
}

tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
// ignore-tidy-linelength
22

3+
// Check that the `CURRENT_RUSTC_VERSION` placeholder is correctly replaced by the current
4+
// `rustc` version and the `since` property in feature stability gating is properly respected.
5+
36
extern crate run_make_support;
47

58
use std::path::PathBuf;
69

7-
use run_make_support::{aux_build, rustc};
10+
use run_make_support::{rustc, aux_build};
811

912
fn main() {
10-
aux_build()
11-
.arg("--emit=metadata")
12-
.arg("stable.rs")
13-
.run();
13+
aux_build().input("stable.rs").emit("metadata").run();
14+
1415
let mut stable_path = PathBuf::from(env!("TMPDIR"));
1516
stable_path.push("libstable.rmeta");
17+
1618
let output = rustc()
17-
.arg("--emit=metadata")
18-
.arg("--extern")
19-
.arg(&format!("stable={}", &stable_path.to_string_lossy()))
20-
.arg("main.rs")
21-
.run();
19+
.input("main.rs")
20+
.emit("metadata")
21+
.extern_("stable", &stable_path)
22+
.output();
2223

2324
let stderr = String::from_utf8_lossy(&output.stderr);
2425
let version = include_str!(concat!(env!("S"), "/src/version"));

0 commit comments

Comments
 (0)