1use std::collections::{BTreeSet, HashMap, HashSet};
27use std::iter::FromIterator;
28use std::path::PathBuf;
29use std::sync::Arc;
30
31use crate::core::compiler::standard_lib;
32use crate::core::compiler::unit_dependencies::{
33 build_unit_dependencies, filter_locals, filter_roots,
34};
35use crate::core::compiler::unit_graph;
36use crate::core::compiler::{BuildConfig, BuildContext, Compilation, Context};
37use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit};
38use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner};
39use crate::core::profiles::{Profiles, UnitFor};
40use crate::core::resolver::features::{self, FeaturesFor};
41use crate::core::resolver::{HasDevUnits, Resolve, ResolveOpts};
42use crate::core::{LibKind, Package, PackageSet, Target};
43use crate::core::{PackageId, PackageIdSpec, TargetKind, Workspace};
44use crate::ops;
45use crate::ops::resolve::WorkspaceResolve;
46use crate::util::config::Config;
47use crate::util::{closest_msg, profile, CargoResult};
48
49#[derive(Debug)]
51pub struct CompileOptions {
52 pub build_config: BuildConfig,
54 pub features: Vec<String>,
56 pub all_features: bool,
58 pub no_default_features: bool,
60 pub spec: Packages,
62 pub filter: CompileFilter,
65 pub deps_only: bool,
67 pub deps_remote_only: bool,
69 pub target_rustdoc_args: Option<Vec<String>>,
71 pub target_rustc_args: Option<Vec<String>>,
74 pub local_rustdoc_args: Option<Vec<String>>,
76 pub rustdoc_document_private_items: bool,
79 pub export_dir: Option<PathBuf>,
85}
86
87impl<'a> CompileOptions {
88 pub fn new(config: &Config, mode: CompileMode) -> CargoResult<CompileOptions> {
89 Ok(CompileOptions {
90 build_config: BuildConfig::new(config, None, &None, mode)?,
91 features: Vec::new(),
92 all_features: false,
93 no_default_features: false,
94 spec: ops::Packages::Packages(Vec::new()),
95 filter: CompileFilter::Default {
96 required_features_filterable: false,
97 },
98 deps_only: false,
99 deps_remote_only: false,
100 target_rustdoc_args: None,
101 target_rustc_args: None,
102 local_rustdoc_args: None,
103 rustdoc_document_private_items: false,
104 export_dir: None,
105 })
106 }
107}
108
109#[derive(Clone, PartialEq, Eq, Debug)]
110pub enum Packages {
111 Default,
112 All,
113 OptOut(Vec<String>),
114 Packages(Vec<String>),
115}
116
117impl Packages {
118 pub fn from_flags(all: bool, exclude: Vec<String>, package: Vec<String>) -> CargoResult<Self> {
119 Ok(match (all, exclude.len(), package.len()) {
120 (false, 0, 0) => Packages::Default,
121 (false, 0, _) => Packages::Packages(package),
122 (false, _, _) => anyhow::bail!("--exclude can only be used together with --workspace"),
123 (true, 0, _) => Packages::All,
124 (true, _, _) => Packages::OptOut(exclude),
125 })
126 }
127
128 pub fn to_package_id_specs(&self, ws: &Workspace<'_>) -> CargoResult<Vec<PackageIdSpec>> {
129 let specs = match self {
130 Packages::All => ws
131 .members()
132 .map(Package::package_id)
133 .map(PackageIdSpec::from_package_id)
134 .collect(),
135 Packages::OptOut(opt_out) => {
136 let mut opt_out = BTreeSet::from_iter(opt_out.iter().cloned());
137 let packages = ws
138 .members()
139 .filter(|pkg| !opt_out.remove(pkg.name().as_str()))
140 .map(Package::package_id)
141 .map(PackageIdSpec::from_package_id)
142 .collect();
143 if !opt_out.is_empty() {
144 ws.config().shell().warn(format!(
145 "excluded package(s) {} not found in workspace `{}`",
146 opt_out
147 .iter()
148 .map(|x| x.as_ref())
149 .collect::<Vec<_>>()
150 .join(", "),
151 ws.root().display(),
152 ))?;
153 }
154 packages
155 }
156 Packages::Packages(packages) if packages.is_empty() => {
157 vec![PackageIdSpec::from_package_id(ws.current()?.package_id())]
158 }
159 Packages::Packages(packages) => packages
160 .iter()
161 .map(|p| PackageIdSpec::parse(p))
162 .collect::<CargoResult<Vec<_>>>()?,
163 Packages::Default => ws
164 .default_members()
165 .map(Package::package_id)
166 .map(PackageIdSpec::from_package_id)
167 .collect(),
168 };
169 if specs.is_empty() {
170 if ws.is_virtual() {
171 anyhow::bail!(
172 "manifest path `{}` contains no package: The manifest is virtual, \
173 and the workspace has no members.",
174 ws.root().display()
175 )
176 }
177 anyhow::bail!("no packages to compile")
178 }
179 Ok(specs)
180 }
181
182 pub fn get_packages<'ws>(&self, ws: &'ws Workspace<'_>) -> CargoResult<Vec<&'ws Package>> {
183 let packages: Vec<_> = match self {
184 Packages::Default => ws.default_members().collect(),
185 Packages::All => ws.members().collect(),
186 Packages::OptOut(opt_out) => ws
187 .members()
188 .filter(|pkg| !opt_out.iter().any(|name| pkg.name().as_str() == name))
189 .collect(),
190 Packages::Packages(packages) => packages
191 .iter()
192 .map(|name| {
193 ws.members()
194 .find(|pkg| pkg.name().as_str() == name)
195 .ok_or_else(|| {
196 anyhow::format_err!(
197 "package `{}` is not a member of the workspace",
198 name
199 )
200 })
201 })
202 .collect::<CargoResult<Vec<_>>>()?,
203 };
204 Ok(packages)
205 }
206
207 pub fn needs_spec_flag(&self, ws: &Workspace<'_>) -> bool {
210 match self {
211 Packages::Default => ws.default_members().count() > 1,
212 Packages::All => ws.members().count() > 1,
213 Packages::Packages(_) => true,
214 Packages::OptOut(_) => true,
215 }
216 }
217}
218
219#[derive(Debug, PartialEq, Eq)]
220pub enum LibRule {
221 True,
223 Default,
225 False,
227}
228
229#[derive(Debug)]
230pub enum FilterRule {
231 All,
232 Just(Vec<String>),
233}
234
235#[derive(Debug)]
236pub enum CompileFilter {
237 Default {
238 required_features_filterable: bool,
240 },
241 Only {
242 all_targets: bool,
243 lib: LibRule,
244 bins: FilterRule,
245 examples: FilterRule,
246 tests: FilterRule,
247 benches: FilterRule,
248 },
249}
250
251pub fn compile<'a>(ws: &Workspace<'a>, options: &CompileOptions) -> CargoResult<Compilation<'a>> {
252 let exec: Arc<dyn Executor> = Arc::new(DefaultExecutor);
253 compile_with_exec(ws, options, &exec)
254}
255
256pub fn compile_with_exec<'a>(
259 ws: &Workspace<'a>,
260 options: &CompileOptions,
261 exec: &Arc<dyn Executor>,
262) -> CargoResult<Compilation<'a>> {
263 ws.emit_warnings()?;
264 compile_ws(ws, options, exec)
265}
266
267pub fn compile_ws<'a>(
268 ws: &Workspace<'a>,
269 options: &CompileOptions,
270 exec: &Arc<dyn Executor>,
271) -> CargoResult<Compilation<'a>> {
272 let CompileOptions {
273 ref build_config,
274 ref spec,
275 ref features,
276 all_features,
277 no_default_features,
278 ref filter,
279 deps_only,
280 deps_remote_only,
281 ref target_rustdoc_args,
282 ref target_rustc_args,
283 ref local_rustdoc_args,
284 rustdoc_document_private_items,
285 ref export_dir,
286 } = *options;
287 let config = ws.config();
288
289 match build_config.mode {
290 CompileMode::Test
291 | CompileMode::Build
292 | CompileMode::Check { .. }
293 | CompileMode::Bench
294 | CompileMode::RunCustomBuild => {
295 if std::env::var("RUST_FLAGS").is_ok() {
296 config.shell().warn(
297 "Cargo does not read `RUST_FLAGS` environment variable. Did you mean `RUSTFLAGS`?",
298 )?;
299 }
300 }
301 CompileMode::Doc { .. } | CompileMode::Doctest => {
302 if std::env::var("RUSTDOC_FLAGS").is_ok() {
303 config.shell().warn(
304 "Cargo does not read `RUSTDOC_FLAGS` environment variable. Did you mean `RUSTDOCFLAGS`?"
305 )?;
306 }
307 }
308 }
309
310 let profiles = Profiles::new(
311 ws.profiles(),
312 config,
313 build_config.requested_profile,
314 ws.features(),
315 )?;
316 let target_data = RustcTargetData::new(ws, build_config.requested_kind)?;
317
318 let specs = spec.to_package_id_specs(ws)?;
319 let dev_deps = ws.require_optional_deps() || filter.need_dev_deps(build_config.mode);
320 let opts = ResolveOpts::new(dev_deps, features, all_features, !no_default_features);
321 let has_dev_units = if filter.need_dev_deps(build_config.mode) {
322 HasDevUnits::Yes
323 } else {
324 HasDevUnits::No
325 };
326 let resolve = ops::resolve_ws_with_opts(
327 ws,
328 &target_data,
329 build_config.requested_kind,
330 &opts,
331 &specs,
332 has_dev_units,
333 )?;
334 let WorkspaceResolve {
335 mut pkg_set,
336 workspace_resolve,
337 targeted_resolve: resolve,
338 resolved_features,
339 } = resolve;
340
341 let std_resolve_features = if let Some(crates) = &config.cli_unstable().build_std {
342 if build_config.build_plan {
343 config
344 .shell()
345 .warn("-Zbuild-std does not currently fully support --build-plan")?;
346 }
347 if build_config.requested_kind.is_host() {
348 anyhow::bail!("-Zbuild-std requires --target");
352 }
353 let (mut std_package_set, std_resolve, std_features) =
354 standard_lib::resolve_std(ws, &target_data, build_config.requested_kind, crates)?;
355 remove_dylib_crate_type(&mut std_package_set)?;
356 pkg_set.add_set(std_package_set);
357 Some((std_resolve, std_features))
358 } else {
359 None
360 };
361
362 let to_build_ids = specs
366 .iter()
367 .map(|s| s.query(resolve.iter()))
368 .collect::<CargoResult<Vec<_>>>()?;
369
370 let mut to_builds = pkg_set.get_many(to_build_ids)?;
374
375 to_builds.sort_by_key(|p| p.package_id());
379
380 for pkg in to_builds.iter() {
381 pkg.manifest().print_teapot(config);
382
383 if build_config.mode.is_any_test()
384 && !ws.is_member(pkg)
385 && pkg.dependencies().iter().any(|dep| !dep.is_transitive())
386 {
387 anyhow::bail!(
388 "package `{}` cannot be tested because it requires dev-dependencies \
389 and is not a member of the workspace",
390 pkg.name()
391 );
392 }
393 }
394
395 let (extra_args, extra_args_name) = match (target_rustc_args, target_rustdoc_args) {
396 (&Some(ref args), _) => (Some(args.clone()), "rustc"),
397 (_, &Some(ref args)) => (Some(args.clone()), "rustdoc"),
398 _ => (None, ""),
399 };
400
401 if extra_args.is_some() && to_builds.len() != 1 {
402 panic!(
403 "`{}` should not accept multiple `-p` flags",
404 extra_args_name
405 );
406 }
407
408 profiles.validate_packages(
409 ws.profiles(),
410 &mut config.shell(),
411 workspace_resolve.as_ref().unwrap_or(&resolve),
412 )?;
413
414 let interner = UnitInterner::new();
415 let mut bcx = BuildContext::new(
416 ws,
417 &pkg_set,
418 config,
419 build_config,
420 profiles,
421 &interner,
422 HashMap::new(),
423 target_data,
424 )?;
425
426 let units = generate_targets(
427 ws,
428 &to_builds,
429 filter,
430 build_config.requested_kind,
431 &resolve,
432 &resolved_features,
433 &bcx,
434 )?;
435
436 let std_roots = if let Some(crates) = &config.cli_unstable().build_std {
437 let mut crates = crates.clone();
439 if !crates.iter().any(|c| c == "test")
440 && units
441 .iter()
442 .any(|unit| unit.mode.is_rustc_test() && unit.target.harness())
443 {
444 if crates.iter().any(|c| c == "std") {
446 crates.push("test".to_string());
447 }
448 }
449 let (std_resolve, std_features) = std_resolve_features.as_ref().unwrap();
450 standard_lib::generate_std_roots(
451 &bcx,
452 &crates,
453 std_resolve,
454 std_features,
455 build_config.requested_kind,
456 )?
457 } else {
458 Vec::new()
459 };
460
461 if let Some(args) = extra_args {
462 if units.len() != 1 {
463 anyhow::bail!(
464 "extra arguments to `{}` can only be passed to one \
465 target, consider filtering\nthe package by passing, \
466 e.g., `--lib` or `--bin NAME` to specify a single target",
467 extra_args_name
468 );
469 }
470 bcx.extra_compiler_args.insert(units[0], args);
471 }
472 for unit in &units {
473 if unit.mode.is_doc() || unit.mode.is_doc_test() {
474 let mut extra_args = local_rustdoc_args.clone();
475
476 if rustdoc_document_private_items || unit.target.is_bin() {
480 let mut args = extra_args.take().unwrap_or_else(|| vec![]);
481 args.push("--document-private-items".into());
482 extra_args = Some(args);
483 }
484
485 if let Some(args) = extra_args {
486 bcx.extra_compiler_args.insert(*unit, args.clone());
487 }
488 }
489 }
490
491 let unit_dependencies = build_unit_dependencies(
492 &bcx,
493 &resolve,
494 &resolved_features,
495 std_resolve_features.as_ref(),
496 &units,
497 &std_roots,
498 )?;
499
500 if deps_only {
501 filter_roots(&bcx, ws, &unit_dependencies);
502 } else if deps_remote_only {
503 filter_locals(&bcx, &unit_dependencies);
504 }
505
506 if bcx.build_config.unit_graph {
507 unit_graph::emit_serialized_unit_graph(&units, &unit_dependencies)?;
508 return Ok(Compilation::new(&bcx, build_config.requested_kind)?);
509 }
510
511 let ret = {
512 let _p = profile::start("compiling");
513 let cx = Context::new(config, &bcx, unit_dependencies, build_config.requested_kind)?;
514 cx.compile(&units, export_dir.clone(), exec)?
515 };
516
517 Ok(ret)
518}
519
520impl FilterRule {
521 pub fn new(targets: Vec<String>, all: bool) -> FilterRule {
522 if all {
523 FilterRule::All
524 } else {
525 FilterRule::Just(targets)
526 }
527 }
528
529 pub fn none() -> FilterRule {
530 FilterRule::Just(Vec::new())
531 }
532
533 fn matches(&self, target: &Target) -> bool {
534 match *self {
535 FilterRule::All => true,
536 FilterRule::Just(ref targets) => targets.iter().any(|x| *x == target.name()),
537 }
538 }
539
540 fn is_specific(&self) -> bool {
541 match *self {
542 FilterRule::All => true,
543 FilterRule::Just(ref targets) => !targets.is_empty(),
544 }
545 }
546
547 pub fn try_collect(&self) -> Option<Vec<String>> {
548 match *self {
549 FilterRule::All => None,
550 FilterRule::Just(ref targets) => Some(targets.clone()),
551 }
552 }
553}
554
555impl CompileFilter {
556 pub fn from_raw_arguments(
558 lib_only: bool,
559 bins: Vec<String>,
560 all_bins: bool,
561 tsts: Vec<String>,
562 all_tsts: bool,
563 exms: Vec<String>,
564 all_exms: bool,
565 bens: Vec<String>,
566 all_bens: bool,
567 all_targets: bool,
568 ) -> CompileFilter {
569 if all_targets {
570 return CompileFilter::new_all_targets();
571 }
572 let rule_lib = if lib_only {
573 LibRule::True
574 } else {
575 LibRule::False
576 };
577 let rule_bins = FilterRule::new(bins, all_bins);
578 let rule_tsts = FilterRule::new(tsts, all_tsts);
579 let rule_exms = FilterRule::new(exms, all_exms);
580 let rule_bens = FilterRule::new(bens, all_bens);
581
582 CompileFilter::new(rule_lib, rule_bins, rule_tsts, rule_exms, rule_bens)
583 }
584
585 pub fn new(
587 rule_lib: LibRule,
588 rule_bins: FilterRule,
589 rule_tsts: FilterRule,
590 rule_exms: FilterRule,
591 rule_bens: FilterRule,
592 ) -> CompileFilter {
593 if rule_lib == LibRule::True
594 || rule_bins.is_specific()
595 || rule_tsts.is_specific()
596 || rule_exms.is_specific()
597 || rule_bens.is_specific()
598 {
599 CompileFilter::Only {
600 all_targets: false,
601 lib: rule_lib,
602 bins: rule_bins,
603 examples: rule_exms,
604 benches: rule_bens,
605 tests: rule_tsts,
606 }
607 } else {
608 CompileFilter::Default {
609 required_features_filterable: true,
610 }
611 }
612 }
613
614 pub fn new_all_targets() -> CompileFilter {
615 CompileFilter::Only {
616 all_targets: true,
617 lib: LibRule::Default,
618 bins: FilterRule::All,
619 examples: FilterRule::All,
620 benches: FilterRule::All,
621 tests: FilterRule::All,
622 }
623 }
624
625 pub fn need_dev_deps(&self, mode: CompileMode) -> bool {
626 match mode {
627 CompileMode::Test | CompileMode::Doctest | CompileMode::Bench => true,
628 CompileMode::Check { test: true } => true,
629 CompileMode::Build | CompileMode::Doc { .. } | CompileMode::Check { test: false } => {
630 match *self {
631 CompileFilter::Default { .. } => false,
632 CompileFilter::Only {
633 ref examples,
634 ref tests,
635 ref benches,
636 ..
637 } => examples.is_specific() || tests.is_specific() || benches.is_specific(),
638 }
639 }
640 CompileMode::RunCustomBuild => panic!("Invalid mode"),
641 }
642 }
643
644 pub fn target_run(&self, target: &Target) -> bool {
647 match *self {
648 CompileFilter::Default { .. } => true,
649 CompileFilter::Only {
650 ref lib,
651 ref bins,
652 ref examples,
653 ref tests,
654 ref benches,
655 ..
656 } => {
657 let rule = match *target.kind() {
658 TargetKind::Bin => bins,
659 TargetKind::Test => tests,
660 TargetKind::Bench => benches,
661 TargetKind::ExampleBin | TargetKind::ExampleLib(..) => examples,
662 TargetKind::Lib(..) => {
663 return match *lib {
664 LibRule::True => true,
665 LibRule::Default => true,
666 LibRule::False => false,
667 };
668 }
669 TargetKind::CustomBuild => return false,
670 };
671 rule.matches(target)
672 }
673 }
674 }
675
676 pub fn is_specific(&self) -> bool {
677 match *self {
678 CompileFilter::Default { .. } => false,
679 CompileFilter::Only { .. } => true,
680 }
681 }
682}
683
684#[derive(Debug)]
689struct Proposal<'a> {
690 pkg: &'a Package,
691 target: &'a Target,
692 requires_features: bool,
697 mode: CompileMode,
698}
699
700fn generate_targets<'a>(
703 ws: &Workspace<'_>,
704 packages: &[&'a Package],
705 filter: &CompileFilter,
706 default_arch_kind: CompileKind,
707 resolve: &'a Resolve,
708 resolved_features: &features::ResolvedFeatures,
709 bcx: &BuildContext<'a, '_>,
710) -> CargoResult<Vec<Unit<'a>>> {
711 let new_unit = |pkg: &'a Package, target: &'a Target, target_mode: CompileMode| {
713 let unit_for = if target_mode.is_any_test() {
714 UnitFor::new_test(bcx.config)
733 } else if target.for_host() {
734 UnitFor::new_compiler()
736 } else {
737 UnitFor::new_normal()
738 };
739 assert!(!target.is_custom_build());
741 let target_mode = match target_mode {
742 CompileMode::Test => {
743 if target.is_example() && !filter.is_specific() && !target.tested() {
744 CompileMode::Build
747 } else {
748 CompileMode::Test
749 }
750 }
751 CompileMode::Build => match *target.kind() {
752 TargetKind::Test => CompileMode::Test,
753 TargetKind::Bench => CompileMode::Bench,
754 _ => CompileMode::Build,
755 },
756 CompileMode::Bench => CompileMode::Test,
765 _ => target_mode,
766 };
767 let kind = default_arch_kind.for_target(target);
768 let profile =
769 bcx.profiles
770 .get_profile(pkg.package_id(), ws.is_member(pkg), unit_for, target_mode);
771
772 let features_for = if target.proc_macro() {
773 FeaturesFor::HostDep
774 } else {
775 FeaturesFor::NormalOrDev
777 };
778 let features =
779 Vec::from(resolved_features.activated_features(pkg.package_id(), features_for));
780 bcx.units.intern(
781 pkg,
782 target,
783 profile,
784 kind,
785 target_mode,
786 features,
787 false,
788 )
789 };
790
791 let mut proposals: Vec<Proposal<'_>> = Vec::new();
793
794 match *filter {
795 CompileFilter::Default {
796 required_features_filterable,
797 } => {
798 for pkg in packages {
799 let default = filter_default_targets(pkg.targets(), bcx.build_config.mode);
800 proposals.extend(default.into_iter().map(|target| Proposal {
801 pkg,
802 target,
803 requires_features: !required_features_filterable,
804 mode: bcx.build_config.mode,
805 }));
806 if bcx.build_config.mode == CompileMode::Test {
807 if let Some(t) = pkg
808 .targets()
809 .iter()
810 .find(|t| t.is_lib() && t.doctested() && t.doctestable())
811 {
812 proposals.push(Proposal {
813 pkg,
814 target: t,
815 requires_features: false,
816 mode: CompileMode::Doctest,
817 });
818 }
819 }
820 }
821 }
822 CompileFilter::Only {
823 all_targets,
824 ref lib,
825 ref bins,
826 ref examples,
827 ref tests,
828 ref benches,
829 } => {
830 if *lib != LibRule::False {
831 let mut libs = Vec::new();
832 for proposal in
833 filter_targets(packages, Target::is_lib, false, bcx.build_config.mode)
834 {
835 let Proposal { target, pkg, .. } = proposal;
836 if bcx.build_config.mode.is_doc_test() && !target.doctestable() {
837 ws.config().shell().warn(format!(
838 "doc tests are not supported for crate type(s) `{}` in package `{}`",
839 target.rustc_crate_types().join(", "),
840 pkg.name()
841 ))?;
842 } else {
843 libs.push(proposal)
844 }
845 }
846 if !all_targets && libs.is_empty() && *lib == LibRule::True {
847 let names = packages.iter().map(|pkg| pkg.name()).collect::<Vec<_>>();
848 if names.len() == 1 {
849 anyhow::bail!("no library targets found in package `{}`", names[0]);
850 } else {
851 anyhow::bail!("no library targets found in packages: {}", names.join(", "));
852 }
853 }
854 proposals.extend(libs);
855 }
856
857 let test_filter = match tests {
860 FilterRule::All => Target::tested,
861 FilterRule::Just(_) => Target::is_test,
862 };
863 let test_mode = match bcx.build_config.mode {
864 CompileMode::Build => CompileMode::Test,
865 CompileMode::Check { .. } => CompileMode::Check { test: true },
866 _ => bcx.build_config.mode,
867 };
868 let bench_filter = match benches {
871 FilterRule::All => Target::benched,
872 FilterRule::Just(_) => Target::is_bench,
873 };
874 let bench_mode = match bcx.build_config.mode {
875 CompileMode::Build => CompileMode::Bench,
876 CompileMode::Check { .. } => CompileMode::Check { test: true },
877 _ => bcx.build_config.mode,
878 };
879
880 proposals.extend(list_rule_targets(
881 packages,
882 bins,
883 "bin",
884 Target::is_bin,
885 bcx.build_config.mode,
886 )?);
887 proposals.extend(list_rule_targets(
888 packages,
889 examples,
890 "example",
891 Target::is_example,
892 bcx.build_config.mode,
893 )?);
894 proposals.extend(list_rule_targets(
895 packages,
896 tests,
897 "test",
898 test_filter,
899 test_mode,
900 )?);
901 proposals.extend(list_rule_targets(
902 packages,
903 benches,
904 "bench",
905 bench_filter,
906 bench_mode,
907 )?);
908 }
909 }
910
911 let mut features_map = HashMap::new();
918 let mut units = HashSet::new();
919 for Proposal {
920 pkg,
921 target,
922 requires_features,
923 mode,
924 } in proposals
925 {
926 let unavailable_features = match target.required_features() {
927 Some(rf) => {
928 let features = features_map.entry(pkg).or_insert_with(|| {
929 resolve_all_features(
930 resolve,
931 resolved_features,
932 &bcx.packages,
933 pkg.package_id(),
934 )
935 });
936 rf.iter().filter(|f| !features.contains(*f)).collect()
937 }
938 None => Vec::new(),
939 };
940 if target.is_lib() || unavailable_features.is_empty() {
941 let unit = new_unit(pkg, target, mode);
942 units.insert(unit);
943 } else if requires_features {
944 let required_features = target.required_features().unwrap();
945 let quoted_required_features: Vec<String> = required_features
946 .iter()
947 .map(|s| format!("`{}`", s))
948 .collect();
949 anyhow::bail!(
950 "target `{}` in package `{}` requires the features: {}\n\
951 Consider enabling them by passing, e.g., `--features=\"{}\"`",
952 target.name(),
953 pkg.name(),
954 quoted_required_features.join(", "),
955 required_features.join(" ")
956 );
957 }
958 }
960 Ok(units.into_iter().collect())
961}
962
963fn resolve_all_features(
969 resolve_with_overrides: &Resolve,
970 resolved_features: &features::ResolvedFeatures,
971 package_set: &PackageSet<'_>,
972 package_id: PackageId,
973) -> HashSet<String> {
974 let mut features: HashSet<String> = resolved_features
975 .activated_features(package_id, FeaturesFor::NormalOrDev)
976 .iter()
977 .map(|s| s.to_string())
978 .collect();
979
980 for (dep_id, deps) in resolve_with_overrides.deps(package_id) {
983 let is_proc_macro = package_set
984 .get_one(dep_id)
985 .expect("packages downloaded")
986 .proc_macro();
987 for dep in deps {
988 let features_for = if is_proc_macro || dep.is_build() {
989 FeaturesFor::HostDep
990 } else {
991 FeaturesFor::NormalOrDev
992 };
993 for feature in resolved_features.activated_features_unverified(dep_id, features_for) {
994 features.insert(format!("{}/{}", dep.name_in_toml(), feature));
995 }
996 }
997 }
998
999 features
1000}
1001
1002fn filter_default_targets(targets: &[Target], mode: CompileMode) -> Vec<&Target> {
1005 match mode {
1006 CompileMode::Bench => targets.iter().filter(|t| t.benched()).collect(),
1007 CompileMode::Test => targets
1008 .iter()
1009 .filter(|t| t.tested() || t.is_example())
1010 .collect(),
1011 CompileMode::Build | CompileMode::Check { .. } => targets
1012 .iter()
1013 .filter(|t| t.is_bin() || t.is_lib())
1014 .collect(),
1015 CompileMode::Doc { .. } => {
1016 targets
1018 .iter()
1019 .filter(|t| {
1020 t.documented()
1021 && (!t.is_bin()
1022 || !targets.iter().any(|l| l.is_lib() && l.name() == t.name()))
1023 })
1024 .collect()
1025 }
1026 CompileMode::Doctest | CompileMode::RunCustomBuild => panic!("Invalid mode {:?}", mode),
1027 }
1028}
1029
1030fn list_rule_targets<'a>(
1032 packages: &[&'a Package],
1033 rule: &FilterRule,
1034 target_desc: &'static str,
1035 is_expected_kind: fn(&Target) -> bool,
1036 mode: CompileMode,
1037) -> CargoResult<Vec<Proposal<'a>>> {
1038 let mut proposals = Vec::new();
1039 match rule {
1040 FilterRule::All => {
1041 proposals.extend(filter_targets(packages, is_expected_kind, false, mode))
1042 }
1043 FilterRule::Just(names) => {
1044 for name in names {
1045 proposals.extend(find_named_targets(
1046 packages,
1047 name,
1048 target_desc,
1049 is_expected_kind,
1050 mode,
1051 )?);
1052 }
1053 }
1054 }
1055 Ok(proposals)
1056}
1057
1058fn find_named_targets<'a>(
1060 packages: &[&'a Package],
1061 target_name: &str,
1062 target_desc: &'static str,
1063 is_expected_kind: fn(&Target) -> bool,
1064 mode: CompileMode,
1065) -> CargoResult<Vec<Proposal<'a>>> {
1066 let filter = |t: &Target| t.name() == target_name && is_expected_kind(t);
1067 let proposals = filter_targets(packages, filter, true, mode);
1068 if proposals.is_empty() {
1069 let targets = packages.iter().flat_map(|pkg| {
1070 pkg.targets()
1071 .iter()
1072 .filter(|target| is_expected_kind(target))
1073 });
1074 let suggestion = closest_msg(target_name, targets, |t| t.name());
1075 anyhow::bail!(
1076 "no {} target named `{}`{}",
1077 target_desc,
1078 target_name,
1079 suggestion
1080 );
1081 }
1082 Ok(proposals)
1083}
1084
1085fn filter_targets<'a>(
1086 packages: &[&'a Package],
1087 predicate: impl Fn(&Target) -> bool,
1088 requires_features: bool,
1089 mode: CompileMode,
1090) -> Vec<Proposal<'a>> {
1091 let mut proposals = Vec::new();
1092 for pkg in packages {
1093 for target in pkg.targets().iter().filter(|t| predicate(t)) {
1094 proposals.push(Proposal {
1095 pkg,
1096 target,
1097 requires_features,
1098 mode,
1099 });
1100 }
1101 }
1102 proposals
1103}
1104
1105fn remove_dylib_crate_type(set: &mut PackageSet<'_>) -> CargoResult<()> {
1117 let ids = set
1118 .package_ids()
1119 .filter(|p| p.source_id().is_path())
1120 .collect::<Vec<_>>();
1121 set.get_many(ids.iter().cloned())?;
1122
1123 for id in ids {
1124 let pkg = set.lookup_mut(id).expect("should be downloaded now");
1125
1126 for target in pkg.manifest_mut().targets_mut() {
1127 if let TargetKind::Lib(crate_types) = target.kind_mut() {
1128 crate_types.truncate(0);
1129 crate_types.push(LibKind::Rlib);
1130 }
1131 }
1132 }
1133
1134 Ok(())
1135}