diff --git a/src/cargo/core/compiler/build_context/target_info.rs b/src/cargo/core/compiler/build_context/target_info.rs index a8561278e58..1c11a93169f 100644 --- a/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/cargo/core/compiler/build_context/target_info.rs @@ -816,6 +816,9 @@ pub struct RustcTargetData<'cfg> { target_config: HashMap, /// Information about the target platform that we're building for. target_info: HashMap, + + /// True if a `--target` flag is passed. + is_cross: bool, } impl<'cfg> RustcTargetData<'cfg> { @@ -834,13 +837,14 @@ impl<'cfg> RustcTargetData<'cfg> { } else { config.host_cfg_triple(&rustc.host)? }; + let is_cross = !requested_kinds.iter().any(CompileKind::is_host); // This is a hack. The unit_dependency graph builder "pretends" that // `CompileKind::Host` is `CompileKind::Target(host)` if the // `--target` flag is not specified. Since the unit_dependency code // needs access to the target config data, create a copy so that it // can be found. See `rebuild_unit_graph_shared` for why this is done. - if requested_kinds.iter().any(CompileKind::is_host) { + if !is_cross { let ct = CompileTarget::new(&rustc.host)?; target_info.insert(ct, host_info.clone()); target_config.insert(ct, config.target_cfg_triple(&rustc.host)?); @@ -854,6 +858,7 @@ impl<'cfg> RustcTargetData<'cfg> { host_info, target_config, target_info, + is_cross, }; // Get all kinds we currently know about. @@ -954,6 +959,10 @@ impl<'cfg> RustcTargetData<'cfg> { pub fn script_override(&self, lib_name: &str, kind: CompileKind) -> Option<&BuildOutput> { self.target_config(kind).links_overrides.get(lib_name) } + + pub fn is_cross(&self) -> bool { + self.is_cross + } } /// Structure used to deal with Rustdoc fingerprinting diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index b3929b8df70..affd34d17aa 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -201,6 +201,13 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { ProfileRoot::Debug => "debug", }, ) + .env( + "CARGO_BUILD_DEPENDENCY_TYPE", + match unit.kind.is_host() { + true => "host", + false => "target", + }, + ) .env("HOST", &bcx.host_triple()) .env("RUSTC", &bcx.rustc().path) .env("RUSTDOC", &*bcx.config.rustdoc()?) @@ -211,6 +218,16 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult { cmd.env(&var, value); } + if !unit.kind.is_host() { + cmd.env( + "CARGO_BUILD_TYPE", + match &bcx.target_data.is_cross() { + true => "cross", + false => "native", + }, + ); + } + if let Some(linker) = &bcx.target_data.target_config(unit.kind).linker { cmd.env( "RUSTC_LINKER", diff --git a/src/doc/src/reference/environment-variables.md b/src/doc/src/reference/environment-variables.md index d49922afbfd..7f4fea0696b 100644 --- a/src/doc/src/reference/environment-variables.md +++ b/src/doc/src/reference/environment-variables.md @@ -299,6 +299,13 @@ let out_dir = env::var("OUT_DIR").unwrap(); `out_dir` will now contain the value of `OUT_DIR`. * `CARGO` — Path to the `cargo` binary performing the build. +* `CARGO_BUILD_TYPE` — The type of build being performed. + `cross` when the build target is overridden. + `native` when a build target is not specified(default). + Note: only present for `target` dependency types +* `CARGO_BUILD_DEPENDENCY_TYPE` — The type of build this is a dependency for. + `host` when the build target is for the host. + `target` when a build target is for the target. * `CARGO_MANIFEST_DIR` — The directory containing the manifest for the package being built (the package containing the build script). Also note that this is the value of the diff --git a/tests/testsuite/build_script.rs b/tests/testsuite/build_script.rs index e81f6ef1ece..4dd7f1800a4 100644 --- a/tests/testsuite/build_script.rs +++ b/tests/testsuite/build_script.rs @@ -129,9 +129,11 @@ fn custom_build_env_vars() { let rustdoc = env::var("RUSTDOC").unwrap(); assert_eq!(rustdoc, "rustdoc"); + // TODO: Fix so that these are correct + // assert_eq!(env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap(), "target"); + // assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "native"); assert!(env::var("RUSTC_WRAPPER").is_err()); assert!(env::var("RUSTC_WORKSPACE_WRAPPER").is_err()); - assert!(env::var("RUSTC_LINKER").is_err()); assert!(env::var("RUSTFLAGS").is_err()); @@ -348,6 +350,7 @@ fn custom_build_env_var_rustc_linker() { use std::env; fn main() { + assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "cross"); assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker")); } "#, @@ -412,6 +415,7 @@ fn custom_build_env_var_rustc_linker_host_target() { use std::env; fn main() { + assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "cross"); assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker")); } "#, @@ -447,6 +451,7 @@ fn custom_build_env_var_rustc_linker_host_target_env() { use std::env; fn main() { + assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "cross"); assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/linker")); } "#, @@ -624,6 +629,7 @@ fn custom_build_env_var_rustc_linker_cross_arch_host() { use std::env; fn main() { + assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "cross"); assert!(env::var("RUSTC_LINKER").unwrap().ends_with("/path/to/target/linker")); } "#, @@ -1048,6 +1054,9 @@ fn overrides_and_links() { r#" use std::env; fn main() { + // TODO: Fix so that these are correct + // assert_eq!(env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap(), "target"); + // assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "native"); assert_eq!(env::var("DEP_FOO_FOO").ok().expect("FOO missing"), "bar"); assert_eq!(env::var("DEP_FOO_BAR").ok().expect("BAR missing"), @@ -1153,6 +1162,9 @@ fn links_passes_env_vars() { r#" use std::env; fn main() { + // TODO: Fix so that these are correct + // assert_eq!(env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap(), "target"); + // assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "native"); assert_eq!(env::var("DEP_FOO_FOO").unwrap(), "bar"); assert_eq!(env::var("DEP_FOO_BAR").unwrap(), "baz"); } @@ -1276,6 +1288,9 @@ fn rebuild_continues_to_pass_env_vars() { r#" use std::env; fn main() { + // TODO: Fix so that these are correct + // assert_eq!(env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap(), "target"); + // assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "native"); assert_eq!(env::var("DEP_FOO_FOO").unwrap(), "bar"); assert_eq!(env::var("DEP_FOO_BAR").unwrap(), "baz"); } @@ -2336,6 +2351,223 @@ fn test_duplicate_deps() { p.cargo("build").run(); } +#[cargo_test] +fn test_duplicate_shared_deps_native() { + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.1.0" + authors = [] + build = "build.rs" + + [dependencies] + bar = { path = 'bar' } + + [build-dependencies] + bar = { path = 'bar' } + "#, + ) + .file( + "src/main.rs", + r#" + extern crate bar; + fn main() { bar::do_nothing() } + "#, + ) + .file( + "build.rs", + r#" + extern crate bar; + use std::env; + fn main() { + bar::do_nothing(); + // TODO: Fix so that these are correct + // assert_eq!(env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap(), "target"); + // assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "native"); + } + "#, + ) + .file( + "bar/Cargo.toml", + r#" + [project] + name = "bar" + version = "0.1.0" + authors = [] + links = "foo" + build = "build.rs" + "#, + ) + .file( + "bar/build.rs", + r#" + use std::env; + fn main() { + println!("cargo:foo=bar"); + if env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap() == "host" { + assert!(env::var("CARGO_BUILD_TYPE").is_err()); + } else { + assert_eq!(env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap(), "target"); + assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "native"); + } + } + "#, + ) + .file("bar/src/lib.rs", "pub fn do_nothing() {}") + .build(); + + p.cargo("build -v").run(); +} + +#[cargo_test] +fn test_duplicate_shared_deps_host_cross() { + let target = rustc_host(); + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.1.0" + authors = [] + build = "build.rs" + + [dependencies] + bar = { path = 'bar' } + + [build-dependencies] + bar = { path = 'bar' } + "#, + ) + .file( + "src/main.rs", + r#" + extern crate bar; + fn main() { bar::do_nothing() } + "#, + ) + .file( + "build.rs", + r#" + extern crate bar; + use std::env; + fn main() { + bar::do_nothing(); + assert_eq!(env::var("DEP_FOO_FOO").unwrap(), "bar"); + assert_eq!(env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap(), "target"); + assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "cross"); + } + "#, + ) + .file( + "bar/Cargo.toml", + r#" + [project] + name = "bar" + version = "0.1.0" + authors = [] + links = "foo" + build = "build.rs" + "#, + ) + .file( + "bar/build.rs", + r#" + use std::env; + fn main() { + println!("cargo:foo=bar"); + if env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap() == "host" { + assert!(env::var("CARGO_BUILD_TYPE").is_err()); + } else { + assert_eq!(env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap(), "target"); + assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "cross"); + } + } + "#, + ) + .file("bar/src/lib.rs", "pub fn do_nothing() {}") + .build(); + + p.cargo("build -v --target").arg(&target).run(); +} + +#[cargo_test] +fn test_duplicate_shared_deps_alt_cross() { + if cross_compile::disabled() { + return; + } + let cross_target = cross_compile::alternate(); + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.1.0" + authors = [] + build = "build.rs" + + [dependencies] + bar = { path = 'bar' } + + [build-dependencies] + bar = { path = 'bar' } + "#, + ) + .file( + "src/main.rs", + r#" + extern crate bar; + fn main() { bar::do_nothing() } + "#, + ) + .file( + "build.rs", + r#" + extern crate bar; + use std::env; + fn main() { + bar::do_nothing(); + assert_eq!(env::var("DEP_FOO_FOO").unwrap(), "bar"); + assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "cross"); + } + "#, + ) + .file( + "bar/Cargo.toml", + r#" + [project] + name = "bar" + version = "0.1.0" + authors = [] + links = "foo" + build = "build.rs" + "#, + ) + .file( + "bar/build.rs", + r#" + use std::env; + fn main() { + println!("cargo:foo=bar"); + if env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap() == "host" { + assert!(env::var("CARGO_BUILD_TYPE").is_err()); + } else { + assert_eq!(env::var("CARGO_BUILD_DEPENDENCY_TYPE").unwrap(), "target"); + assert_eq!(env::var("CARGO_BUILD_TYPE").unwrap(), "cross"); + } + } + "#, + ) + .file("bar/src/lib.rs", "pub fn do_nothing() {}") + .build(); + + p.cargo("build --target").arg(&cross_target).run(); +} + #[cargo_test] fn cfg_feedback() { let p = project()