Auto merge of #10473 - weihanglo:multitarget-config, r=ehuss

Support `-Zmultitarget` in cargo config
This commit is contained in:
bors 2022-03-31 00:17:18 +00:00
commit 1ef1e0a127
4 changed files with 232 additions and 22 deletions

View file

@ -52,11 +52,8 @@ 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
@ -64,21 +61,22 @@ impl CompileKind {
.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)?)
}
None => CompileKind::Host,
.collect())
};
Ok(vec![kind])
if !targets.is_empty() {
if targets.len() > 1 && !config.cli_unstable().multitarget {
bail!("specifying multiple `--target` flags requires `-Zmultitarget`")
}
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)?),
};
kinds
}
/// Hash used for fingerprinting.

View file

@ -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>,
@ -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>,

View file

@ -238,6 +238,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

View file

@ -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();
}
@ -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() {
@ -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();
@ -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());
}