Skip to content

Add support for custom target-specific runners #3954

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,8 +662,11 @@ fn scrape_target_config(config: &Config, triple: &str)
None => return Ok(ret),
};
for (lib_name, value) in table {
if lib_name == "ar" || lib_name == "linker" || lib_name == "rustflags" {
continue
match lib_name.as_str() {
"ar" | "linker" | "runner" | "rustflags" => {
continue
},
_ => {}
}

let mut output = BuildOutput {
Expand Down
22 changes: 20 additions & 2 deletions src/cargo/ops/cargo_rustc/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::path::PathBuf;
use semver::Version;

use core::{PackageId, Package, Target, TargetKind};
use util::{self, CargoResult, Config, ProcessBuilder, process, join_paths};
use util::{self, CargoResult, Config, LazyCell, ProcessBuilder, process, join_paths};

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

config: &'cfg Config,

target_runner: LazyCell<Option<(PathBuf, Vec<String>)>>,
}

impl<'cfg> Compilation<'cfg> {
Expand All @@ -72,6 +74,7 @@ impl<'cfg> Compilation<'cfg> {
cfgs: HashMap::new(),
config: config,
target: String::new(),
target_runner: LazyCell::new(),
}
}

Expand All @@ -91,10 +94,25 @@ impl<'cfg> Compilation<'cfg> {
self.fill_env(process(cmd), pkg, true)
}

fn target_runner(&self) -> CargoResult<&Option<(PathBuf, Vec<String>)>> {
self.target_runner.get_or_try_init(|| {
let key = format!("target.{}.runner", self.target);
Ok(self.config.get_path_and_args(&key)?.map(|v| v.val))
})
}

/// See `process`.
pub fn target_process<T: AsRef<OsStr>>(&self, cmd: T, pkg: &Package)
-> CargoResult<ProcessBuilder> {
self.fill_env(process(cmd), pkg, false)
let builder = if let &Some((ref runner, ref args)) = self.target_runner()? {
let mut builder = process(runner);
builder.args(args);
builder.arg(cmd);
builder
} else {
process(cmd)
};
self.fill_env(builder, pkg, false)
}

/// Prepares a new process with an appropriate environment to run against
Expand Down
36 changes: 26 additions & 10 deletions src/cargo/util/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,25 +215,41 @@ impl Config {
}
}

fn string_to_path(&self, value: String, definition: &Definition) -> PathBuf {
let is_path = value.contains('/') ||
(cfg!(windows) && value.contains('\\'));
if is_path {
definition.root(self).join(value)
} else {
// A pathless name
PathBuf::from(value)
}
}

pub fn get_path(&self, key: &str) -> CargoResult<Option<Value<PathBuf>>> {
if let Some(val) = self.get_string(key)? {
let is_path = val.val.contains('/') ||
(cfg!(windows) && val.val.contains('\\'));
let path = if is_path {
val.definition.root(self).join(val.val)
} else {
// A pathless name
PathBuf::from(val.val)
};
Ok(Some(Value {
val: path,
definition: val.definition,
val: self.string_to_path(val.val, &val.definition),
definition: val.definition
}))
} else {
Ok(None)
}
}

pub fn get_path_and_args(&self, key: &str)
-> CargoResult<Option<Value<(PathBuf, Vec<String>)>>> {
if let Some(mut val) = self.get_list_or_split_string(key)? {
if !val.val.is_empty() {
return Ok(Some(Value {
val: (self.string_to_path(val.val.remove(0), &val.definition), val.val),
definition: val.definition
}));
}
}
Ok(None)
}

pub fn get_list(&self, key: &str)
-> CargoResult<Option<Value<Vec<(String, PathBuf)>>>> {
match self.get(key)? {
Expand Down
15 changes: 10 additions & 5 deletions src/doc/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,20 @@ email = "..."
vcs = "none"

# For the following sections, $triple refers to any valid target triple, not the
# literal string "$triple", and it will apply whenever that target triple is
# literal string "$triple", and it will apply whenever that target triple is
# being compiled to. 'cfg(...)' refers to the Rust-like `#[cfg]` syntax for
# conditional compilation.
[target.$triple]
# This is the linker which is passed to rustc (via `-C linker=`) when the `$triple`
[target.$triple]
# This is the linker which is passed to rustc (via `-C linker=`) when the `$triple`
# is being compiled for. By default this flag is not passed to the compiler.
linker = ".."
# Same but for the library archiver which is passed to rustc via `-C ar=`.
linker = ".."
# Same but for the library archiver which is passed to rustc via `-C ar=`.
ar = ".."
# If a runner is provided, compiled targets for the `$triple` will be executed
# by invoking the specified runner executable with actual target as first argument.
# This applies to `cargo run`, `cargo test` and `cargo bench` commands.
# By default compiled targets are executed directly.
runner = ".."
# custom flags to pass to all compiler invocations that target $triple
# this value overrides build.rustflags when both are present
rustflags = ["..", ".."]
Expand Down
45 changes: 45 additions & 0 deletions tests/tool-paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,48 @@ fn relative_tools() {
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
", url = foo_url, ar = output.0, linker = output.1)))
}

#[test]
fn custom_runner() {
let target = rustc_host();

let foo = project("foo")
.file("Cargo.toml", r#"
[package]
name = "foo"
version = "0.0.1"
"#)
.file("src/main.rs", "fn main() {}")
.file("tests/test.rs", "")
.file("benches/bench.rs", "")
.file(".cargo/config", &format!(r#"
[target.{}]
runner = "nonexistent-runner -r"
"#, target));

foo.build();

assert_that(foo.cargo("run").args(&["--", "--param"]),
execs().with_stderr_contains(&format!("\
[COMPILING] foo v0.0.1 ({url})
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r target[/]debug[/]foo[EXE] --param`
", url = foo.url())));

assert_that(foo.cargo("test").args(&["--test", "test", "--verbose", "--", "--param"]),
execs().with_stderr_contains(&format!("\
[COMPILING] foo v0.0.1 ({url})
[RUNNING] `rustc [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..][/]target[/]debug[/]deps[/]test-[..][EXE] --param`
", url = foo.url())));

assert_that(foo.cargo("bench").args(&["--bench", "bench", "--verbose", "--", "--param"]),
execs().with_stderr_contains(&format!("\
[COMPILING] foo v0.0.1 ({url})
[RUNNING] `rustc [..]`
[RUNNING] `rustc [..]`
[FINISHED] release [optimized] target(s) in [..]
[RUNNING] `nonexistent-runner -r [..][/]target[/]release[/]deps[/]bench-[..][EXE] --param --bench`
", url = foo.url())));
}