Skip to content

Commit c828984

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

File tree

15 files changed

+241
-163
lines changed

15 files changed

+241
-163
lines changed

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

Lines changed: 96 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
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 wasmparser;
68

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

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

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

41+
/// A `rustc` invocation builder.
3542
#[derive(Debug)]
36-
pub struct RustcInvocationBuilder {
43+
pub struct Rustc {
3744
cmd: Command,
3845
}
3946

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

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

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

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

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

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

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

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

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

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

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

Lines changed: 67 additions & 0 deletions
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

Lines changed: 11 additions & 10 deletions
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)