Skip to content

Commit e1a85a6

Browse files
committed
Add support for custom target-specific runners
When `target.$triple.runner` is specified, it will be used for any execution commands by cargo including `cargo run`, `cargo test` and `cargo bench`. The original file is passed to the runner executable as a first argument. This allows to run tests when cross-comping Rust projects. This is not a complete solution, and might be extended in future for better ergonomics to support passing extra arguments to the runner itself or overriding runner from command line, but it should already unlock major existing usecases. Fixes #1411 Resolves #3626
1 parent 13d92c6 commit e1a85a6

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

src/cargo/ops/cargo_compile.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -662,8 +662,11 @@ fn scrape_target_config(config: &Config, triple: &str)
662662
None => return Ok(ret),
663663
};
664664
for (lib_name, value) in table {
665-
if lib_name == "ar" || lib_name == "linker" || lib_name == "rustflags" {
666-
continue
665+
match lib_name.as_str() {
666+
"ar" | "linker" | "runner" | "rustflags" => {
667+
continue
668+
},
669+
_ => {}
667670
}
668671

669672
let mut output = BuildOutput {

src/cargo/ops/cargo_rustc/compilation.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::path::PathBuf;
44
use semver::Version;
55

66
use core::{PackageId, Package, Target, TargetKind};
7-
use util::{self, CargoResult, Config, ProcessBuilder, process, join_paths};
7+
use util::{self, CargoResult, Config, LazyCell, ProcessBuilder, process, join_paths};
88

99
/// A structure returning the result of a compilation.
1010
pub struct Compilation<'cfg> {
@@ -53,6 +53,8 @@ pub struct Compilation<'cfg> {
5353
pub target: String,
5454

5555
config: &'cfg Config,
56+
57+
target_runner: LazyCell<Option<PathBuf>>,
5658
}
5759

5860
impl<'cfg> Compilation<'cfg> {
@@ -72,6 +74,7 @@ impl<'cfg> Compilation<'cfg> {
7274
cfgs: HashMap::new(),
7375
config: config,
7476
target: String::new(),
77+
target_runner: LazyCell::new(),
7578
}
7679
}
7780

@@ -91,10 +94,24 @@ impl<'cfg> Compilation<'cfg> {
9194
self.fill_env(process(cmd), pkg, true)
9295
}
9396

97+
fn target_runner(&self) -> CargoResult<&Option<PathBuf>> {
98+
self.target_runner.get_or_try_init(|| {
99+
let key = format!("target.{}.runner", self.target);
100+
Ok(self.config.get_path(&key)?.map(|v| v.val))
101+
})
102+
}
103+
94104
/// See `process`.
95105
pub fn target_process<T: AsRef<OsStr>>(&self, cmd: T, pkg: &Package)
96106
-> CargoResult<ProcessBuilder> {
97-
self.fill_env(process(cmd), pkg, false)
107+
let builder = if let &Some(ref runner) = self.target_runner()? {
108+
let mut builder = process(runner);
109+
builder.arg(cmd);
110+
builder
111+
} else {
112+
process(cmd)
113+
};
114+
self.fill_env(builder, pkg, false)
98115
}
99116

100117
/// Prepares a new process with an appropriate environment to run against

tests/tool-paths.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,48 @@ fn relative_tools() {
124124
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
125125
", url = foo_url, ar = output.0, linker = output.1)))
126126
}
127+
128+
#[test]
129+
fn custom_runner() {
130+
let target = rustc_host();
131+
132+
let foo = project("foo")
133+
.file("Cargo.toml", r#"
134+
[package]
135+
name = "foo"
136+
version = "0.0.1"
137+
"#)
138+
.file("src/main.rs", "fn main() {}")
139+
.file("tests/test.rs", "")
140+
.file("benches/bench.rs", "")
141+
.file(".cargo/config", &format!(r#"
142+
[target.{}]
143+
runner = "nonexistent-runner"
144+
"#, target));
145+
146+
foo.build();
147+
148+
assert_that(foo.cargo("run").args(&["--", "--param"]),
149+
execs().with_stderr_contains(&format!("\
150+
[COMPILING] foo v0.0.1 ({url})
151+
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
152+
[RUNNING] `nonexistent-runner target[/]debug[/]foo[EXE] --param`
153+
", url = foo.url())));
154+
155+
assert_that(foo.cargo("test").args(&["--test", "test", "--verbose", "--", "--param"]),
156+
execs().with_stderr_contains(&format!("\
157+
[COMPILING] foo v0.0.1 ({url})
158+
[RUNNING] `rustc [..]`
159+
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
160+
[RUNNING] `nonexistent-runner [..][/]target[/]debug[/]deps[/]test-[..][EXE] --param`
161+
", url = foo.url())));
162+
163+
assert_that(foo.cargo("bench").args(&["--bench", "bench", "--verbose", "--", "--param"]),
164+
execs().with_stderr_contains(&format!("\
165+
[COMPILING] foo v0.0.1 ({url})
166+
[RUNNING] `rustc [..]`
167+
[RUNNING] `rustc [..]`
168+
[FINISHED] release [optimized] target(s) in [..]
169+
[RUNNING] `nonexistent-runner [..][/]target[/]release[/]deps[/]bench-[..][EXE] --param --bench`
170+
", url = foo.url())));
171+
}

0 commit comments

Comments
 (0)