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