mirror of
https://github.com/rust-lang/cargo
synced 2024-10-01 05:23:56 +00:00
Auto merge of #10473 - weihanglo:multitarget-config, r=ehuss
Support `-Zmultitarget` in cargo config
This commit is contained in:
commit
1ef1e0a127
|
@ -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.
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue