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