refactor: separate "global" mode from CompileMode (#15601)

### What does this PR try to resolve?

This separates the concern of two different "mode".

- UserIntent: focus on the overall goal of the build
- CompileMode: the actual compile operation for each unit (I'd like to
rename it to something else in the future, such as CompileAction)

This is a preparation of adding `-Zno-link`/`-Zlink-only` support,
which we'll have `CompileMode::Link` but that doesn't make sense to
show up in `UserIntent`.

### How should we test and review this PR?

It should have no functional change.

### Additional information
This commit is contained in:
Eric Huss 2025-05-28 23:50:22 +00:00 committed by GitHub
commit bffece899e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 204 additions and 169 deletions

View File

@ -61,7 +61,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let ws = args.workspace(gctx)?;
let mut compile_opts =
args.compile_options(gctx, CompileMode::Bench, Some(&ws), ProfileChecking::Custom)?;
args.compile_options(gctx, UserIntent::Bench, Some(&ws), ProfileChecking::Custom)?;
compile_opts.build_config.requested_profile =
args.get_profile_name("bench", ProfileChecking::Custom)?;

View File

@ -49,7 +49,7 @@ pub fn cli() -> Command {
pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let ws = args.workspace(gctx)?;
let mut compile_opts =
args.compile_options(gctx, CompileMode::Build, Some(&ws), ProfileChecking::Custom)?;
args.compile_options(gctx, UserIntent::Build, Some(&ws), ProfileChecking::Custom)?;
if let Some(artifact_dir) = args.value_of_path("artifact-dir", gctx) {
// If the user specifies `--artifact-dir`, use that

View File

@ -50,9 +50,9 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
args.get_one::<String>("profile").map(String::as_str),
Some("test")
);
let mode = CompileMode::Check { test };
let intent = UserIntent::Check { test };
let compile_opts =
args.compile_options(gctx, mode, Some(&ws), ProfileChecking::LegacyTestOnly)?;
args.compile_options(gctx, intent, Some(&ws), ProfileChecking::LegacyTestOnly)?;
ops::compile(&ws, &compile_opts)?;
Ok(())

View File

@ -48,11 +48,12 @@ pub fn cli() -> Command {
pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let ws = args.workspace(gctx)?;
let mode = CompileMode::Doc {
let intent = UserIntent::Doc {
deps: !args.flag("no-deps"),
json: false,
};
let mut compile_opts = args.compile_options(gctx, mode, Some(&ws), ProfileChecking::Custom)?;
let mut compile_opts =
args.compile_options(gctx, intent, Some(&ws), ProfileChecking::Custom)?;
compile_opts.rustdoc_document_private_items = args.flag("document-private-items");
let doc_opts = DocOptions {

View File

@ -67,7 +67,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
args.get_one::<String>("profile").map(String::as_str),
Some("test")
);
let mode = CompileMode::Check { test };
let intent = UserIntent::Check { test };
// Unlike other commands default `cargo fix` to all targets to fix as much
// code as we can.
@ -79,7 +79,8 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let lockfile_path = args.lockfile_path(gctx)?;
ws.set_requested_lockfile_path(lockfile_path.clone());
let mut opts = args.compile_options(gctx, mode, Some(&ws), ProfileChecking::LegacyTestOnly)?;
let mut opts =
args.compile_options(gctx, intent, Some(&ws), ProfileChecking::LegacyTestOnly)?;
let edition = args.flag("edition") || args.flag("edition-idioms");
if !opts.filter.is_specific() && edition {

View File

@ -216,7 +216,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let mut compile_opts = args.compile_options(
gctx,
CompileMode::Build,
UserIntent::Build,
workspace.as_ref(),
ProfileChecking::Custom,
)?;

View File

@ -51,7 +51,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let ws = args.workspace(gctx)?;
let mut compile_opts =
args.compile_options(gctx, CompileMode::Build, Some(&ws), ProfileChecking::Custom)?;
args.compile_options(gctx, UserIntent::Build, Some(&ws), ProfileChecking::Custom)?;
// Disallow `spec` to be an glob pattern
if let Packages::Packages(opt_in) = &compile_opts.spec {
@ -180,7 +180,7 @@ pub fn exec_manifest_command(gctx: &mut GlobalContext, cmd: &str, args: &[OsStri
}
let mut compile_opts =
cargo::ops::CompileOptions::new(gctx, cargo::core::compiler::CompileMode::Build)?;
cargo::ops::CompileOptions::new(gctx, cargo::core::compiler::UserIntent::Build)?;
compile_opts.spec = cargo::ops::Packages::Default;
cargo::ops::run(&ws, &compile_opts, args).map_err(|err| to_run_error(gctx, err))

View File

@ -64,15 +64,15 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
// This is a legacy behavior that changes the behavior based on the profile.
// If we want to support this more formally, I think adding a --mode flag
// would be warranted.
let mode = match args.get_one::<String>("profile").map(String::as_str) {
Some("test") => CompileMode::Test,
Some("bench") => CompileMode::Bench,
Some("check") => CompileMode::Check { test: false },
_ => CompileMode::Build,
let intent = match args.get_one::<String>("profile").map(String::as_str) {
Some("test") => UserIntent::Test,
Some("bench") => UserIntent::Bench,
Some("check") => UserIntent::Check { test: false },
_ => UserIntent::Build,
};
let mut compile_opts = args.compile_options_for_single_package(
gctx,
mode,
intent,
Some(&ws),
ProfileChecking::LegacyRustc,
)?;

View File

@ -64,7 +64,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let mut compile_opts = args.compile_options_for_single_package(
gctx,
CompileMode::Doc {
UserIntent::Doc {
deps: false,
json: matches!(output_format, OutputFormat::Json),
},

View File

@ -72,7 +72,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
let ws = args.workspace(gctx)?;
let mut compile_opts =
args.compile_options(gctx, CompileMode::Test, Some(&ws), ProfileChecking::Custom)?;
args.compile_options(gctx, UserIntent::Test, Some(&ws), ProfileChecking::Custom)?;
compile_opts.build_config.requested_profile =
args.get_profile_name("test", ProfileChecking::Custom)?;
@ -95,7 +95,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult {
if no_run {
return Err(anyhow::format_err!("Can't skip running doc tests with --no-run").into());
}
compile_opts.build_config.mode = CompileMode::Doctest;
compile_opts.build_config.intent = UserIntent::Doctest;
compile_opts.filter = ops::CompileFilter::lib_only();
} else if test_name.is_some() && !compile_opts.filter.is_specific() {
// If arg `TESTNAME` is provided, assumed that the user knows what

View File

@ -21,8 +21,8 @@ pub struct BuildConfig {
pub keep_going: bool,
/// Build profile
pub requested_profile: InternedString,
/// The mode we are compiling in.
pub mode: CompileMode,
/// The intent we are compiling in.
pub intent: UserIntent,
/// `true` to print stdout in JSON format (for machine reading).
pub message_format: MessageFormat,
/// Force Cargo to do a full rebuild and treat each target as changed.
@ -72,7 +72,7 @@ impl BuildConfig {
jobs: Option<JobsConfig>,
keep_going: bool,
requested_targets: &[String],
mode: CompileMode,
intent: UserIntent,
) -> CargoResult<BuildConfig> {
let cfg = gctx.build_config()?;
let requested_kinds = CompileKind::from_requested_targets(gctx, requested_targets)?;
@ -117,7 +117,7 @@ impl BuildConfig {
jobs,
keep_going,
requested_profile: InternedString::new("dev"),
mode,
intent,
message_format: MessageFormat::Human,
force_rebuild: false,
build_plan: false,
@ -138,10 +138,6 @@ impl BuildConfig {
matches!(self.message_format, MessageFormat::Json { .. })
}
pub fn test(&self) -> bool {
self.mode == CompileMode::Test || self.mode == CompileMode::Bench
}
pub fn single_requested_kind(&self) -> CargoResult<CompileKind> {
match self.requested_kinds.len() {
1 => Ok(self.requested_kinds[0]),
@ -167,37 +163,28 @@ pub enum MessageFormat {
Short,
}
/// The general "mode" for what to do.
///
/// This is used for two purposes. The commands themselves pass this in to
/// `compile_ws` to tell it the general execution strategy. This influences
/// the default targets selected. The other use is in the `Unit` struct
/// to indicate what is being done with a specific target.
/// The specific action to be performed on each `Unit` of work.
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
pub enum CompileMode {
/// A target being built for a test.
/// Test with `rustc`.
Test,
/// Building a target with `rustc` (lib or bin).
/// Compile with `rustc`.
Build,
/// Building a target with `rustc` to emit `rmeta` metadata only. If
/// `test` is true, then it is also compiled with `--test` to check it like
/// Type-check with `rustc` by emitting `rmeta` metadata only.
///
/// If `test` is true, then it is also compiled with `--test` to check it like
/// a test.
Check { test: bool },
/// Used to indicate benchmarks should be built. This is not used in
/// `Unit`, because it is essentially the same as `Test` (indicating
/// `--test` should be passed to rustc) and by using `Test` instead it
/// allows some de-duping of Units to occur.
Bench,
/// A target that will be documented with `rustdoc`.
/// Document with `rustdoc`.
///
/// If `deps` is true, then it will also document all dependencies.
/// if `json` is true, the documentation output is in json format.
Doc { deps: bool, json: bool },
/// A target that will be tested with `rustdoc`.
/// Test with `rustdoc`.
Doctest,
/// An example or library that will be scraped for function calls by `rustdoc`.
/// Scrape for function calls by `rustdoc`.
Docscrape,
/// A marker for Units that represent the execution of a `build.rs` script.
/// Execute the binary built from the `build.rs` script.
RunCustomBuild,
}
@ -211,7 +198,6 @@ impl ser::Serialize for CompileMode {
Test => "test".serialize(s),
Build => "build".serialize(s),
Check { .. } => "check".serialize(s),
Bench => "bench".serialize(s),
Doc { .. } => "doc".serialize(s),
Doctest => "doctest".serialize(s),
Docscrape => "docscrape".serialize(s),
@ -246,19 +232,13 @@ impl CompileMode {
pub fn is_any_test(self) -> bool {
matches!(
self,
CompileMode::Test
| CompileMode::Bench
| CompileMode::Check { test: true }
| CompileMode::Doctest
CompileMode::Test | CompileMode::Check { test: true } | CompileMode::Doctest
)
}
/// Returns `true` if this is something that passes `--test` to rustc.
pub fn is_rustc_test(self) -> bool {
matches!(
self,
CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true }
)
matches!(self, CompileMode::Test | CompileMode::Check { test: true })
}
/// Returns `true` if this is the *execution* of a `build.rs` script.
@ -271,9 +251,64 @@ impl CompileMode {
/// Note that this also returns `true` for building libraries, so you also
/// have to check the target.
pub fn generates_executable(self) -> bool {
matches!(self, CompileMode::Test | CompileMode::Build)
}
}
/// Represents the high-level operation requested by the user.
///
/// It determines which "Cargo targets" are selected by default and influences
/// how they will be processed. This is derived from the Cargo command the user
/// invoked (like `cargo build` or `cargo test`).
///
/// Unlike [`CompileMode`], which describes the specific compilation steps for
/// individual units, [`UserIntent`] represents the overall goal of the build
/// process as specified by the user.
///
/// For example, when a user runs `cargo test`, the intent is [`UserIntent::Test`],
/// but this might result in multiple [`CompileMode`]s for different units.
#[derive(Clone, Copy, Debug)]
pub enum UserIntent {
/// Build benchmark binaries, e.g., `cargo bench`
Bench,
/// Build binaries and libraray, e.g., `cargo run`, `cargo install`, `cargo build`.
Build,
/// Perform type-check, e.g., `cargo check`.
Check { test: bool },
/// Document packages.
///
/// If `deps` is true, then it will also document all dependencies.
/// if `json` is true, the documentation output is in json format.
Doc { deps: bool, json: bool },
/// Build doctest binaries, e.g., `cargo test --doc`
Doctest,
/// Build test binaries, e.g., `cargo test`
Test,
}
impl UserIntent {
/// Returns `true` if this is generating documentation.
pub fn is_doc(self) -> bool {
matches!(self, UserIntent::Doc { .. })
}
/// Returns `true` if this is any type of test (test, benchmark, doc test, or
/// check test).
pub fn is_any_test(self) -> bool {
matches!(
self,
CompileMode::Test | CompileMode::Bench | CompileMode::Build
UserIntent::Test
| UserIntent::Bench
| UserIntent::Check { test: true }
| UserIntent::Doctest
)
}
/// Returns `true` if this is something that passes `--test` to rustc.
pub fn is_rustc_test(self) -> bool {
matches!(
self,
UserIntent::Test | UserIntent::Bench | UserIntent::Check { test: true }
)
}
}

View File

@ -574,7 +574,7 @@ impl TargetInfo {
) -> CargoResult<(Vec<FileType>, Vec<CrateType>)> {
match mode {
CompileMode::Build => self.calc_rustc_outputs(target_kind, target_triple, gctx),
CompileMode::Test | CompileMode::Bench => {
CompileMode::Test => {
match self.file_types(&CrateType::Bin, FileFlavor::Normal, target_triple)? {
Some(fts) => Ok((fts, Vec::new())),
None => Ok((Vec::new(), vec![CrateType::Bin])),

View File

@ -493,10 +493,7 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
flavor: FileFlavor::Normal,
}]
}
CompileMode::Test
| CompileMode::Build
| CompileMode::Bench
| CompileMode::Check { .. } => {
CompileMode::Test | CompileMode::Build | CompileMode::Check { .. } => {
let mut outputs = self.calc_outputs_rustc(unit, bcx)?;
if bcx.build_config.sbom && bcx.gctx.cli_unstable().sbom {
let sbom_files: Vec<_> = outputs

View File

@ -183,7 +183,7 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> {
// any versioning (See https://github.com/rust-lang/cargo/issues/8461).
// Therefore, we can end up with weird bugs and behaviours if we mix different
// versions of these files.
if self.bcx.build_config.mode.is_doc() {
if self.bcx.build_config.intent.is_doc() {
RustDocFingerprint::check_rustdoc_fingerprint(&self)?
}

View File

@ -28,7 +28,7 @@
//! [build script]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html
//! [`TargetKind::CustomBuild`]: crate::core::manifest::TargetKind::CustomBuild
//! [`UnitGraph`]: super::unit_graph::UnitGraph
//! [`CompileMode::RunCustomBuild`]: super::CompileMode
//! [`CompileMode::RunCustomBuild`]: crate::core::compiler::CompileMode::RunCustomBuild
//! [instructions]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script
use super::{fingerprint, get_dynamic_search_path, BuildRunner, Job, Unit, Work};
@ -36,8 +36,8 @@ use crate::core::compiler::artifact;
use crate::core::compiler::build_runner::UnitHash;
use crate::core::compiler::fingerprint::DirtyReason;
use crate::core::compiler::job_queue::JobState;
use crate::core::compiler::CompileMode;
use crate::core::{profiles::ProfileRoot, PackageId, Target};
use crate::util::command_prelude::CompileMode;
use crate::util::errors::CargoResult;
use crate::util::internal;
use crate::util::machine_message::{self, Message};

View File

@ -97,7 +97,7 @@ fn calculate(
let crate_types = match unit.mode {
// Note: Doctest ignores LTO, but for now we'll compute it as-if it is
// a Bin, in case it is ever supported in the future.
CompileMode::Test | CompileMode::Bench | CompileMode::Doctest => vec![CrateType::Bin],
CompileMode::Test | CompileMode::Doctest => vec![CrateType::Bin],
// Notes on other modes:
// - Check: Treat as the underlying type, it doesn't really matter.
// - Doc: LTO is N/A for the Doc unit itself since rustdoc does not

View File

@ -69,6 +69,7 @@ use anyhow::{Context as _, Error};
use lazycell::LazyCell;
use tracing::{debug, instrument, trace};
pub use self::build_config::UserIntent;
pub use self::build_config::{BuildConfig, CompileMode, MessageFormat, TimingOutput};
pub use self::build_context::{
BuildContext, FileFlavor, FileType, RustDocFingerprint, RustcTargetData, TargetInfo,

View File

@ -168,7 +168,6 @@ impl<'gctx> Timings<'gctx> {
CompileMode::Build => {}
CompileMode::Check { test: true } => target.push_str(" (check-test)"),
CompileMode::Check { test: false } => target.push_str(" (check)"),
CompileMode::Bench => target.push_str(" (bench)"),
CompileMode::Doc { .. } => target.push_str(" (doc)"),
CompileMode::Doctest => target.push_str(" (doc test)"),
CompileMode::Docscrape => target.push_str(" (doc scrape)"),

View File

@ -21,6 +21,7 @@ use tracing::trace;
use crate::core::compiler::artifact::match_artifacts_kind_with_targets;
use crate::core::compiler::unit_graph::{UnitDep, UnitGraph};
use crate::core::compiler::UserIntent;
use crate::core::compiler::{
CompileKind, CompileMode, CrateType, RustcTargetData, Unit, UnitInterner,
};
@ -51,8 +52,9 @@ struct State<'a, 'gctx> {
std_features: Option<&'a ResolvedFeatures>,
/// `true` while generating the dependencies for the standard library.
is_std: bool,
/// The mode we are compiling in. Used for preventing from building lib thrice.
global_mode: CompileMode,
/// The high-level operation requested by the user.
/// Used for preventing from building lib thrice.
intent: UserIntent,
target_data: &'a RustcTargetData<'gctx>,
profiles: &'a Profiles,
interner: &'a UnitInterner,
@ -91,7 +93,7 @@ pub fn build_unit_dependencies<'a, 'gctx>(
roots: &[Unit],
scrape_units: &[Unit],
std_roots: &HashMap<CompileKind, Vec<Unit>>,
global_mode: CompileMode,
intent: UserIntent,
target_data: &'a RustcTargetData<'gctx>,
profiles: &'a Profiles,
interner: &'a UnitInterner,
@ -116,7 +118,7 @@ pub fn build_unit_dependencies<'a, 'gctx>(
std_resolve,
std_features,
is_std: false,
global_mode,
intent,
target_data,
profiles,
interner,
@ -203,13 +205,13 @@ fn attach_std_deps(
fn deps_of_roots(roots: &[Unit], state: &mut State<'_, '_>) -> CargoResult<()> {
for unit in roots.iter() {
// Dependencies of tests/benches should not have `panic` set.
// We check the global test mode to see if we are running in `cargo
// test` in which case we ensure all dependencies have `panic`
// cleared, and avoid building the lib thrice (once with `panic`, once
// without, once for `--test`). In particular, the lib included for
// Doc tests and examples are `Build` mode here.
// We check the user intent to see if we are running in `cargo test` in
// which case we ensure all dependencies have `panic` cleared, and
// avoid building the lib thrice (once with `panic`, once without, once
// for `--test`). In particular, the lib included for Doc tests and
// examples are `Build` mode here.
let root_compile_kind = unit.kind;
let unit_for = if unit.mode.is_any_test() || state.global_mode.is_rustc_test() {
let unit_for = if unit.mode.is_any_test() || state.intent.is_rustc_test() {
if unit.target.proc_macro() {
// Special-case for proc-macros, which are forced to for-host
// since they need to link with the proc_macro crate.

View File

@ -1,7 +1,6 @@
//! Filters and their rules to select which Cargo targets will be built.
use crate::core::compiler::CompileMode;
use crate::core::compiler::UserIntent;
use crate::core::{Target, TargetKind};
use crate::util::restricted_names::is_glob_pattern;
@ -216,23 +215,21 @@ impl CompileFilter {
}
/// Indicates if Cargo needs to build any dev dependency.
pub fn need_dev_deps(&self, mode: CompileMode) -> bool {
match mode {
CompileMode::Test | CompileMode::Doctest | CompileMode::Bench => true,
CompileMode::Check { test: true } => true,
CompileMode::Build
| CompileMode::Doc { .. }
| CompileMode::Docscrape
| CompileMode::Check { test: false } => match *self {
CompileFilter::Default { .. } => false,
CompileFilter::Only {
ref examples,
ref tests,
ref benches,
..
} => examples.is_specific() || tests.is_specific() || benches.is_specific(),
},
CompileMode::RunCustomBuild => panic!("Invalid mode"),
pub fn need_dev_deps(&self, intent: UserIntent) -> bool {
match intent {
UserIntent::Test | UserIntent::Doctest | UserIntent::Bench => true,
UserIntent::Check { test: true } => true,
UserIntent::Build | UserIntent::Doc { .. } | UserIntent::Check { test: false } => {
match *self {
CompileFilter::Default { .. } => false,
CompileFilter::Only {
ref examples,
ref tests,
ref benches,
..
} => examples.is_specific() || tests.is_specific() || benches.is_specific(),
}
}
}
}

View File

@ -41,9 +41,10 @@ use std::sync::Arc;
use crate::core::compiler::unit_dependencies::build_unit_dependencies;
use crate::core::compiler::unit_graph::{self, UnitDep, UnitGraph};
use crate::core::compiler::UserIntent;
use crate::core::compiler::{apply_env_config, standard_lib, CrateType, TargetInfo};
use crate::core::compiler::{BuildConfig, BuildContext, BuildRunner, Compilation};
use crate::core::compiler::{CompileKind, CompileMode, CompileTarget, RustcTargetData, Unit};
use crate::core::compiler::{CompileKind, CompileTarget, RustcTargetData, Unit};
use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner};
use crate::core::profiles::Profiles;
use crate::core::resolver::features::{self, CliFeatures, FeaturesFor};
@ -101,11 +102,11 @@ pub struct CompileOptions {
}
impl CompileOptions {
pub fn new(gctx: &GlobalContext, mode: CompileMode) -> CargoResult<CompileOptions> {
pub fn new(gctx: &GlobalContext, intent: UserIntent) -> CargoResult<CompileOptions> {
let jobs = None;
let keep_going = false;
Ok(CompileOptions {
build_config: BuildConfig::new(gctx, jobs, keep_going, &[], mode)?,
build_config: BuildConfig::new(gctx, jobs, keep_going, &[], intent)?,
cli_features: CliFeatures::new_all(false),
spec: ops::Packages::Packages(Vec::new()),
filter: CompileFilter::Default {
@ -226,19 +227,15 @@ pub fn create_bcx<'a, 'gctx>(
let gctx = ws.gctx();
// Perform some pre-flight validation.
match build_config.mode {
CompileMode::Test
| CompileMode::Build
| CompileMode::Check { .. }
| CompileMode::Bench
| CompileMode::RunCustomBuild => {
match build_config.intent {
UserIntent::Test | UserIntent::Build | UserIntent::Check { .. } | UserIntent::Bench => {
if ws.gctx().get_env("RUST_FLAGS").is_ok() {
gctx.shell().warn(
"Cargo does not read `RUST_FLAGS` environment variable. Did you mean `RUSTFLAGS`?",
)?;
}
}
CompileMode::Doc { .. } | CompileMode::Doctest | CompileMode::Docscrape => {
UserIntent::Doc { .. } | UserIntent::Doctest => {
if ws.gctx().get_env("RUSTDOC_FLAGS").is_ok() {
gctx.shell().warn(
"Cargo does not read `RUSTDOC_FLAGS` environment variable. Did you mean `RUSTDOCFLAGS`?"
@ -264,8 +261,8 @@ pub fn create_bcx<'a, 'gctx>(
.any(|target| target.is_example() && target.doc_scrape_examples().is_enabled())
});
if filter.need_dev_deps(build_config.mode)
|| (build_config.mode.is_doc() && any_pkg_has_scrape_enabled)
if filter.need_dev_deps(build_config.intent)
|| (build_config.intent.is_doc() && any_pkg_has_scrape_enabled)
{
HasDevUnits::Yes
} else {
@ -321,7 +318,7 @@ pub fn create_bcx<'a, 'gctx>(
for pkg in to_builds.iter() {
pkg.manifest().print_teapot(gctx);
if build_config.mode.is_any_test()
if build_config.intent.is_any_test()
&& !ws.is_member(pkg)
&& pkg.dependencies().iter().any(|dep| !dep.is_transitive())
{
@ -379,7 +376,7 @@ pub fn create_bcx<'a, 'gctx>(
filter,
requested_kinds: &build_config.requested_kinds,
explicit_host_kind,
mode: build_config.mode,
intent: build_config.intent,
resolve: &resolve,
workspace_resolve: &workspace_resolve,
resolved_features: &resolved_features,
@ -394,13 +391,9 @@ pub fn create_bcx<'a, 'gctx>(
override_rustc_crate_types(&mut units, args, interner)?;
}
let should_scrape = build_config.mode.is_doc() && gctx.cli_unstable().rustdoc_scrape_examples;
let should_scrape = build_config.intent.is_doc() && gctx.cli_unstable().rustdoc_scrape_examples;
let mut scrape_units = if should_scrape {
UnitGenerator {
mode: CompileMode::Docscrape,
..generator
}
.generate_scrape_units(&units)?
generator.generate_scrape_units(&units)?
} else {
Vec::new()
};
@ -431,7 +424,7 @@ pub fn create_bcx<'a, 'gctx>(
&units,
&scrape_units,
&std_roots,
build_config.mode,
build_config.intent,
&target_data,
&profiles,
interner,
@ -439,7 +432,7 @@ pub fn create_bcx<'a, 'gctx>(
// TODO: In theory, Cargo should also dedupe the roots, but I'm uncertain
// what heuristics to use in that case.
if matches!(build_config.mode, CompileMode::Doc { deps: true, .. }) {
if matches!(build_config.intent, UserIntent::Doc { deps: true, .. }) {
remove_duplicate_doc(build_config, &units, &mut unit_graph);
}

View File

@ -4,6 +4,7 @@ use std::fmt::Write;
use crate::core::compiler::rustdoc::RustdocScrapeExamples;
use crate::core::compiler::unit_dependencies::IsArtifact;
use crate::core::compiler::UserIntent;
use crate::core::compiler::{CompileKind, CompileMode, Unit};
use crate::core::compiler::{RustcTargetData, UnitInterner};
use crate::core::dependency::DepKind;
@ -53,7 +54,7 @@ pub(super) struct UnitGenerator<'a, 'gctx> {
pub filter: &'a CompileFilter,
pub requested_kinds: &'a [CompileKind],
pub explicit_host_kind: CompileKind,
pub mode: CompileMode,
pub intent: UserIntent,
pub resolve: &'a Resolve,
pub workspace_resolve: &'a Option<Resolve>,
pub resolved_features: &'a features::ResolvedFeatures,
@ -85,18 +86,9 @@ impl<'a> UnitGenerator<'a, '_> {
}
CompileMode::Build => match *target.kind() {
TargetKind::Test => CompileMode::Test,
TargetKind::Bench => CompileMode::Bench,
TargetKind::Bench => CompileMode::Test,
_ => CompileMode::Build,
},
// `CompileMode::Bench` is only used to inform `filter_default_targets`
// which command is being used (`cargo bench`). Afterwards, tests
// and benches are treated identically. Switching the mode allows
// de-duplication of units that are essentially identical. For
// example, `cargo build --all-targets --release` creates the units
// (lib profile:bench, mode:test) and (lib profile:bench, mode:bench)
// and since these are the same, we want them to be de-duplicated in
// `unit_dependencies`.
CompileMode::Bench => CompileMode::Test,
_ => initial_target_mode,
};
@ -188,17 +180,17 @@ impl<'a> UnitGenerator<'a, '_> {
/// Given a list of all targets for a package, filters out only the targets
/// that are automatically included when the user doesn't specify any targets.
fn filter_default_targets<'b>(&self, targets: &'b [Target]) -> Vec<&'b Target> {
match self.mode {
CompileMode::Bench => targets.iter().filter(|t| t.benched()).collect(),
CompileMode::Test => targets
match self.intent {
UserIntent::Bench => targets.iter().filter(|t| t.benched()).collect(),
UserIntent::Test => targets
.iter()
.filter(|t| t.tested() || t.is_example())
.collect(),
CompileMode::Build | CompileMode::Check { .. } => targets
UserIntent::Build | UserIntent::Check { .. } => targets
.iter()
.filter(|t| t.is_bin() || t.is_lib())
.collect(),
CompileMode::Doc { .. } => {
UserIntent::Doc { .. } => {
// `doc` does lib and bins (bin with same name as lib is skipped).
targets
.iter()
@ -211,8 +203,8 @@ impl<'a> UnitGenerator<'a, '_> {
})
.collect()
}
CompileMode::Doctest | CompileMode::RunCustomBuild | CompileMode::Docscrape => {
panic!("Invalid mode {:?}", self.mode)
UserIntent::Doctest => {
panic!("Invalid intent {:?}", self.intent)
}
}
}
@ -395,9 +387,9 @@ impl<'a> UnitGenerator<'a, '_> {
pkg,
target,
requires_features: !required_features_filterable,
mode: self.mode,
mode: to_compile_mode(self.intent),
}));
if self.mode == CompileMode::Test {
if matches!(self.intent, UserIntent::Test) {
if let Some(t) = pkg
.targets()
.iter()
@ -423,9 +415,10 @@ impl<'a> UnitGenerator<'a, '_> {
} => {
if *lib != LibRule::False {
let mut libs = Vec::new();
for proposal in self.filter_targets(Target::is_lib, false, self.mode) {
let compile_mode = to_compile_mode(self.intent);
for proposal in self.filter_targets(Target::is_lib, false, compile_mode) {
let Proposal { target, pkg, .. } = proposal;
if self.mode.is_doc_test() && !target.doctestable() {
if matches!(self.intent, UserIntent::Doctest) && !target.doctestable() {
let types = target.rustc_crate_types();
let types_str: Vec<&str> = types.iter().map(|t| t.as_str()).collect();
self.ws.gctx().shell().warn(format!(
@ -455,16 +448,18 @@ impl<'a> UnitGenerator<'a, '_> {
proposals.extend(libs);
}
let default_mode = to_compile_mode(self.intent);
// If `--tests` was specified, add all targets that would be
// generated by `cargo test`.
let test_filter = match tests {
FilterRule::All => Target::tested,
FilterRule::Just(_) => Target::is_test,
};
let test_mode = match self.mode {
CompileMode::Build => CompileMode::Test,
CompileMode::Check { .. } => CompileMode::Check { test: true },
_ => self.mode,
let test_mode = match self.intent {
UserIntent::Build => CompileMode::Test,
UserIntent::Check { .. } => CompileMode::Check { test: true },
_ => default_mode,
};
// If `--benches` was specified, add all targets that would be
// generated by `cargo bench`.
@ -472,25 +467,25 @@ impl<'a> UnitGenerator<'a, '_> {
FilterRule::All => Target::benched,
FilterRule::Just(_) => Target::is_bench,
};
let bench_mode = match self.mode {
CompileMode::Build => CompileMode::Bench,
CompileMode::Check { .. } => CompileMode::Check { test: true },
_ => self.mode,
};
proposals.extend(self.list_rule_targets(bins, "bin", Target::is_bin, self.mode)?);
proposals.extend(self.list_rule_targets(
bins,
"bin",
Target::is_bin,
default_mode,
)?);
proposals.extend(self.list_rule_targets(
examples,
"example",
Target::is_example,
self.mode,
default_mode,
)?);
proposals.extend(self.list_rule_targets(tests, "test", test_filter, test_mode)?);
proposals.extend(self.list_rule_targets(
benches,
"bench",
bench_filter,
bench_mode,
test_mode,
)?);
}
}
@ -779,3 +774,14 @@ Rustdoc did not scrape the following examples because they require dev-dependenc
Ok(scrape_units)
}
}
/// Converts [`UserIntent`] to [`CompileMode`] for root units.
fn to_compile_mode(intent: UserIntent) -> CompileMode {
match intent {
UserIntent::Test | UserIntent::Bench => CompileMode::Test,
UserIntent::Build => CompileMode::Build,
UserIntent::Check { test } => CompileMode::Check { test },
UserIntent::Doc { deps, json } => CompileMode::Doc { deps, json },
UserIntent::Doctest => CompileMode::Doctest,
}
}

View File

@ -1,5 +1,7 @@
use crate::core::compiler::standard_lib;
use crate::core::compiler::{BuildConfig, CompileMode, RustcTargetData};
use crate::core::compiler::BuildConfig;
use crate::core::compiler::RustcTargetData;
use crate::core::compiler::UserIntent;
use crate::core::{PackageSet, Resolve, Workspace};
use crate::ops;
use crate::util::context::JobsConfig;
@ -26,7 +28,7 @@ pub fn fetch<'a>(
let keep_going = false;
let gctx = ws.gctx();
let build_config =
BuildConfig::new(gctx, jobs, keep_going, &options.targets, CompileMode::Build)?;
BuildConfig::new(gctx, jobs, keep_going, &options.targets, UserIntent::Build)?;
let mut data = RustcTargetData::new(ws, &build_config.requested_kinds)?;
let mut fetched_packages = HashSet::new();
let mut deps_to_fetch = ws.members().map(|p| p.package_id()).collect::<Vec<_>>();

View File

@ -15,9 +15,9 @@ use flate2::read::GzDecoder;
use tar::Archive;
use crate::core::compiler::BuildConfig;
use crate::core::compiler::CompileMode;
use crate::core::compiler::DefaultExecutor;
use crate::core::compiler::Executor;
use crate::core::compiler::UserIntent;
use crate::core::Feature;
use crate::core::Package;
use crate::core::SourceId;
@ -103,7 +103,7 @@ pub fn run_verify(
opts.jobs.clone(),
opts.keep_going,
&opts.targets,
CompileMode::Build,
UserIntent::Build,
)?,
cli_features: opts.cli_features.clone(),
spec: ops::Packages::Packages(Vec::new()),

View File

@ -29,7 +29,7 @@ use std::ffi::{OsStr, OsString};
use std::path::Path;
use std::path::PathBuf;
pub use crate::core::compiler::CompileMode;
pub use crate::core::compiler::UserIntent;
pub use crate::{CliError, CliResult, GlobalContext};
pub use clap::{value_parser, Arg, ArgAction, ArgMatches};
@ -723,7 +723,7 @@ Run `{cmd}` to see possible targets."
fn compile_options(
&self,
gctx: &GlobalContext,
mode: CompileMode,
mode: UserIntent,
workspace: Option<&Workspace<'_>>,
profile_checking: ProfileChecking,
) -> CargoResult<CompileOptions> {
@ -887,7 +887,7 @@ Run `{cmd}` to see possible targets."
fn compile_options_for_single_package(
&self,
gctx: &GlobalContext,
mode: CompileMode,
mode: UserIntent,
workspace: Option<&Workspace<'_>>,
profile_checking: ProfileChecking,
) -> CargoResult<CompileOptions> {

View File

@ -5,12 +5,11 @@ use std::fs;
use std::io::Read;
use std::process::Stdio;
use cargo::{
core::compiler::CompileMode,
core::{Shell, Workspace},
ops::CompileOptions,
GlobalContext,
};
use cargo::core::compiler::UserIntent;
use cargo::core::Shell;
use cargo::core::Workspace;
use cargo::ops::CompileOptions;
use cargo::GlobalContext;
use cargo_test_support::compare::assert_e2e;
use cargo_test_support::paths::root;
use cargo_test_support::prelude::*;
@ -665,7 +664,7 @@ fn cargo_compile_api_exposes_artifact_paths() {
let shell = Shell::from_write(Box::new(Vec::new()));
let gctx = GlobalContext::new(shell, env::current_dir().unwrap(), paths::home());
let ws = Workspace::new(&p.root().join("Cargo.toml"), &gctx).unwrap();
let compile_options = CompileOptions::new(ws.gctx(), CompileMode::Build).unwrap();
let compile_options = CompileOptions::new(ws.gctx(), UserIntent::Build).unwrap();
let result = cargo::ops::compile(&ws, &compile_options).unwrap();

View File

@ -1,7 +1,9 @@
//! Tests for workspace member errors.
use cargo::core::compiler::UserIntent;
use cargo::core::resolver::ResolveError;
use cargo::core::{compiler::CompileMode, Shell, Workspace};
use cargo::core::Shell;
use cargo::core::Workspace;
use cargo::ops::{self, CompileOptions};
use cargo::util::{context::GlobalContext, errors::ManifestError};
use cargo_test_support::paths;
@ -155,7 +157,7 @@ fn member_manifest_version_error() {
paths::cargo_home(),
);
let ws = Workspace::new(&p.root().join("Cargo.toml"), &gctx).unwrap();
let compile_options = CompileOptions::new(&gctx, CompileMode::Build).unwrap();
let compile_options = CompileOptions::new(&gctx, UserIntent::Build).unwrap();
let member_bar = ws.members().find(|m| &*m.name() == "bar").unwrap();
let error = ops::compile(&ws, &compile_options).map(|_| ()).unwrap_err();