diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 79d8c47abed..0fc9a8145d9 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -530,6 +530,11 @@ fn prepare_rustc( let mut base = cx .compilation .rustc_process(unit, is_primary, is_workspace)?; + + if is_primary { + base.env("CARGO_PRIMARY_PACKAGE", "1"); + } + if cx.bcx.config.cli_unstable().jobserver_per_rustc { let client = cx.new_jobserver()?; base.inherit_jobserver(&client); diff --git a/src/doc/src/reference/environment-variables.md b/src/doc/src/reference/environment-variables.md index eec0d0aac04..4e9f36bc20e 100644 --- a/src/doc/src/reference/environment-variables.md +++ b/src/doc/src/reference/environment-variables.md @@ -265,6 +265,12 @@ let out_dir = env::var("OUT_DIR").unwrap(); Currently Cargo doesn't set the `MAKEFLAGS` variable, but it's free for build scripts invoking GNU Make to set it to the contents of `CARGO_MAKEFLAGS`. +* `CARGO_PRIMARY_PACKAGE` — This environment variable will be set if the package being + built is primary. Primary packages are the ones the user + selected on the command-line, either with `-p` flags or + the defaults based on the current directory and the default + workspace members. + This environment variable will not be set when building dependencies. * `CARGO_FEATURE_` — For each activated feature of the package being built, this environment variable will be present where `` is the name of the feature uppercased diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index 268ddbdf36f..a350286d55c 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -10,7 +10,7 @@ use cargo::{ use cargo_test_support::paths::{root, CargoPathExt}; use cargo_test_support::registry::Package; use cargo_test_support::{ - basic_bin_manifest, basic_lib_manifest, basic_manifest, is_nightly, lines_match_unordered, + basic_bin_manifest, basic_lib_manifest, basic_manifest, git, is_nightly, lines_match_unordered, main_file, paths, project, rustc_host, sleep_ms, symlink_supported, t, Execs, ProjectBuilder, }; use std::env; @@ -5179,3 +5179,68 @@ fn build_script_o0_default_even_with_release() { .with_stderr_does_not_contain("[..]build_script_build[..]opt-level[..]") .run(); } + +#[cargo_test] +fn primary_package_env_var() { + // Test that CARGO_PRIMARY_PACKAGE is enabled only for "foo" and not for any dependency. + + let is_primary_package = r#" + pub fn is_primary_package() -> bool {{ + option_env!("CARGO_PRIMARY_PACKAGE").is_some() + }} + "#; + + Package::new("qux", "0.1.0") + .file("src/lib.rs", is_primary_package) + .publish(); + + let baz = git::new("baz", |project| { + project + .file("Cargo.toml", &basic_manifest("baz", "0.1.0")) + .file("src/lib.rs", is_primary_package) + }); + + let foo = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ path = "bar" }} + baz = {{ git = '{}' }} + qux = "0.1" + "#, + baz.url() + ), + ) + .file( + "src/lib.rs", + &format!( + r#" + extern crate bar; + extern crate baz; + extern crate qux; + + {} + + #[test] + fn verify_primary_package() {{ + assert!(!bar::is_primary_package()); + assert!(!baz::is_primary_package()); + assert!(!qux::is_primary_package()); + assert!(is_primary_package()); + }} + "#, + is_primary_package + ), + ) + .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) + .file("bar/src/lib.rs", is_primary_package) + .build(); + + foo.cargo("test").run(); +} diff --git a/tests/testsuite/workspaces.rs b/tests/testsuite/workspaces.rs index c9ca991708d..a20ef11ba70 100644 --- a/tests/testsuite/workspaces.rs +++ b/tests/testsuite/workspaces.rs @@ -2319,3 +2319,80 @@ Caused by: ) .run(); } + +#[cargo_test] +fn simple_primary_package_env_var() { + let is_primary_package = r#" + #[test] + fn verify_primary_package() {{ + assert!(option_env!("CARGO_PRIMARY_PACKAGE").is_some()); + }} + "#; + + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.1.0" + authors = [] + + [workspace] + members = ["bar"] + "#, + ) + .file("src/lib.rs", is_primary_package) + .file( + "bar/Cargo.toml", + r#" + [project] + name = "bar" + version = "0.1.0" + authors = [] + workspace = ".." + "#, + ) + .file("bar/src/lib.rs", is_primary_package); + let p = p.build(); + + p.cargo("test").run(); + + // Again, this time selecting a specific crate + p.cargo("clean").run(); + p.cargo("test -p bar").run(); + + // Again, this time selecting all crates + p.cargo("clean").run(); + p.cargo("test --all").run(); +} + +#[cargo_test] +fn virtual_primary_package_env_var() { + let is_primary_package = r#" + #[test] + fn verify_primary_package() {{ + assert!(option_env!("CARGO_PRIMARY_PACKAGE").is_some()); + }} + "#; + + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["foo", "bar"] + "#, + ) + .file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0")) + .file("foo/src/lib.rs", is_primary_package) + .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0")) + .file("bar/src/lib.rs", is_primary_package); + let p = p.build(); + + p.cargo("test").run(); + + // Again, this time selecting a specific crate + p.cargo("clean").run(); + p.cargo("test -p foo").run(); +}