]> git.proxmox.com Git - cargo.git/blame - src/cargo/ops/cargo_compile.rs
Remove `--rustc-cfg` argument
[cargo.git] / src / cargo / ops / cargo_compile.rs
CommitLineData
2599c34d 1//! The Cargo "compile" operation.
64ff29ff 2//!
2599c34d
EH
3//! This module contains the entry point for starting the compilation process
4//! for commands like `build`, `test`, `doc`, `rustc`, etc.
64ff29ff 5//!
2599c34d
EH
6//! The `compile` function will do all the work to compile a workspace. A
7//! rough outline is:
64ff29ff 8//!
2599c34d 9//! - Resolve the dependency graph (see `ops::resolve`).
e0bd9e23 10//! - Download any packages needed (see `PackageSet`).
2599c34d
EH
11//! - Generate a list of top-level "units" of work for the targets the user
12//! requested on the command-line. Each `Unit` corresponds to a compiler
13//! invocation. This is done in this module (`generate_targets`).
e0bd9e23
EH
14//! - Build the graph of `Unit` dependencies (see
15//! `core::compiler::context::unit_dependencies`).
2599c34d 16//! - Create a `Context` which will perform the following steps:
2599c34d
EH
17//! - Prepare the `target` directory (see `Layout`).
18//! - Create a job queue (see `JobQueue`). The queue checks the
19//! fingerprint of each `Unit` to determine if it should run or be
20//! skipped.
21//! - Execute the queue. Each leaf in the queue's dependency graph is
22//! executed, and then removed from the graph when finished. This
23//! repeats until the queue is empty.
62bff631 24
45ce445c 25use std::collections::{BTreeSet, HashMap, HashSet};
9efa0d55 26use std::hash::{Hash, Hasher};
1ab19a5a 27use std::sync::Arc;
12af54e1 28
9be620a7 29use crate::core::compiler::rustc_cfg;
9efa0d55 30use crate::core::compiler::standard_lib;
1f14fa31 31use crate::core::compiler::unit_dependencies::build_unit_dependencies;
9efa0d55 32use crate::core::compiler::unit_graph::{self, UnitDep, UnitGraph};
e4544466 33use crate::core::compiler::{BuildConfig, BuildContext, Compilation, Context};
9efa0d55 34use crate::core::compiler::{CompileKind, CompileMode, CompileTarget, RustcTargetData, Unit};
e4544466 35use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner};
04ddd4d0 36use crate::core::profiles::{Profiles, UnitFor};
027977c8 37use crate::core::resolver::features::{self, FeaturesFor, RequestedFeatures};
e0d64f94 38use crate::core::resolver::{HasDevUnits, Resolve, ResolveOpts};
19a95790 39use crate::core::{FeatureValue, Package, PackageSet, Shell, Summary, Target};
04ddd4d0
DW
40use crate::core::{PackageId, PackageIdSpec, TargetKind, Workspace};
41use crate::ops;
12392f6d 42use crate::ops::resolve::WorkspaceResolve;
04ddd4d0 43use crate::util::config::Config;
42696ae2 44use crate::util::restricted_names::is_glob_pattern;
9efa0d55 45use crate::util::{closest_msg, profile, CargoResult, StableHasher};
50f110a4 46
42696ae2
WL
47use anyhow::Context as _;
48
bacb6be3 49/// Contains information about how a package should be compiled.
e0bd9e23
EH
50///
51/// Note on distinction between `CompileOptions` and `BuildConfig`:
52/// `BuildConfig` contains values that need to be retained after
53/// `BuildContext` is created. The other fields are no longer necessary. Think
54/// of it as `CompileOptions` are high-level settings requested on the
55/// command-line, and `BuildConfig` are low-level settings for actually
56/// driving `rustc`.
876af7c1 57#[derive(Debug)]
e4918c45 58pub struct CompileOptions {
08025169
DO
59 /// Configuration information for a rustc build
60 pub build_config: BuildConfig,
9e779198 61 /// Extra features to build for the root package
bb643cca 62 pub features: Vec<String>,
1f8b3988
DA
63 /// Flag whether all available features should be built for the root package
64 pub all_features: bool,
9e779198 65 /// Flag if the default feature should be built for the root package
2b46d039 66 pub no_default_features: bool,
6b32c4d7 67 /// A set of packages to build.
bb643cca 68 pub spec: Packages,
9e779198
AC
69 /// Filter to apply to the root package to select which targets will be
70 /// built.
bb643cca 71 pub filter: CompileFilter,
1ef954ea 72 /// Extra arguments to be passed to rustdoc (single target only)
bb643cca 73 pub target_rustdoc_args: Option<Vec<String>>,
77bb01ec
SL
74 /// The specified target will be compiled with all the available arguments,
75 /// note that this only accounts for the *final* invocation of rustc
bb643cca 76 pub target_rustc_args: Option<Vec<String>>,
1ef954ea
EH
77 /// Extra arguments passed to all selected targets for rustdoc.
78 pub local_rustdoc_args: Option<Vec<String>>,
e7ee237c
LK
79 /// Whether the `--document-private-items` flags was specified and should
80 /// be forwarded to `rustdoc`.
81 pub rustdoc_document_private_items: bool,
9e779198
AC
82}
83
e4918c45
EH
84impl<'a> CompileOptions {
85 pub fn new(config: &Config, mode: CompileMode) -> CargoResult<CompileOptions> {
08025169 86 Ok(CompileOptions {
3fd28143 87 build_config: BuildConfig::new(config, None, &[], mode)?,
bb643cca 88 features: Vec::new(),
69caa63b
NC
89 all_features: false,
90 no_default_features: false,
bb643cca 91 spec: ops::Packages::Packages(Vec::new()),
1e682848
AC
92 filter: CompileFilter::Default {
93 required_features_filterable: false,
94 },
69caa63b
NC
95 target_rustdoc_args: None,
96 target_rustc_args: None,
1ef954ea 97 local_rustdoc_args: None,
e7ee237c 98 rustdoc_document_private_items: false,
08025169 99 })
69caa63b
NC
100 }
101}
102
bb643cca
AK
103#[derive(Clone, PartialEq, Eq, Debug)]
104pub enum Packages {
ba7911dd 105 Default,
62c04979 106 All,
bb643cca
AK
107 OptOut(Vec<String>),
108 Packages(Vec<String>),
62c04979
AR
109}
110
bb643cca 111impl Packages {
1e682848 112 pub fn from_flags(all: bool, exclude: Vec<String>, package: Vec<String>) -> CargoResult<Self> {
ba7911dd
SS
113 Ok(match (all, exclude.len(), package.len()) {
114 (false, 0, 0) => Packages::Default,
115 (false, 0, _) => Packages::Packages(package),
3a18c89a 116 (false, _, _) => anyhow::bail!("--exclude can only be used together with --workspace"),
ba7911dd
SS
117 (true, 0, _) => Packages::All,
118 (true, _, _) => Packages::OptOut(exclude),
119 })
7ffd1cfc 120 }
121
2361fb0f 122 /// Converts selected packages from a workspace to `PackageIdSpec`s.
b8b7faee 123 pub fn to_package_id_specs(&self, ws: &Workspace<'_>) -> CargoResult<Vec<PackageIdSpec>> {
d347908d 124 let specs = match self {
dae87a26
E
125 Packages::All => ws
126 .members()
1e682848
AC
127 .map(Package::package_id)
128 .map(PackageIdSpec::from_package_id)
129 .collect(),
45ce445c 130 Packages::OptOut(opt_out) => {
2361fb0f
WL
131 let (mut patterns, mut names) = opt_patterns_and_names(opt_out)?;
132 let specs = ws
45ce445c 133 .members()
2361fb0f
WL
134 .filter(|pkg| {
135 !names.remove(pkg.name().as_str()) && !match_patterns(pkg, &mut patterns)
136 })
45ce445c
DW
137 .map(Package::package_id)
138 .map(PackageIdSpec::from_package_id)
139 .collect();
2361fb0f
WL
140 let warn = |e| ws.config().shell().warn(e);
141 emit_package_not_found(ws, names, true).or_else(warn)?;
142 emit_pattern_not_found(ws, patterns, true).or_else(warn)?;
143 specs
f16efff1 144 }
d347908d 145 Packages::Packages(packages) if packages.is_empty() => {
037a879d
EH
146 vec![PackageIdSpec::from_package_id(ws.current()?.package_id())]
147 }
2361fb0f
WL
148 Packages::Packages(opt_in) => {
149 let (mut patterns, packages) = opt_patterns_and_names(opt_in)?;
150 let mut specs = packages
151 .iter()
152 .map(|p| PackageIdSpec::parse(p))
153 .collect::<CargoResult<Vec<_>>>()?;
154 if !patterns.is_empty() {
155 let matched_pkgs = ws
156 .members()
157 .filter(|pkg| match_patterns(pkg, &mut patterns))
158 .map(Package::package_id)
159 .map(PackageIdSpec::from_package_id);
160 specs.extend(matched_pkgs);
161 }
e4a1794b 162 emit_pattern_not_found(ws, patterns, false)?;
2361fb0f
WL
163 specs
164 }
dae87a26
E
165 Packages::Default => ws
166 .default_members()
1e682848
AC
167 .map(Package::package_id)
168 .map(PackageIdSpec::from_package_id)
169 .collect(),
6b32c4d7 170 };
68a681ff 171 if specs.is_empty() {
691f95de 172 if ws.is_virtual() {
3a18c89a 173 anyhow::bail!(
1e682848
AC
174 "manifest path `{}` contains no package: The manifest is virtual, \
175 and the workspace has no members.",
176 ws.root().display()
177 )
05b896ac 178 }
3a18c89a 179 anyhow::bail!("no packages to compile")
68a681ff 180 }
6b32c4d7
AK
181 Ok(specs)
182 }
fa54a794 183
2361fb0f 184 /// Gets a list of selected packages from a workspace.
b8b7faee 185 pub fn get_packages<'ws>(&self, ws: &'ws Workspace<'_>) -> CargoResult<Vec<&'ws Package>> {
fa54a794
EH
186 let packages: Vec<_> = match self {
187 Packages::Default => ws.default_members().collect(),
188 Packages::All => ws.members().collect(),
2361fb0f
WL
189 Packages::OptOut(opt_out) => {
190 let (mut patterns, mut names) = opt_patterns_and_names(opt_out)?;
191 let packages = ws
192 .members()
193 .filter(|pkg| {
194 !names.remove(pkg.name().as_str()) && !match_patterns(pkg, &mut patterns)
195 })
196 .collect();
197 emit_package_not_found(ws, names, true)?;
198 emit_pattern_not_found(ws, patterns, true)?;
199 packages
200 }
201 Packages::Packages(opt_in) => {
202 let (mut patterns, mut names) = opt_patterns_and_names(opt_in)?;
203 let packages = ws
204 .members()
205 .filter(|pkg| {
206 names.remove(pkg.name().as_str()) || match_patterns(pkg, &mut patterns)
207 })
208 .collect();
209 emit_package_not_found(ws, names, false)?;
210 emit_pattern_not_found(ws, patterns, false)?;
211 packages
212 }
fa54a794
EH
213 };
214 Ok(packages)
215 }
44c535ab
EH
216
217 /// Returns whether or not the user needs to pass a `-p` flag to target a
218 /// specific package in the workspace.
219 pub fn needs_spec_flag(&self, ws: &Workspace<'_>) -> bool {
220 match self {
221 Packages::Default => ws.default_members().count() > 1,
222 Packages::All => ws.members().count() > 1,
223 Packages::Packages(_) => true,
224 Packages::OptOut(_) => true,
225 }
226 }
6b32c4d7
AK
227}
228
aef99e0e
DW
229#[derive(Debug, PartialEq, Eq)]
230pub enum LibRule {
231 /// Include the library, fail if not present
232 True,
233 /// Include the library if present
234 Default,
235 /// Exclude the library
236 False,
237}
238
bb643cca
AK
239#[derive(Debug)]
240pub enum FilterRule {
2a82378a 241 All,
bb643cca 242 Just(Vec<String>),
2a82378a
BW
243}
244
876af7c1 245#[derive(Debug)]
bb643cca 246pub enum CompileFilter {
6344db05 247 Default {
25e50b58
JB
248 /// Flag whether targets can be safely skipped when required-features are not satisfied.
249 required_features_filterable: bool,
250 },
9e779198 251 Only {
b9497ab2 252 all_targets: bool,
aef99e0e 253 lib: LibRule,
bb643cca
AK
254 bins: FilterRule,
255 examples: FilterRule,
256 tests: FilterRule,
257 benches: FilterRule,
1e682848 258 },
a1980dc7
YKCL
259}
260
e4918c45 261pub fn compile<'a>(ws: &Workspace<'a>, options: &CompileOptions) -> CargoResult<Compilation<'a>> {
b8b7faee 262 let exec: Arc<dyn Executor> = Arc::new(DefaultExecutor);
689f412c 263 compile_with_exec(ws, options, &exec)
8c3b3605
NC
264}
265
4a64d05e 266/// Like `compile` but allows specifying a custom `Executor` that will be able to intercept build
d70f91ee 267/// calls and add custom logic. `compile` uses `DefaultExecutor` which just passes calls through.
1e682848
AC
268pub fn compile_with_exec<'a>(
269 ws: &Workspace<'a>,
e4918c45 270 options: &CompileOptions,
b8b7faee 271 exec: &Arc<dyn Executor>,
a340ba0b 272) -> CargoResult<Compilation<'a>> {
688a4fa6 273 ws.emit_warnings()?;
8a301589 274 compile_ws(ws, options, exec)
9fba127e
AC
275}
276
1e682848
AC
277pub fn compile_ws<'a>(
278 ws: &Workspace<'a>,
e4918c45 279 options: &CompileOptions,
b8b7faee 280 exec: &Arc<dyn Executor>,
a340ba0b 281) -> CargoResult<Compilation<'a>> {
e0bd9e23
EH
282 let interner = UnitInterner::new();
283 let bcx = create_bcx(ws, options, &interner)?;
284 if options.build_config.unit_graph {
285 unit_graph::emit_serialized_unit_graph(&bcx.roots, &bcx.unit_graph)?;
286 return Ok(Compilation::new(&bcx)?);
287 }
d49a32fd 288 if options.build_config.rustc_cfg {
6789a4cc 289 rustc_cfg::emit_serialized_rustc_cfg(&bcx.target_data, &bcx.build_config.requested_kinds)?;
0018ef06
CF
290 return Ok(Compilation::new(&bcx)?);
291 }
e0bd9e23
EH
292 let _p = profile::start("compiling");
293 let cx = Context::new(&bcx)?;
294 cx.compile(exec)
295}
296
297pub fn create_bcx<'a, 'cfg>(
298 ws: &'a Workspace<'cfg>,
299 options: &'a CompileOptions,
300 interner: &'a UnitInterner,
301) -> CargoResult<BuildContext<'a, 'cfg>> {
1e682848 302 let CompileOptions {
08025169 303 ref build_config,
1e682848
AC
304 ref spec,
305 ref features,
306 all_features,
307 no_default_features,
1e682848
AC
308 ref filter,
309 ref target_rustdoc_args,
310 ref target_rustc_args,
1ef954ea 311 ref local_rustdoc_args,
e7ee237c 312 rustdoc_document_private_items,
1e682848 313 } = *options;
e4918c45 314 let config = ws.config();
3656bec8 315
d649c661 316 // Perform some pre-flight validation.
d17ccec2
HY
317 match build_config.mode {
318 CompileMode::Test
319 | CompileMode::Build
320 | CompileMode::Check { .. }
321 | CompileMode::Bench
322 | CompileMode::RunCustomBuild => {
323 if std::env::var("RUST_FLAGS").is_ok() {
324 config.shell().warn(
325 "Cargo does not read `RUST_FLAGS` environment variable. Did you mean `RUSTFLAGS`?",
326 )?;
327 }
328 }
329 CompileMode::Doc { .. } | CompileMode::Doctest => {
330 if std::env::var("RUSTDOC_FLAGS").is_ok() {
331 config.shell().warn(
332 "Cargo does not read `RUSTDOC_FLAGS` environment variable. Did you mean `RUSTDOCFLAGS`?"
333 )?;
334 }
335 }
336 }
d649c661 337 config.validate_term_config()?;
d17ccec2 338
3fd28143 339 let target_data = RustcTargetData::new(ws, &build_config.requested_kinds)?;
47007d97 340
8947ed1f 341 let specs = spec.to_package_id_specs(ws)?;
e26ef017 342 let dev_deps = ws.require_optional_deps() || filter.need_dev_deps(build_config.mode);
027977c8
JG
343 let opts = ResolveOpts::new(
344 dev_deps,
345 RequestedFeatures::from_command_line(features, all_features, !no_default_features),
346 );
2b1dc3e5
AT
347 let has_dev_units = if filter.need_dev_deps(build_config.mode) {
348 HasDevUnits::Yes
349 } else {
350 HasDevUnits::No
e0d64f94 351 };
d728f386
EH
352 let resolve = ops::resolve_ws_with_opts(
353 ws,
354 &target_data,
3fd28143 355 &build_config.requested_kinds,
d728f386
EH
356 &opts,
357 &specs,
358 has_dev_units,
d267fac2 359 crate::core::resolver::features::ForceAllTargets::No,
d728f386 360 )?;
12392f6d
EH
361 let WorkspaceResolve {
362 mut pkg_set,
363 workspace_resolve,
364 targeted_resolve: resolve,
7caa1612 365 resolved_features,
12392f6d 366 } = resolve;
1f14fa31 367
7caa1612 368 let std_resolve_features = if let Some(crates) = &config.cli_unstable().build_std {
3afb5d7d
EH
369 if build_config.build_plan {
370 config
371 .shell()
372 .warn("-Zbuild-std does not currently fully support --build-plan")?;
373 }
3fd28143 374 if build_config.requested_kinds[0].is_host() {
1f14fa31
EH
375 // TODO: This should eventually be fixed. Unfortunately it is not
376 // easy to get the host triple in BuildConfig. Consider changing
377 // requested_target to an enum, or some other approach.
3a18c89a 378 anyhow::bail!("-Zbuild-std requires --target");
1f14fa31 379 }
98b6f816 380 let (std_package_set, std_resolve, std_features) =
3fd28143 381 standard_lib::resolve_std(ws, &target_data, &build_config.requested_kinds, crates)?;
12392f6d 382 pkg_set.add_set(std_package_set);
7caa1612 383 Some((std_resolve, std_features))
1f14fa31
EH
384 } else {
385 None
386 };
9c296792 387
1f14fa31
EH
388 // Find the packages in the resolver that the user wants to build (those
389 // passed in with `-p` or the defaults from the workspace), and convert
96a39371
EH
390 // Vec<PackageIdSpec> to a Vec<PackageId>.
391 let to_build_ids = resolve.specs_to_ids(&specs)?;
1f14fa31
EH
392 // Now get the `Package` for each `PackageId`. This may trigger a download
393 // if the user specified `-p` for a dependency that is not downloaded.
394 // Dependencies will be downloaded during build_unit_dependencies.
12392f6d 395 let mut to_builds = pkg_set.get_many(to_build_ids)?;
0ea0c8ba 396
7b1a0dc5
AC
397 // The ordering here affects some error messages coming out of cargo, so
398 // let's be test and CLI friendly by always printing in the same order if
399 // there's an error.
400 to_builds.sort_by_key(|p| p.package_id());
401
402 for pkg in to_builds.iter() {
1f14fa31 403 pkg.manifest().print_teapot(config);
786848a0
EH
404
405 if build_config.mode.is_any_test()
406 && !ws.is_member(pkg)
407 && pkg.dependencies().iter().any(|dep| !dep.is_transitive())
408 {
3a18c89a 409 anyhow::bail!(
786848a0
EH
410 "package `{}` cannot be tested because it requires dev-dependencies \
411 and is not a member of the workspace",
412 pkg.name()
413 );
414 }
7b1a0dc5 415 }
f0647ea2 416
575d6e81
EH
417 let (extra_args, extra_args_name) = match (target_rustc_args, target_rustdoc_args) {
418 (&Some(ref args), _) => (Some(args.clone()), "rustc"),
419 (_, &Some(ref args)) => (Some(args.clone()), "rustdoc"),
420 _ => (None, ""),
f0647ea2 421 };
b3ade7c7 422
575d6e81
EH
423 if extra_args.is_some() && to_builds.len() != 1 {
424 panic!(
425 "`{}` should not accept multiple `-p` flags",
426 extra_args_name
427 );
428 }
429
e0bd9e23
EH
430 let profiles = Profiles::new(
431 ws.profiles(),
432 config,
433 build_config.requested_profile,
36c69a18 434 ws.unstable_features(),
e0bd9e23 435 )?;
12392f6d 436 profiles.validate_packages(
77ee608d 437 ws.profiles(),
12392f6d
EH
438 &mut config.shell(),
439 workspace_resolve.as_ref().unwrap_or(&resolve),
440 )?;
a0a880c3 441
9efa0d55
EH
442 // If `--target` has not been specified, then the unit graph is built
443 // assuming `--target $HOST` was specified. See
444 // `rebuild_unit_graph_shared` for more on why this is done.
445 let explicit_host_kind = CompileKind::Target(CompileTarget::new(&target_data.rustc.host)?);
446 let explicit_host_kinds: Vec<_> = build_config
447 .requested_kinds
448 .iter()
449 .map(|kind| match kind {
450 CompileKind::Host => explicit_host_kind,
451 CompileKind::Target(t) => CompileKind::Target(*t),
452 })
453 .collect();
454
455 let mut units = generate_targets(
73660740 456 ws,
575d6e81
EH
457 &to_builds,
458 filter,
9efa0d55 459 &explicit_host_kinds,
e0bd9e23 460 build_config.mode,
12392f6d 461 &resolve,
19a95790 462 &workspace_resolve,
7caa1612 463 &resolved_features,
e0bd9e23
EH
464 &pkg_set,
465 &profiles,
686ccfa4 466 interner,
575d6e81
EH
467 )?;
468
1f14fa31 469 let std_roots = if let Some(crates) = &config.cli_unstable().build_std {
3ba9de85
EH
470 // Only build libtest if it looks like it is needed.
471 let mut crates = crates.clone();
472 if !crates.iter().any(|c| c == "test")
473 && units
474 .iter()
475 .any(|unit| unit.mode.is_rustc_test() && unit.target.harness())
476 {
18a89732
PO
477 // Only build libtest when libstd is built (libtest depends on libstd)
478 if crates.iter().any(|c| c == "std") {
479 crates.push("test".to_string());
480 }
3ba9de85 481 }
7caa1612 482 let (std_resolve, std_features) = std_resolve_features.as_ref().unwrap();
593a02f2 483 standard_lib::generate_std_roots(
593a02f2 484 &crates,
7caa1612
EH
485 std_resolve,
486 std_features,
9efa0d55 487 &explicit_host_kinds,
e0bd9e23 488 &pkg_set,
686ccfa4 489 interner,
e0bd9e23 490 &profiles,
593a02f2 491 )?
1f14fa31 492 } else {
3fd28143 493 Default::default()
1f14fa31
EH
494 };
495
9efa0d55
EH
496 let mut unit_graph = build_unit_dependencies(
497 ws,
498 &pkg_set,
499 &resolve,
500 &resolved_features,
501 std_resolve_features.as_ref(),
502 &units,
503 &std_roots,
504 build_config.mode,
505 &target_data,
506 &profiles,
507 interner,
508 )?;
509
510 if build_config
511 .requested_kinds
512 .iter()
513 .any(CompileKind::is_host)
514 {
515 // Rebuild the unit graph, replacing the explicit host targets with
516 // CompileKind::Host, merging any dependencies shared with build
517 // dependencies.
518 let new_graph = rebuild_unit_graph_shared(interner, unit_graph, &units, explicit_host_kind);
519 // This would be nicer with destructuring assignment.
520 units = new_graph.0;
521 unit_graph = new_graph.1;
522 }
523
e0bd9e23 524 let mut extra_compiler_args = HashMap::new();
575d6e81
EH
525 if let Some(args) = extra_args {
526 if units.len() != 1 {
3a18c89a 527 anyhow::bail!(
575d6e81 528 "extra arguments to `{}` can only be passed to one \
f7c91ba6
AR
529 target, consider filtering\nthe package by passing, \
530 e.g., `--lib` or `--bin NAME` to specify a single target",
575d6e81
EH
531 extra_args_name
532 );
8a8ea1e8 533 }
45d49579 534 extra_compiler_args.insert(units[0].clone(), args);
1ef954ea 535 }
e7ee237c
LK
536 for unit in &units {
537 if unit.mode.is_doc() || unit.mode.is_doc_test() {
538 let mut extra_args = local_rustdoc_args.clone();
539
540 // Add `--document-private-items` rustdoc flag if requested or if
541 // the target is a binary. Binary crates get their private items
542 // documented by default.
543 if rustdoc_document_private_items || unit.target.is_bin() {
a6a395c6 544 let mut args = extra_args.take().unwrap_or_else(|| vec![]);
e7ee237c
LK
545 args.push("--document-private-items".into());
546 extra_args = Some(args);
547 }
548
1d1b3447
JN
549 if let Some(args) = extra_args {
550 extra_compiler_args
551 .entry(unit.clone())
552 .or_default()
553 .extend(args);
1ef954ea
EH
554 }
555 }
b3ade7c7 556 }
575d6e81 557
e0bd9e23
EH
558 let bcx = BuildContext::new(
559 ws,
560 pkg_set,
561 build_config,
562 profiles,
563 extra_compiler_args,
564 target_data,
565 units,
566 unit_graph,
567 )?;
8b840393 568
e0bd9e23 569 Ok(bcx)
62bff631 570}
51c9cf0f 571
bb643cca
AK
572impl FilterRule {
573 pub fn new(targets: Vec<String>, all: bool) -> FilterRule {
2a82378a
BW
574 if all {
575 FilterRule::All
576 } else {
577 FilterRule::Just(targets)
578 }
579 }
580
12307fc2
DW
581 pub fn none() -> FilterRule {
582 FilterRule::Just(Vec::new())
583 }
584
2a82378a
BW
585 fn matches(&self, target: &Target) -> bool {
586 match *self {
587 FilterRule::All => true,
1e682848 588 FilterRule::Just(ref targets) => targets.iter().any(|x| *x == target.name()),
2a82378a
BW
589 }
590 }
591
592 fn is_specific(&self) -> bool {
593 match *self {
594 FilterRule::All => true,
bb643cca 595 FilterRule::Just(ref targets) => !targets.is_empty(),
2a82378a
BW
596 }
597 }
598
599 pub fn try_collect(&self) -> Option<Vec<String>> {
600 match *self {
601 FilterRule::All => None,
bb643cca 602 FilterRule::Just(ref targets) => Some(targets.clone()),
2a82378a
BW
603 }
604 }
42696ae2
WL
605
606 pub(crate) fn contains_glob_patterns(&self) -> bool {
607 match self {
608 FilterRule::All => false,
609 FilterRule::Just(targets) => targets.iter().any(is_glob_pattern),
610 }
611 }
2a82378a
BW
612}
613
bb643cca 614impl CompileFilter {
12307fc2
DW
615 /// Construct a CompileFilter from raw command line arguments.
616 pub fn from_raw_arguments(
1e682848
AC
617 lib_only: bool,
618 bins: Vec<String>,
619 all_bins: bool,
620 tsts: Vec<String>,
621 all_tsts: bool,
622 exms: Vec<String>,
623 all_exms: bool,
624 bens: Vec<String>,
625 all_bens: bool,
626 all_targets: bool,
627 ) -> CompileFilter {
5a59b809
EH
628 if all_targets {
629 return CompileFilter::new_all_targets();
630 }
f16efff1
AC
631 let rule_lib = if lib_only {
632 LibRule::True
633 } else {
634 LibRule::False
635 };
2a82378a
BW
636 let rule_bins = FilterRule::new(bins, all_bins);
637 let rule_tsts = FilterRule::new(tsts, all_tsts);
638 let rule_exms = FilterRule::new(exms, all_exms);
639 let rule_bens = FilterRule::new(bens, all_bens);
640
5a59b809 641 CompileFilter::new(rule_lib, rule_bins, rule_tsts, rule_exms, rule_bens)
12307fc2
DW
642 }
643
644 /// Construct a CompileFilter from underlying primitives.
645 pub fn new(
aef99e0e 646 rule_lib: LibRule,
12307fc2
DW
647 rule_bins: FilterRule,
648 rule_tsts: FilterRule,
649 rule_exms: FilterRule,
650 rule_bens: FilterRule,
651 ) -> CompileFilter {
aef99e0e 652 if rule_lib == LibRule::True
dae87a26
E
653 || rule_bins.is_specific()
654 || rule_tsts.is_specific()
655 || rule_exms.is_specific()
656 || rule_bens.is_specific()
1e682848 657 {
7a1d8d94 658 CompileFilter::Only {
b9497ab2 659 all_targets: false,
aef99e0e 660 lib: rule_lib,
1e682848
AC
661 bins: rule_bins,
662 examples: rule_exms,
663 benches: rule_bens,
2a82378a 664 tests: rule_tsts,
7a1d8d94
AC
665 }
666 } else {
6344db05 667 CompileFilter::Default {
25e50b58
JB
668 required_features_filterable: true,
669 }
7a1d8d94
AC
670 }
671 }
672
5a59b809
EH
673 pub fn new_all_targets() -> CompileFilter {
674 CompileFilter::Only {
675 all_targets: true,
676 lib: LibRule::Default,
677 bins: FilterRule::All,
678 examples: FilterRule::All,
679 benches: FilterRule::All,
680 tests: FilterRule::All,
681 }
682 }
683
89d5161d
XL
684 pub fn need_dev_deps(&self, mode: CompileMode) -> bool {
685 match mode {
686 CompileMode::Test | CompileMode::Doctest | CompileMode::Bench => true,
b112255f
EH
687 CompileMode::Check { test: true } => true,
688 CompileMode::Build | CompileMode::Doc { .. } | CompileMode::Check { test: false } => {
689 match *self {
690 CompileFilter::Default { .. } => false,
691 CompileFilter::Only {
692 ref examples,
693 ref tests,
694 ref benches,
695 ..
696 } => examples.is_specific() || tests.is_specific() || benches.is_specific(),
697 }
698 }
575d6e81 699 CompileMode::RunCustomBuild => panic!("Invalid mode"),
7de30dd2
XL
700 }
701 }
702
ce26ddfd 703 // this selects targets for "cargo run". for logic to select targets for
771fec3c 704 // other subcommands, see generate_targets and filter_default_targets
ce26ddfd 705 pub fn target_run(&self, target: &Target) -> bool {
9e779198 706 match *self {
70170d1b 707 CompileFilter::Default { .. } => true,
1e682848 708 CompileFilter::Only {
aef99e0e 709 ref lib,
1e682848
AC
710 ref bins,
711 ref examples,
712 ref tests,
713 ref benches,
714 ..
715 } => {
2a82378a 716 let rule = match *target.kind() {
9e779198
AC
717 TargetKind::Bin => bins,
718 TargetKind::Test => tests,
719 TargetKind::Bench => benches,
1e682848 720 TargetKind::ExampleBin | TargetKind::ExampleLib(..) => examples,
f16efff1
AC
721 TargetKind::Lib(..) => {
722 return match *lib {
723 LibRule::True => true,
724 LibRule::Default => true,
725 LibRule::False => false,
726 };
727 }
9e779198
AC
728 TargetKind::CustomBuild => return false,
729 };
2a82378a 730 rule.matches(target)
9e779198
AC
731 }
732 }
733 }
c98b8c4c
BW
734
735 pub fn is_specific(&self) -> bool {
736 match *self {
6344db05 737 CompileFilter::Default { .. } => false,
c98b8c4c
BW
738 CompileFilter::Only { .. } => true,
739 }
740 }
42696ae2
WL
741
742 pub(crate) fn contains_glob_patterns(&self) -> bool {
743 match self {
744 CompileFilter::Default { .. } => false,
745 CompileFilter::Only {
746 bins,
747 examples,
748 tests,
749 benches,
750 ..
751 } => {
752 bins.contains_glob_patterns()
753 || examples.contains_glob_patterns()
754 || tests.contains_glob_patterns()
755 || benches.contains_glob_patterns()
756 }
757 }
758 }
9e779198
AC
759}
760
3a1cad6f
EH
761/// A proposed target.
762///
f7c91ba6 763/// Proposed targets are later filtered into actual `Unit`s based on whether or
3a1cad6f
EH
764/// not the target requires its features to be present.
765#[derive(Debug)]
766struct Proposal<'a> {
fbd34a69 767 pkg: &'a Package,
45d49579 768 target: &'a Target,
3a1cad6f
EH
769 /// Indicates whether or not all required features *must* be present. If
770 /// false, and the features are not available, then it will be silently
771 /// skipped. Generally, targets specified by name (`--bin foo`) are
772 /// required, all others can be silently skipped if features are missing.
773 requires_features: bool,
774 mode: CompileMode,
775}
776
575d6e81 777/// Generates all the base targets for the packages the user has requested to
f7c91ba6 778/// compile. Dependencies for these targets are computed later in `unit_dependencies`.
c85ed044 779fn generate_targets(
b8b7faee 780 ws: &Workspace<'_>,
fbd34a69 781 packages: &[&Package],
575d6e81 782 filter: &CompileFilter,
3fd28143 783 requested_kinds: &[CompileKind],
e0bd9e23
EH
784 mode: CompileMode,
785 resolve: &Resolve,
19a95790 786 workspace_resolve: &Option<Resolve>,
7caa1612 787 resolved_features: &features::ResolvedFeatures,
e0bd9e23
EH
788 package_set: &PackageSet<'_>,
789 profiles: &Profiles,
c85ed044
AC
790 interner: &UnitInterner,
791) -> CargoResult<Vec<Unit>> {
e0bd9e23 792 let config = ws.config();
3fd28143
AC
793 // Helper for creating a list of `Unit` structures
794 let new_unit =
795 |units: &mut HashSet<Unit>, pkg: &Package, target: &Target, target_mode: CompileMode| {
796 let unit_for = if target_mode.is_any_test() {
797 // NOTE: the `UnitFor` here is subtle. If you have a profile
798 // with `panic` set, the `panic` flag is cleared for
799 // tests/benchmarks and their dependencies. If this
800 // was `normal`, then the lib would get compiled three
801 // times (once with panic, once without, and once with
802 // `--test`).
803 //
804 // This would cause a problem for doc tests, which would fail
805 // because `rustdoc` would attempt to link with both libraries
806 // at the same time. Also, it's probably not important (or
807 // even desirable?) for rustdoc to link with a lib with
808 // `panic` set.
809 //
810 // As a consequence, Examples and Binaries get compiled
811 // without `panic` set. This probably isn't a bad deal.
812 //
813 // Forcing the lib to be compiled three times during `cargo
814 // test` is probably also not desirable.
815 UnitFor::new_test(config)
816 } else if target.for_host() {
817 // Proc macro / plugin should not have `panic` set.
818 UnitFor::new_compiler()
819 } else {
820 UnitFor::new_normal()
821 };
822 // Custom build units are added in `build_unit_dependencies`.
823 assert!(!target.is_custom_build());
824 let target_mode = match target_mode {
825 CompileMode::Test => {
826 if target.is_example() && !filter.is_specific() && !target.tested() {
827 // Examples are included as regular binaries to verify
828 // that they compile.
829 CompileMode::Build
830 } else {
831 CompileMode::Test
832 }
2a82378a 833 }
3fd28143
AC
834 CompileMode::Build => match *target.kind() {
835 TargetKind::Test => CompileMode::Test,
836 TargetKind::Bench => CompileMode::Bench,
837 _ => CompileMode::Build,
838 },
839 // `CompileMode::Bench` is only used to inform `filter_default_targets`
840 // which command is being used (`cargo bench`). Afterwards, tests
841 // and benches are treated identically. Switching the mode allows
842 // de-duplication of units that are essentially identical. For
843 // example, `cargo build --all-targets --release` creates the units
844 // (lib profile:bench, mode:test) and (lib profile:bench, mode:bench)
845 // and since these are the same, we want them to be de-duplicated in
846 // `unit_dependencies`.
847 CompileMode::Bench => CompileMode::Test,
848 _ => target_mode,
849 };
850
851 let is_local = pkg.package_id().source_id().is_path();
852 let profile = profiles.get_profile(
853 pkg.package_id(),
854 ws.is_member(pkg),
855 is_local,
856 unit_for,
857 target_mode,
858 );
859
860 // No need to worry about build-dependencies, roots are never build dependencies.
861 let features_for = FeaturesFor::from_for_host(target.proc_macro());
862 let features = resolved_features.activated_features(pkg.package_id(), features_for);
863
864 for kind in requested_kinds {
865 let unit = interner.intern(
866 pkg,
867 target,
868 profile,
869 kind.for_target(target),
870 target_mode,
871 features.clone(),
872 /*is_std*/ false,
9efa0d55 873 /*dep_hash*/ 0,
3fd28143
AC
874 );
875 units.insert(unit);
2a82378a 876 }
575d6e81
EH
877 };
878
3a1cad6f 879 // Create a list of proposed targets.
b8b7faee 880 let mut proposals: Vec<Proposal<'_>> = Vec::new();
771fec3c
EH
881
882 match *filter {
883 CompileFilter::Default {
884 required_features_filterable,
885 } => {
886 for pkg in packages {
e0bd9e23 887 let default = filter_default_targets(pkg.targets(), mode);
3a1cad6f
EH
888 proposals.extend(default.into_iter().map(|target| Proposal {
889 pkg,
890 target,
891 requires_features: !required_features_filterable,
e0bd9e23 892 mode,
771fec3c 893 }));
e0bd9e23 894 if mode == CompileMode::Test {
dd6c6102
EH
895 if let Some(t) = pkg
896 .targets()
897 .iter()
898 .find(|t| t.is_lib() && t.doctested() && t.doctestable())
899 {
3a1cad6f
EH
900 proposals.push(Proposal {
901 pkg,
902 target: t,
903 requires_features: false,
904 mode: CompileMode::Doctest,
905 });
575d6e81 906 }
2a82378a
BW
907 }
908 }
771fec3c
EH
909 }
910 CompileFilter::Only {
911 all_targets,
aef99e0e 912 ref lib,
771fec3c
EH
913 ref bins,
914 ref examples,
915 ref tests,
916 ref benches,
917 } => {
aef99e0e 918 if *lib != LibRule::False {
771fec3c 919 let mut libs = Vec::new();
e0bd9e23 920 for proposal in filter_targets(packages, Target::is_lib, false, mode) {
df9ca871 921 let Proposal { target, pkg, .. } = proposal;
e0bd9e23 922 if mode.is_doc_test() && !target.doctestable() {
7a06be14
EH
923 let types = target.rustc_crate_types();
924 let types_str: Vec<&str> = types.iter().map(|t| t.as_str()).collect();
df9ca871
DW
925 ws.config().shell().warn(format!(
926 "doc tests are not supported for crate type(s) `{}` in package `{}`",
7a06be14 927 types_str.join(", "),
df9ca871
DW
928 pkg.name()
929 ))?;
930 } else {
931 libs.push(proposal)
575d6e81
EH
932 }
933 }
aef99e0e 934 if !all_targets && libs.is_empty() && *lib == LibRule::True {
771fec3c
EH
935 let names = packages.iter().map(|pkg| pkg.name()).collect::<Vec<_>>();
936 if names.len() == 1 {
3a18c89a 937 anyhow::bail!("no library targets found in package `{}`", names[0]);
771fec3c 938 } else {
3a18c89a 939 anyhow::bail!("no library targets found in packages: {}", names.join(", "));
771fec3c
EH
940 }
941 }
942 proposals.extend(libs);
575d6e81 943 }
3a1cad6f 944
f7c91ba6 945 // If `--tests` was specified, add all targets that would be
771fec3c 946 // generated by `cargo test`.
df9ca871 947 let test_filter = match tests {
771fec3c
EH
948 FilterRule::All => Target::tested,
949 FilterRule::Just(_) => Target::is_test,
950 };
e0bd9e23 951 let test_mode = match mode {
771fec3c
EH
952 CompileMode::Build => CompileMode::Test,
953 CompileMode::Check { .. } => CompileMode::Check { test: true },
e0bd9e23 954 _ => mode,
771fec3c 955 };
f7c91ba6 956 // If `--benches` was specified, add all targets that would be
771fec3c 957 // generated by `cargo bench`.
df9ca871 958 let bench_filter = match benches {
771fec3c
EH
959 FilterRule::All => Target::benched,
960 FilterRule::Just(_) => Target::is_bench,
961 };
e0bd9e23 962 let bench_mode = match mode {
771fec3c
EH
963 CompileMode::Build => CompileMode::Bench,
964 CompileMode::Check { .. } => CompileMode::Check { test: true },
e0bd9e23 965 _ => mode,
771fec3c
EH
966 };
967
968 proposals.extend(list_rule_targets(
969 packages,
970 bins,
971 "bin",
972 Target::is_bin,
e0bd9e23 973 mode,
771fec3c
EH
974 )?);
975 proposals.extend(list_rule_targets(
976 packages,
977 examples,
978 "example",
979 Target::is_example,
e0bd9e23 980 mode,
771fec3c
EH
981 )?);
982 proposals.extend(list_rule_targets(
983 packages,
984 tests,
985 "test",
986 test_filter,
987 test_mode,
988 )?);
989 proposals.extend(list_rule_targets(
990 packages,
991 benches,
992 "bench",
993 bench_filter,
994 bench_mode,
995 )?);
2a82378a 996 }
771fec3c 997 }
2a82378a 998
771fec3c
EH
999 // Only include targets that are libraries or have all required
1000 // features available.
7caa1612
EH
1001 //
1002 // `features_map` is a map of &Package -> enabled_features
1003 // It is computed by the set of enabled features for the package plus
1004 // every enabled feature of every enabled dependency.
771fec3c 1005 let mut features_map = HashMap::new();
3a1cad6f 1006 let mut units = HashSet::new();
dae87a26
E
1007 for Proposal {
1008 pkg,
1009 target,
1010 requires_features,
1011 mode,
1012 } in proposals
1013 {
771fec3c
EH
1014 let unavailable_features = match target.required_features() {
1015 Some(rf) => {
bcfdf9fb 1016 validate_required_features(
19a95790 1017 workspace_resolve,
bcfdf9fb 1018 target.name(),
19a95790
AT
1019 rf,
1020 pkg.summary(),
1021 &mut config.shell(),
1022 )?;
1023
7caa1612 1024 let features = features_map.entry(pkg).or_insert_with(|| {
e0bd9e23 1025 resolve_all_features(resolve, resolved_features, package_set, pkg.package_id())
7caa1612 1026 });
771fec3c 1027 rf.iter().filter(|f| !features.contains(*f)).collect()
2a82378a 1028 }
771fec3c
EH
1029 None => Vec::new(),
1030 };
1031 if target.is_lib() || unavailable_features.is_empty() {
3fd28143 1032 new_unit(&mut units, pkg, target, mode);
3a1cad6f 1033 } else if requires_features {
771fec3c
EH
1034 let required_features = target.required_features().unwrap();
1035 let quoted_required_features: Vec<String> = required_features
1036 .iter()
1037 .map(|s| format!("`{}`", s))
1038 .collect();
3a18c89a 1039 anyhow::bail!(
771fec3c 1040 "target `{}` in package `{}` requires the features: {}\n\
f7c91ba6 1041 Consider enabling them by passing, e.g., `--features=\"{}\"`",
771fec3c
EH
1042 target.name(),
1043 pkg.name(),
1044 quoted_required_features.join(", "),
1045 required_features.join(" ")
1046 );
2a82378a 1047 }
771fec3c 1048 // else, silently skip target.
2a82378a 1049 }
3a1cad6f 1050 Ok(units.into_iter().collect())
2a82378a
BW
1051}
1052
bcfdf9fb
EH
1053/// Warns if a target's required-features references a feature that doesn't exist.
1054///
1055/// This is a warning because historically this was not validated, and it
1056/// would cause too much breakage to make it an error.
1057fn validate_required_features(
19a95790 1058 resolve: &Option<Resolve>,
bcfdf9fb 1059 target_name: &str,
19a95790
AT
1060 required_features: &[String],
1061 summary: &Summary,
1062 shell: &mut Shell,
1063) -> CargoResult<()> {
1064 let resolve = match resolve {
1065 None => return Ok(()),
1066 Some(resolve) => resolve,
1067 };
1068
1069 for feature in required_features {
bcfdf9fb
EH
1070 let fv = FeatureValue::new(feature.into());
1071 match &fv {
1072 FeatureValue::Feature(f) => {
1073 if !summary.features().contains_key(f) {
19a95790 1074 shell.warn(format!(
bcfdf9fb
EH
1075 "invalid feature `{}` in required-features of target `{}`: \
1076 `{}` is not present in [features] section",
1077 fv, target_name, fv
19a95790
AT
1078 ))?;
1079 }
1080 }
f4ac82a0
EH
1081 FeatureValue::Dep { .. }
1082 | FeatureValue::DepFeature {
1083 dep_prefix: true, ..
8ff130bb 1084 } => {
bcfdf9fb
EH
1085 anyhow::bail!(
1086 "invalid feature `{}` in required-features of target `{}`: \
f4ac82a0 1087 `dep:` prefixed feature values are not allowed in required-features",
bcfdf9fb
EH
1088 fv,
1089 target_name
1090 );
1091 }
9ffcf690
EH
1092 FeatureValue::DepFeature { weak: true, .. } => {
1093 anyhow::bail!(
1094 "invalid feature `{}` in required-features of target `{}`: \
1095 optional dependency with `?` is not allowed in required-features",
1096 fv,
1097 target_name
1098 );
1099 }
19a95790 1100 // Handling of dependent_crate/dependent_crate_feature syntax
f4ac82a0 1101 FeatureValue::DepFeature {
bcfdf9fb
EH
1102 dep_name,
1103 dep_feature,
f4ac82a0 1104 dep_prefix: false,
9ffcf690 1105 weak: false,
bcfdf9fb 1106 } => {
19a95790
AT
1107 match resolve
1108 .deps(summary.package_id())
bcfdf9fb 1109 .find(|(_dep_id, deps)| deps.iter().any(|dep| dep.name_in_toml() == *dep_name))
19a95790
AT
1110 {
1111 Some((dep_id, _deps)) => {
1112 let dep_summary = resolve.summary(dep_id);
bcfdf9fb 1113 if !dep_summary.features().contains_key(dep_feature)
19a95790
AT
1114 && !dep_summary
1115 .dependencies()
1116 .iter()
bcfdf9fb 1117 .any(|dep| dep.name_in_toml() == *dep_feature && dep.is_optional())
19a95790
AT
1118 {
1119 shell.warn(format!(
bcfdf9fb
EH
1120 "invalid feature `{}` in required-features of target `{}`: \
1121 feature `{}` does not exist in package `{}`",
1122 fv, target_name, dep_feature, dep_id
19a95790
AT
1123 ))?;
1124 }
1125 }
1126 None => {
1127 shell.warn(format!(
bcfdf9fb
EH
1128 "invalid feature `{}` in required-features of target `{}`: \
1129 dependency `{}` does not exist",
1130 fv, target_name, dep_name
19a95790
AT
1131 ))?;
1132 }
1133 }
1134 }
1135 }
1136 }
1137 Ok(())
1138}
1139
3f068230
EH
1140/// Gets all of the features enabled for a package, plus its dependencies'
1141/// features.
1142///
1143/// Dependencies are added as `dep_name/feat_name` because `required-features`
1144/// wants to support that syntax.
8b17895b 1145pub fn resolve_all_features(
575d6e81 1146 resolve_with_overrides: &Resolve,
7caa1612 1147 resolved_features: &features::ResolvedFeatures,
944f5049 1148 package_set: &PackageSet<'_>,
dae87a26 1149 package_id: PackageId,
575d6e81 1150) -> HashSet<String> {
7caa1612 1151 let mut features: HashSet<String> = resolved_features
137642c4 1152 .activated_features(package_id, FeaturesFor::NormalOrDev)
7caa1612
EH
1153 .iter()
1154 .map(|s| s.to_string())
1155 .collect();
575d6e81
EH
1156
1157 // Include features enabled for use by dependencies so targets can also use them with the
1158 // required-features field when deciding whether to be built or skipped.
cafec114 1159 for (dep_id, deps) in resolve_with_overrides.deps(package_id) {
944f5049
EH
1160 let is_proc_macro = package_set
1161 .get_one(dep_id)
1162 .expect("packages downloaded")
1163 .proc_macro();
8973b959 1164 for dep in deps {
96a39371 1165 let features_for = FeaturesFor::from_for_host(is_proc_macro || dep.is_build());
e94facea
R
1166 for feature in resolved_features
1167 .activated_features_unverified(dep_id, features_for)
1168 .unwrap_or_default()
1169 {
887ee6cc 1170 features.insert(format!("{}/{}", dep.name_in_toml(), feature));
cafec114 1171 }
575d6e81
EH
1172 }
1173 }
1174
1175 features
1176}
1177
1178/// Given a list of all targets for a package, filters out only the targets
1179/// that are automatically included when the user doesn't specify any targets.
45d49579 1180fn filter_default_targets(targets: &[Target], mode: CompileMode) -> Vec<&Target> {
575d6e81
EH
1181 match mode {
1182 CompileMode::Bench => targets.iter().filter(|t| t.benched()).collect(),
a4947c2b
EH
1183 CompileMode::Test => targets
1184 .iter()
1185 .filter(|t| t.tested() || t.is_example())
1186 .collect(),
575d6e81
EH
1187 CompileMode::Build | CompileMode::Check { .. } => targets
1188 .iter()
1189 .filter(|t| t.is_bin() || t.is_lib())
1190 .collect(),
1191 CompileMode::Doc { .. } => {
1192 // `doc` does lib and bins (bin with same name as lib is skipped).
1193 targets
1e682848 1194 .iter()
575d6e81
EH
1195 .filter(|t| {
1196 t.documented()
1197 && (!t.is_bin()
1198 || !targets.iter().any(|l| l.is_lib() && l.name() == t.name()))
1199 })
1200 .collect()
2a82378a 1201 }
00d325db 1202 CompileMode::Doctest | CompileMode::RunCustomBuild => panic!("Invalid mode {:?}", mode),
2a82378a 1203 }
2a82378a
BW
1204}
1205
df9ca871 1206/// Returns a list of proposed targets based on command-line target selection flags.
575d6e81 1207fn list_rule_targets<'a>(
fbd34a69 1208 packages: &[&'a Package],
575d6e81
EH
1209 rule: &FilterRule,
1210 target_desc: &'static str,
1211 is_expected_kind: fn(&Target) -> bool,
771fec3c 1212 mode: CompileMode,
3a1cad6f 1213) -> CargoResult<Vec<Proposal<'a>>> {
df9ca871
DW
1214 let mut proposals = Vec::new();
1215 match rule {
771fec3c 1216 FilterRule::All => {
df9ca871 1217 proposals.extend(filter_targets(packages, is_expected_kind, false, mode))
771fec3c 1218 }
df9ca871 1219 FilterRule::Just(names) => {
771fec3c 1220 for name in names {
df9ca871 1221 proposals.extend(find_named_targets(
771fec3c
EH
1222 packages,
1223 name,
1224 target_desc,
1225 is_expected_kind,
1226 mode,
1227 )?);
1228 }
1229 }
575d6e81 1230 }
df9ca871 1231 Ok(proposals)
575d6e81 1232}
235712f5 1233
f7c91ba6 1234/// Finds the targets for a specifically named target.
771fec3c 1235fn find_named_targets<'a>(
fbd34a69 1236 packages: &[&'a Package],
575d6e81
EH
1237 target_name: &str,
1238 target_desc: &'static str,
1239 is_expected_kind: fn(&Target) -> bool,
771fec3c 1240 mode: CompileMode,
3a1cad6f 1241) -> CargoResult<Vec<Proposal<'a>>> {
42696ae2
WL
1242 let is_glob = is_glob_pattern(target_name);
1243 let proposals = if is_glob {
1244 let pattern = build_glob(target_name)?;
1245 let filter = |t: &Target| is_expected_kind(t) && pattern.matches(t.name());
1246 filter_targets(packages, filter, true, mode)
1247 } else {
1248 let filter = |t: &Target| t.name() == target_name && is_expected_kind(t);
1249 filter_targets(packages, filter, true, mode)
1250 };
1251
df9ca871 1252 if proposals.is_empty() {
7d7fe679
EH
1253 let targets = packages.iter().flat_map(|pkg| {
1254 pkg.targets()
1255 .iter()
1256 .filter(|target| is_expected_kind(target))
1257 });
1258 let suggestion = closest_msg(target_name, targets, |t| t.name());
3a18c89a 1259 anyhow::bail!(
42696ae2 1260 "no {} target {} `{}`{}",
7d7fe679 1261 target_desc,
42696ae2 1262 if is_glob { "matches pattern" } else { "named" },
7d7fe679
EH
1263 target_name,
1264 suggestion
1265 );
771fec3c 1266 }
df9ca871
DW
1267 Ok(proposals)
1268}
1269
1270fn filter_targets<'a>(
fbd34a69 1271 packages: &[&'a Package],
df9ca871
DW
1272 predicate: impl Fn(&Target) -> bool,
1273 requires_features: bool,
1274 mode: CompileMode,
1275) -> Vec<Proposal<'a>> {
1276 let mut proposals = Vec::new();
1277 for pkg in packages {
1278 for target in pkg.targets().iter().filter(|t| predicate(t)) {
1279 proposals.push(Proposal {
1280 pkg,
1281 target,
1282 requires_features,
1283 mode,
1284 });
1285 }
1286 }
1287 proposals
9e779198 1288}
9efa0d55
EH
1289
1290/// This is used to rebuild the unit graph, sharing host dependencies if possible.
1291///
1292/// This will translate any unit's `CompileKind::Target(host)` to
1293/// `CompileKind::Host` if the kind is equal to `to_host`. This also handles
1294/// generating the unit `dep_hash`, and merging shared units if possible.
1295///
1296/// This is necessary because if normal dependencies used `CompileKind::Host`,
1297/// there would be no way to distinguish those units from build-dependency
1298/// units. This can cause a problem if a shared normal/build dependency needs
1299/// to link to another dependency whose features differ based on whether or
1300/// not it is a normal or build dependency. If both units used
1301/// `CompileKind::Host`, then they would end up being identical, causing a
1302/// collision in the `UnitGraph`, and Cargo would end up randomly choosing one
1303/// value or the other.
1304///
1305/// The solution is to keep normal and build dependencies separate when
1306/// building the unit graph, and then run this second pass which will try to
1307/// combine shared dependencies safely. By adding a hash of the dependencies
1308/// to the `Unit`, this allows the `CompileKind` to be changed back to `Host`
1309/// without fear of an unwanted collision.
1310fn rebuild_unit_graph_shared(
1311 interner: &UnitInterner,
1312 unit_graph: UnitGraph,
1313 roots: &[Unit],
1314 to_host: CompileKind,
1315) -> (Vec<Unit>, UnitGraph) {
1316 let mut result = UnitGraph::new();
1317 // Map of the old unit to the new unit, used to avoid recursing into units
1318 // that have already been computed to improve performance.
1319 let mut memo = HashMap::new();
1320 let new_roots = roots
1321 .iter()
1322 .map(|root| {
1323 traverse_and_share(interner, &mut memo, &mut result, &unit_graph, root, to_host)
1324 })
1325 .collect();
1326 (new_roots, result)
1327}
1328
1329/// Recursive function for rebuilding the graph.
1330///
1331/// This walks `unit_graph`, starting at the given `unit`. It inserts the new
1332/// units into `new_graph`, and returns a new updated version of the given
1333/// unit (`dep_hash` is filled in, and `kind` switched if necessary).
1334fn traverse_and_share(
1335 interner: &UnitInterner,
1336 memo: &mut HashMap<Unit, Unit>,
1337 new_graph: &mut UnitGraph,
1338 unit_graph: &UnitGraph,
1339 unit: &Unit,
1340 to_host: CompileKind,
1341) -> Unit {
1342 if let Some(new_unit) = memo.get(unit) {
1343 // Already computed, no need to recompute.
1344 return new_unit.clone();
1345 }
1346 let mut dep_hash = StableHasher::new();
1347 let new_deps: Vec<_> = unit_graph[unit]
1348 .iter()
1349 .map(|dep| {
1350 let new_dep_unit =
1351 traverse_and_share(interner, memo, new_graph, unit_graph, &dep.unit, to_host);
1352 new_dep_unit.hash(&mut dep_hash);
1353 UnitDep {
1354 unit: new_dep_unit,
1355 ..dep.clone()
1356 }
1357 })
1358 .collect();
1359 let new_dep_hash = dep_hash.finish();
1360 let new_kind = if unit.kind == to_host {
1361 CompileKind::Host
1362 } else {
1363 unit.kind
1364 };
1365 let new_unit = interner.intern(
1366 &unit.pkg,
1367 &unit.target,
1368 unit.profile,
1369 new_kind,
1370 unit.mode,
1371 unit.features.clone(),
1372 unit.is_std,
1373 new_dep_hash,
1374 );
1375 assert!(memo.insert(unit.clone(), new_unit.clone()).is_none());
1376 new_graph.entry(new_unit.clone()).or_insert(new_deps);
1377 new_unit
1378}
42696ae2 1379
2361fb0f 1380/// Build `glob::Pattern` with informative context.
42696ae2 1381fn build_glob(pat: &str) -> CargoResult<glob::Pattern> {
5e3dc467 1382 glob::Pattern::new(pat).with_context(|| format!("cannot build glob pattern from `{}`", pat))
42696ae2 1383}
2361fb0f
WL
1384
1385/// Emits "package not found" error.
1386///
1387/// > This function should be used only in package selection processes such like
1388/// `Packages::to_package_id_specs` and `Packages::get_packages`.
1389fn emit_package_not_found(
1390 ws: &Workspace<'_>,
1391 opt_names: BTreeSet<&str>,
1392 opt_out: bool,
1393) -> CargoResult<()> {
1394 if !opt_names.is_empty() {
1395 anyhow::bail!(
5e3dc467 1396 "{}package(s) `{}` not found in workspace `{}`",
2361fb0f 1397 if opt_out { "excluded " } else { "" },
3d042688 1398 opt_names.into_iter().collect::<Vec<_>>().join(", "),
2361fb0f
WL
1399 ws.root().display(),
1400 )
1401 }
1402 Ok(())
1403}
1404
1405/// Emits "glob pattern not found" error.
1406///
1407/// > This function should be used only in package selection processes such like
1408/// `Packages::to_package_id_specs` and `Packages::get_packages`.
1409fn emit_pattern_not_found(
1410 ws: &Workspace<'_>,
1411 opt_patterns: Vec<(glob::Pattern, bool)>,
1412 opt_out: bool,
1413) -> CargoResult<()> {
1414 let not_matched = opt_patterns
1415 .iter()
1416 .filter(|(_, matched)| !*matched)
1417 .map(|(pat, _)| pat.as_str())
1418 .collect::<Vec<_>>();
1419 if !not_matched.is_empty() {
1420 anyhow::bail!(
5e3dc467 1421 "{}package pattern(s) `{}` not found in workspace `{}`",
2361fb0f
WL
1422 if opt_out { "excluded " } else { "" },
1423 not_matched.join(", "),
1424 ws.root().display(),
1425 )
1426 }
1427 Ok(())
1428}
1429
1430/// Checks whether a package matches any of a list of glob patterns generated
1431/// from `opt_patterns_and_names`.
1432///
1433/// > This function should be used only in package selection processes such like
1434/// `Packages::to_package_id_specs` and `Packages::get_packages`.
1435fn match_patterns(pkg: &Package, patterns: &mut Vec<(glob::Pattern, bool)>) -> bool {
1436 patterns.iter_mut().any(|(m, matched)| {
1437 let is_matched = m.matches(pkg.name().as_str());
1438 *matched |= is_matched;
1439 is_matched
1440 })
1441}
1442
1443/// Given a list opt-in or opt-out package selection strings, generates two
1444/// collections that represent glob patterns and package names respectively.
1445///
1446/// > This function should be used only in package selection processes such like
1447/// `Packages::to_package_id_specs` and `Packages::get_packages`.
1448fn opt_patterns_and_names(
1449 opt: &[String],
1450) -> CargoResult<(Vec<(glob::Pattern, bool)>, BTreeSet<&str>)> {
1451 let mut opt_patterns = Vec::new();
1452 let mut opt_names = BTreeSet::new();
1453 for x in opt.iter() {
1454 if is_glob_pattern(x) {
1455 opt_patterns.push((build_glob(x)?, false));
1456 } else {
1457 opt_names.insert(String::as_str(x));
1458 }
1459 }
1460 Ok((opt_patterns, opt_names))
1461}