diff --git a/src/cargo/core/compiler/build_config.rs b/src/cargo/core/compiler/build_config.rs index d0f5431a47e..0d6f6ad60ea 100644 --- a/src/cargo/core/compiler/build_config.rs +++ b/src/cargo/core/compiler/build_config.rs @@ -45,6 +45,7 @@ impl BuildConfig { /// /// * `build.jobs` /// * `build.target` + /// * `build.test-target` /// * `target.$target.ar` /// * `target.$target.linker` /// * `target.$target.libfoo.metadata` @@ -55,7 +56,8 @@ impl BuildConfig { mode: CompileMode, ) -> CargoResult { let cfg = config.build_config()?; - let requested_kinds = CompileKind::from_requested_targets(config, requested_targets)?; + let requested_kinds = + CompileKind::from_requested_targets(config, requested_targets, Some(mode))?; if jobs == Some(0) { anyhow::bail!("jobs must be at least 1") } diff --git a/src/cargo/core/compiler/compile_kind.rs b/src/cargo/core/compiler/compile_kind.rs index 4c123601f8e..47c8b12fc56 100644 --- a/src/cargo/core/compiler/compile_kind.rs +++ b/src/cargo/core/compiler/compile_kind.rs @@ -1,3 +1,4 @@ +use crate::core::compiler::CompileMode; use crate::core::Target; use crate::util::errors::{CargoResult, CargoResultExt}; use crate::util::interning::InternedString; @@ -49,6 +50,7 @@ impl CompileKind { pub fn from_requested_targets( config: &Config, targets: &[String], + compile_mode: Option, ) -> CargoResult> { if targets.len() > 1 && !config.cli_unstable().multitarget { bail!("specifying multiple `--target` flags requires `-Zmultitarget`") @@ -64,7 +66,20 @@ impl CompileKind { .into_iter() .collect()); } - let kind = match &config.build_config()?.target { + + let build_configs = config.build_config()?; + let target = match compile_mode { + Some(CompileMode::Test) => { + if build_configs.test_target.is_some() { + &build_configs.test_target + } else { + &build_configs.target + } + } + _ => &build_configs.target, + }; + + let kind = match &target { Some(val) => { let value = if val.raw_value().ends_with(".json") { let path = val.clone().resolve_path(config); diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs index 5efa976f04d..ba01ff4e296 100644 --- a/src/cargo/ops/cargo_clean.rs +++ b/src/cargo/ops/cargo_clean.rs @@ -54,7 +54,7 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> { } // Clean specific packages. - let requested_kinds = CompileKind::from_requested_targets(config, &opts.targets)?; + let requested_kinds = CompileKind::from_requested_targets(config, &opts.targets, None)?; let target_data = RustcTargetData::new(ws, &requested_kinds)?; let (pkg_set, resolve) = ops::resolve_ws(ws)?; let prof_dir_name = profiles.get_dir_name(); diff --git a/src/cargo/ops/cargo_output_metadata.rs b/src/cargo/ops/cargo_output_metadata.rs index a3aaf2e7a07..6508cdac068 100644 --- a/src/cargo/ops/cargo_output_metadata.rs +++ b/src/cargo/ops/cargo_output_metadata.rs @@ -109,7 +109,7 @@ fn build_resolve_graph( // TODO: Without --filter-platform, features are being resolved for `host` only. // How should this work? let requested_kinds = - CompileKind::from_requested_targets(ws.config(), &metadata_opts.filter_platforms)?; + CompileKind::from_requested_targets(ws.config(), &metadata_opts.filter_platforms, None)?; let target_data = RustcTargetData::new(ws, &requested_kinds)?; // Resolve entire workspace. let specs = Packages::All.to_package_id_specs(ws)?; diff --git a/src/cargo/ops/tree/mod.rs b/src/cargo/ops/tree/mod.rs index 7c007778c17..2b0fef2adbd 100644 --- a/src/cargo/ops/tree/mod.rs +++ b/src/cargo/ops/tree/mod.rs @@ -133,7 +133,8 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<() }; // TODO: Target::All is broken with -Zfeatures=itarget. To handle that properly, // `FeatureResolver` will need to be taught what "all" means. - let requested_kinds = CompileKind::from_requested_targets(ws.config(), &requested_targets)?; + let requested_kinds = + CompileKind::from_requested_targets(ws.config(), &requested_targets, None)?; let target_data = RustcTargetData::new(ws, &requested_kinds)?; let specs = opts.packages.to_package_id_specs(ws)?; let resolve_opts = ResolveOpts::new( diff --git a/src/cargo/util/config/mod.rs b/src/cargo/util/config/mod.rs index dde02ac6253..7196be2b976 100644 --- a/src/cargo/util/config/mod.rs +++ b/src/cargo/util/config/mod.rs @@ -1768,6 +1768,7 @@ pub struct CargoBuildConfig { pub target_dir: Option, pub incremental: Option, pub target: Option, + pub test_target: Option, pub jobs: Option, pub rustflags: Option, pub rustdocflags: Option, diff --git a/src/doc/src/reference/config.md b/src/doc/src/reference/config.md index 6fafaecc962..269483f22b0 100644 --- a/src/doc/src/reference/config.md +++ b/src/doc/src/reference/config.md @@ -58,7 +58,8 @@ jobs = 1 # number of parallel jobs, defaults to # of CPUs rustc = "rustc" # the rust compiler tool rustc-wrapper = "…" # run this wrapper instead of `rustc` rustdoc = "rustdoc" # the doc generator tool -target = "triple" # build for the target triple (ignored by `cargo install`) +target = "triple" # default build for the target triple (ignored by `cargo install`) +test-target = "triple" # build target triple when `cargo test` is invoked (overrides `build.target` option) target-dir = "target" # path of where to place all generated artifacts rustflags = ["…", "…"] # custom flags to pass to all compiler invocations rustdocflags = ["…", "…"] # custom flags to pass to rustdoc diff --git a/tests/testsuite/cross_compile.rs b/tests/testsuite/cross_compile.rs index fe573a88270..b019a4c43b6 100644 --- a/tests/testsuite/cross_compile.rs +++ b/tests/testsuite/cross_compile.rs @@ -117,6 +117,63 @@ fn simple_cross_config() { } } +#[cargo_test] +fn simple_cross_test_config() { + if cross_compile::disabled() { + return; + } + + let p = project() + .file( + ".cargo/config", + &format!( + r#" + [build] + test-target = "{}" + "#, + cross_compile::alternate() + ), + ) + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.0" + authors = [] + "#, + ) + .file( + "src/main.rs", + &format!( + r#" + use std::env; + + fn main() {{ + assert_ne!(env::consts::ARCH, "{}"); + }} + + #[cfg(test)] + mod tests {{ + use super::*; + fn test_on_non_host_target() {{ + assert_eq!(env::consts::ARCH, "{}"); + }} + }} + "#, + cross_compile::alternate_arch(), + cross_compile::alternate_arch() + ), + ) + .build(); + + p.cargo("build -v").run(); + + if cross_compile::can_run_on_host() { + p.cargo("test").run(); + } +} + #[cargo_test] fn simple_deps() { if cross_compile::disabled() {