Skip to content
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

Support -Zmultitarget in cargo config #10473

Merged
merged 8 commits into from
Mar 31, 2022
Merged
34 changes: 16 additions & 18 deletions src/cargo/core/compiler/compile_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,33 +52,31 @@ impl CompileKind {
config: &Config,
targets: &[String],
) -> CargoResult<Vec<CompileKind>> {
if targets.len() > 1 && !config.cli_unstable().multitarget {
bail!("specifying multiple `--target` flags requires `-Zmultitarget`")
}
if !targets.is_empty() {
return Ok(targets
let dedup = |targets: &[String]| {
Ok(targets
.iter()
.map(|value| Ok(CompileKind::Target(CompileTarget::new(value)?)))
// First collect into a set to deduplicate any `--target` passed
// more than once...
.collect::<CargoResult<BTreeSet<_>>>()?
// ... then generate a flat list for everything else to use.
.into_iter()
.collect());
}
let kind = match &config.build_config()?.target {
Some(val) => {
let value = if val.raw_value().ends_with(".json") {
let path = val.clone().resolve_path(config);
path.to_str().expect("must be utf-8 in toml").to_string()
} else {
val.raw_value().to_string()
};
CompileKind::Target(CompileTarget::new(&value)?)
.collect())
};

if !targets.is_empty() {
if targets.len() > 1 && !config.cli_unstable().multitarget {
bail!("specifying multiple `--target` flags requires `-Zmultitarget`")
}
None => CompileKind::Host,
return dedup(targets);
}

let kinds = match &config.build_config()?.target {
None => Ok(vec![CompileKind::Host]),
Some(build_target_config) => dedup(&build_target_config.values(config)?),
};
Ok(vec![kind])

kinds
}

/// Hash used for fingerprinting.
Expand Down
57 changes: 56 additions & 1 deletion src/cargo/util/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2169,7 +2169,7 @@ pub struct CargoBuildConfig {
pub dep_info_basedir: Option<ConfigRelativePath>,
pub target_dir: Option<ConfigRelativePath>,
pub incremental: Option<bool>,
pub target: Option<ConfigRelativePath>,
pub target: Option<BuildTargetConfig>,
pub jobs: Option<u32>,
pub rustflags: Option<StringList>,
pub rustdocflags: Option<StringList>,
Expand All @@ -2180,6 +2180,61 @@ pub struct CargoBuildConfig {
pub out_dir: Option<ConfigRelativePath>,
}

/// Configuration for `build.target`.
///
/// Accepts in the following forms:
///
/// ```toml
/// target = "a"
/// target = ["a"]
/// target = ["a", "b"]
/// ```
#[derive(Debug, Deserialize)]
#[serde(transparent)]
pub struct BuildTargetConfig {
inner: Value<BuildTargetConfigInner>,
}

#[derive(Debug, Deserialize)]
#[serde(untagged)]
enum BuildTargetConfigInner {
One(String),
Many(Vec<String>),
}

impl BuildTargetConfig {
/// Gets values of `build.target` as a list of strings.
pub fn values(&self, config: &Config) -> CargoResult<Vec<String>> {
let map = |s: &String| {
if s.ends_with(".json") {
// Path to a target specification file (in JSON).
// <https://doc.rust-lang.org/rustc/targets/custom.html>
self.inner
.definition
.root(config)
.join(s)
.to_str()
.expect("must be utf-8 in toml")
.to_string()
} else {
// A string. Probably a target triple.
s.to_string()
}
};
let values = match &self.inner.val {
BuildTargetConfigInner::One(s) => vec![map(s)],
BuildTargetConfigInner::Many(v) => {
if !config.cli_unstable().multitarget {
bail!("specifying an array in `build.target` config value requires `-Zmultitarget`")
} else {
v.iter().map(map).collect()
}
}
};
Ok(values)
}
}

#[derive(Deserialize, Default)]
struct TermConfig {
verbose: Option<bool>,
Expand Down
6 changes: 6 additions & 0 deletions src/doc/src/reference/unstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,12 @@ or running tests for both targets:
cargo test --target x86_64-unknown-linux-gnu --target i686-unknown-linux-gnu
```

This can also be specified in `.cargo/config.toml` files.

```toml
[build]
target = ["x86_64-unknown-linux-gnu", "i686-unknown-linux-gnu"]
```

#### New `dir-name` attribute

Expand Down
155 changes: 153 additions & 2 deletions tests/testsuite/multitarget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,44 @@ fn double_target_rejected() {
.build();

p.cargo("build --target a --target b")
.with_stderr("error: specifying multiple `--target` flags requires `-Zmultitarget`")
.with_stderr("[ERROR] specifying multiple `--target` flags requires `-Zmultitarget`")
.with_status(101)
.run();
}

#[cargo_test]
fn array_of_target_rejected_with_config() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
.file("src/main.rs", "fn main() {}")
.file(
".cargo/config.toml",
r#"
[build]
target = ["a", "b"]
"#,
)
.build();

p.cargo("build")
.with_stderr(
"[ERROR] specifying an array in `build.target` config value requires `-Zmultitarget`",
)
.with_status(101)
.run();

p.change_file(
".cargo/config.toml",
r#"
[build]
target = ["a"]
"#,
);

p.cargo("build")
.with_stderr(
"[ERROR] specifying an array in `build.target` config value requires `-Zmultitarget`",
)
.with_status(101)
.run();
}
Expand Down Expand Up @@ -39,6 +76,35 @@ fn simple_build() {
assert!(p.target_bin(t2, "foo").is_file());
}

#[cargo_test]
fn simple_build_with_config() {
if cross_compile::disabled() {
return;
}
let t1 = cross_compile::alternate();
let t2 = rustc_host();
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
.file("src/main.rs", "fn main() {}")
.file(
".cargo/config.toml",
&format!(
r#"
[unstable]
multitarget = true
[build]
target = ["{t1}", "{t2}"]
"#
),
)
.build();

p.cargo("build").masquerade_as_nightly_cargo().run();

assert!(p.target_bin(t1, "foo").is_file());
assert!(p.target_bin(t2, "foo").is_file());
}

#[cargo_test]
fn simple_test() {
if !cross_compile::can_run_on_host() {
Expand Down Expand Up @@ -70,7 +136,7 @@ fn simple_run() {
.build();

p.cargo("run -Z multitarget --target a --target b")
.with_stderr("error: only one `--target` argument is supported")
.with_stderr("[ERROR] only one `--target` argument is supported")
.with_status(101)
.masquerade_as_nightly_cargo()
.run();
Expand Down Expand Up @@ -142,3 +208,88 @@ fn same_value_twice() {

assert!(p.target_bin(t, "foo").is_file());
}

#[cargo_test]
fn same_value_twice_with_config() {
if cross_compile::disabled() {
return;
}
let t = rustc_host();
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
.file("src/main.rs", "fn main() {}")
.file(
".cargo/config.toml",
&format!(
r#"
[unstable]
multitarget = true
[build]
target = ["{t}", "{t}"]
"#
),
)
.build();

p.cargo("build").masquerade_as_nightly_cargo().run();

assert!(p.target_bin(t, "foo").is_file());
}

#[cargo_test]
fn works_with_config_in_both_string_or_list() {
if cross_compile::disabled() {
return;
}
let t = rustc_host();
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
.file("src/main.rs", "fn main() {}")
.file(
".cargo/config.toml",
&format!(
r#"
[unstable]
multitarget = true
[build]
target = "{t}"
"#
),
)
.build();

p.cargo("build").masquerade_as_nightly_cargo().run();

assert!(p.target_bin(t, "foo").is_file());

p.cargo("clean").run();

p.change_file(
".cargo/config.toml",
&format!(
r#"
[unstable]
multitarget = true
[build]
target = ["{t}"]
"#
),
);

p.cargo("build").masquerade_as_nightly_cargo().run();

assert!(p.target_bin(t, "foo").is_file());
}

#[cargo_test]
fn works_with_env() {
let t = rustc_host();
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
.file("src/main.rs", "fn main() {}")
.build();

p.cargo("build").env("CARGO_BUILD_TARGET", t).run();

assert!(p.target_bin(t, "foo").is_file());
}