1use std::collections::{HashMap, HashSet};
39use std::hash::{Hash, Hasher};
40use std::sync::Arc;
41
42use crate::core::compiler::UserIntent;
43use crate::core::compiler::unit_dependencies::build_unit_dependencies;
44use crate::core::compiler::unit_graph::{self, UnitDep, UnitGraph};
45use crate::core::compiler::{BuildConfig, BuildContext, BuildRunner, Compilation};
46use crate::core::compiler::{CompileKind, CompileTarget, RustcTargetData, Unit};
47use crate::core::compiler::{CrateType, TargetInfo, apply_env_config, standard_lib};
48use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner};
49use crate::core::profiles::Profiles;
50use crate::core::resolver::features::{self, CliFeatures, FeaturesFor};
51use crate::core::resolver::{HasDevUnits, Resolve};
52use crate::core::{PackageId, PackageSet, SourceId, TargetKind, Workspace};
53use crate::drop_println;
54use crate::ops;
55use crate::ops::resolve::{SpecsAndResolvedFeatures, WorkspaceResolve};
56use crate::util::context::{GlobalContext, WarningHandling};
57use crate::util::interning::InternedString;
58use crate::util::{CargoResult, StableHasher};
59
60mod compile_filter;
61pub use compile_filter::{CompileFilter, FilterRule, LibRule};
62
63pub(super) mod unit_generator;
64use unit_generator::UnitGenerator;
65
66mod packages;
67
68pub use packages::Packages;
69
70#[derive(Debug, Clone)]
79pub struct CompileOptions {
80 pub build_config: BuildConfig,
82 pub cli_features: CliFeatures,
84 pub spec: Packages,
86 pub filter: CompileFilter,
89 pub target_rustdoc_args: Option<Vec<String>>,
91 pub target_rustc_args: Option<Vec<String>>,
94 pub target_rustc_crate_types: Option<Vec<String>>,
96 pub rustdoc_document_private_items: bool,
99 pub honor_rust_version: Option<bool>,
102}
103
104impl CompileOptions {
105 pub fn new(gctx: &GlobalContext, intent: UserIntent) -> CargoResult<CompileOptions> {
106 let jobs = None;
107 let keep_going = false;
108 Ok(CompileOptions {
109 build_config: BuildConfig::new(gctx, jobs, keep_going, &[], intent)?,
110 cli_features: CliFeatures::new_all(false),
111 spec: ops::Packages::Packages(Vec::new()),
112 filter: CompileFilter::Default {
113 required_features_filterable: false,
114 },
115 target_rustdoc_args: None,
116 target_rustc_args: None,
117 target_rustc_crate_types: None,
118 rustdoc_document_private_items: false,
119 honor_rust_version: None,
120 })
121 }
122}
123
124pub fn compile<'a>(ws: &Workspace<'a>, options: &CompileOptions) -> CargoResult<Compilation<'a>> {
128 let exec: Arc<dyn Executor> = Arc::new(DefaultExecutor);
129 compile_with_exec(ws, options, &exec)
130}
131
132pub fn compile_with_exec<'a>(
137 ws: &Workspace<'a>,
138 options: &CompileOptions,
139 exec: &Arc<dyn Executor>,
140) -> CargoResult<Compilation<'a>> {
141 ws.emit_warnings()?;
142 let compilation = compile_ws(ws, options, exec)?;
143 if ws.gctx().warning_handling()? == WarningHandling::Deny && compilation.warning_count > 0 {
144 anyhow::bail!("warnings are denied by `build.warnings` configuration")
145 }
146 Ok(compilation)
147}
148
149#[tracing::instrument(skip_all)]
151pub fn compile_ws<'a>(
152 ws: &Workspace<'a>,
153 options: &CompileOptions,
154 exec: &Arc<dyn Executor>,
155) -> CargoResult<Compilation<'a>> {
156 let interner = UnitInterner::new();
157 let bcx = create_bcx(ws, options, &interner)?;
158 if options.build_config.unit_graph {
159 unit_graph::emit_serialized_unit_graph(&bcx.roots, &bcx.unit_graph, ws.gctx())?;
160 return Compilation::new(&bcx);
161 }
162 crate::core::gc::auto_gc(bcx.gctx);
163 let build_runner = BuildRunner::new(&bcx)?;
164 if options.build_config.dry_run {
165 build_runner.dry_run()
166 } else {
167 build_runner.compile(exec)
168 }
169}
170
171pub fn print<'a>(
175 ws: &Workspace<'a>,
176 options: &CompileOptions,
177 print_opt_value: &str,
178) -> CargoResult<()> {
179 let CompileOptions {
180 ref build_config,
181 ref target_rustc_args,
182 ..
183 } = *options;
184 let gctx = ws.gctx();
185 let rustc = gctx.load_global_rustc(Some(ws))?;
186 for (index, kind) in build_config.requested_kinds.iter().enumerate() {
187 if index != 0 {
188 drop_println!(gctx);
189 }
190 let target_info = TargetInfo::new(gctx, &build_config.requested_kinds, &rustc, *kind)?;
191 let mut process = rustc.process();
192 apply_env_config(gctx, &mut process)?;
193 process.args(&target_info.rustflags);
194 if let Some(args) = target_rustc_args {
195 process.args(args);
196 }
197 if let CompileKind::Target(t) = kind {
198 process.arg("--target").arg(t.rustc_target());
199 }
200 process.arg("--print").arg(print_opt_value);
201 process.exec()?;
202 }
203 Ok(())
204}
205
206#[tracing::instrument(skip_all)]
211pub fn create_bcx<'a, 'gctx>(
212 ws: &'a Workspace<'gctx>,
213 options: &'a CompileOptions,
214 interner: &'a UnitInterner,
215) -> CargoResult<BuildContext<'a, 'gctx>> {
216 let CompileOptions {
217 ref build_config,
218 ref spec,
219 ref cli_features,
220 ref filter,
221 ref target_rustdoc_args,
222 ref target_rustc_args,
223 ref target_rustc_crate_types,
224 rustdoc_document_private_items,
225 honor_rust_version,
226 } = *options;
227 let gctx = ws.gctx();
228
229 match build_config.intent {
231 UserIntent::Test | UserIntent::Build | UserIntent::Check { .. } | UserIntent::Bench => {
232 if ws.gctx().get_env("RUST_FLAGS").is_ok() {
233 gctx.shell()
234 .warn("ignoring environment variable `RUST_FLAGS`")?;
235 gctx.shell().note("rust flags are passed via `RUSTFLAGS`")?;
236 }
237 }
238 UserIntent::Doc { .. } | UserIntent::Doctest => {
239 if ws.gctx().get_env("RUSTDOC_FLAGS").is_ok() {
240 gctx.shell()
241 .warn("ignoring environment variable `RUSTDOC_FLAGS`")?;
242 gctx.shell()
243 .note("rustdoc flags are passed via `RUSTDOCFLAGS`")?;
244 }
245 }
246 }
247 gctx.validate_term_config()?;
248
249 let mut target_data = RustcTargetData::new(ws, &build_config.requested_kinds)?;
250
251 let specs = spec.to_package_id_specs(ws)?;
252 let has_dev_units = {
253 let any_pkg_has_scrape_enabled = ws
257 .members_with_features(&specs, cli_features)?
258 .iter()
259 .any(|(pkg, _)| {
260 pkg.targets()
261 .iter()
262 .any(|target| target.is_example() && target.doc_scrape_examples().is_enabled())
263 });
264
265 if filter.need_dev_deps(build_config.intent)
266 || (build_config.intent.is_doc() && any_pkg_has_scrape_enabled)
267 {
268 HasDevUnits::Yes
269 } else {
270 HasDevUnits::No
271 }
272 };
273 let dry_run = false;
274 let resolve = ops::resolve_ws_with_opts(
275 ws,
276 &mut target_data,
277 &build_config.requested_kinds,
278 cli_features,
279 &specs,
280 has_dev_units,
281 crate::core::resolver::features::ForceAllTargets::No,
282 dry_run,
283 )?;
284 let WorkspaceResolve {
285 mut pkg_set,
286 workspace_resolve,
287 targeted_resolve: resolve,
288 specs_and_features,
289 } = resolve;
290
291 let std_resolve_features = if let Some(crates) = &gctx.cli_unstable().build_std {
292 let (std_package_set, std_resolve, std_features) = standard_lib::resolve_std(
293 ws,
294 &mut target_data,
295 &build_config,
296 crates,
297 &build_config.requested_kinds,
298 )?;
299 pkg_set.add_set(std_package_set);
300 Some((std_resolve, std_features))
301 } else {
302 None
303 };
304
305 let to_build_ids = resolve.specs_to_ids(&specs)?;
309 let mut to_builds = pkg_set.get_many(to_build_ids)?;
313
314 to_builds.sort_by_key(|p| p.package_id());
318
319 for pkg in to_builds.iter() {
320 pkg.manifest().print_teapot(gctx);
321
322 if build_config.intent.is_any_test()
323 && !ws.is_member(pkg)
324 && pkg.dependencies().iter().any(|dep| !dep.is_transitive())
325 {
326 anyhow::bail!(
327 "package `{}` cannot be tested because it requires dev-dependencies \
328 and is not a member of the workspace",
329 pkg.name()
330 );
331 }
332 }
333
334 let (extra_args, extra_args_name) = match (target_rustc_args, target_rustdoc_args) {
335 (Some(args), _) => (Some(args.clone()), "rustc"),
336 (_, Some(args)) => (Some(args.clone()), "rustdoc"),
337 _ => (None, ""),
338 };
339
340 if extra_args.is_some() && to_builds.len() != 1 {
341 panic!(
342 "`{}` should not accept multiple `-p` flags",
343 extra_args_name
344 );
345 }
346
347 let profiles = Profiles::new(ws, build_config.requested_profile)?;
348 profiles.validate_packages(
349 ws.profiles(),
350 &mut gctx.shell(),
351 workspace_resolve.as_ref().unwrap_or(&resolve),
352 )?;
353
354 let explicit_host_kind = CompileKind::Target(CompileTarget::new(&target_data.rustc.host)?);
358 let explicit_host_kinds: Vec<_> = build_config
359 .requested_kinds
360 .iter()
361 .map(|kind| match kind {
362 CompileKind::Host => explicit_host_kind,
363 CompileKind::Target(t) => CompileKind::Target(*t),
364 })
365 .collect();
366
367 let mut units = Vec::new();
368 let mut unit_graph = HashMap::new();
369 let mut scrape_units = Vec::new();
370
371 for SpecsAndResolvedFeatures {
372 specs,
373 resolved_features,
374 } in &specs_and_features
375 {
376 let spec_names = specs.iter().map(|spec| spec.name()).collect::<Vec<_>>();
382 let packages = to_builds
383 .iter()
384 .filter(|package| spec_names.contains(&package.name().as_str()))
385 .cloned()
386 .collect::<Vec<_>>();
387 let generator = UnitGenerator {
388 ws,
389 packages: &packages,
390 spec,
391 target_data: &target_data,
392 filter,
393 requested_kinds: &build_config.requested_kinds,
394 explicit_host_kind,
395 intent: build_config.intent,
396 resolve: &resolve,
397 workspace_resolve: &workspace_resolve,
398 resolved_features: &resolved_features,
399 package_set: &pkg_set,
400 profiles: &profiles,
401 interner,
402 has_dev_units,
403 };
404 let mut targeted_root_units = generator.generate_root_units()?;
405
406 if let Some(args) = target_rustc_crate_types {
407 override_rustc_crate_types(&mut targeted_root_units, args, interner)?;
408 }
409
410 let should_scrape =
411 build_config.intent.is_doc() && gctx.cli_unstable().rustdoc_scrape_examples;
412 let targeted_scrape_units = if should_scrape {
413 generator.generate_scrape_units(&targeted_root_units)?
414 } else {
415 Vec::new()
416 };
417
418 let std_roots = if let Some(crates) = gctx.cli_unstable().build_std.as_ref() {
419 let (std_resolve, std_features) = std_resolve_features.as_ref().unwrap();
420 standard_lib::generate_std_roots(
421 &crates,
422 &targeted_root_units,
423 std_resolve,
424 std_features,
425 &explicit_host_kinds,
426 &pkg_set,
427 interner,
428 &profiles,
429 &target_data,
430 )?
431 } else {
432 Default::default()
433 };
434
435 unit_graph.extend(build_unit_dependencies(
436 ws,
437 &pkg_set,
438 &resolve,
439 &resolved_features,
440 std_resolve_features.as_ref(),
441 &targeted_root_units,
442 &targeted_scrape_units,
443 &std_roots,
444 build_config.intent,
445 &target_data,
446 &profiles,
447 interner,
448 )?);
449 units.extend(targeted_root_units);
450 scrape_units.extend(targeted_scrape_units);
451 }
452
453 if build_config.intent.wants_deps_docs() {
456 remove_duplicate_doc(build_config, &units, &mut unit_graph);
457 }
458
459 let host_kind_requested = build_config
460 .requested_kinds
461 .iter()
462 .any(CompileKind::is_host);
463 (units, scrape_units, unit_graph) = rebuild_unit_graph_shared(
467 interner,
468 unit_graph,
469 &units,
470 &scrape_units,
471 host_kind_requested.then_some(explicit_host_kind),
472 build_config.compile_time_deps_only,
473 );
474
475 let mut extra_compiler_args = HashMap::new();
476 if let Some(args) = extra_args {
477 if units.len() != 1 {
478 anyhow::bail!(
479 "extra arguments to `{}` can only be passed to one \
480 target, consider filtering\nthe package by passing, \
481 e.g., `--lib` or `--bin NAME` to specify a single target",
482 extra_args_name
483 );
484 }
485 extra_compiler_args.insert(units[0].clone(), args);
486 }
487
488 for unit in units
489 .iter()
490 .filter(|unit| unit.mode.is_doc() || unit.mode.is_doc_test())
491 .filter(|unit| rustdoc_document_private_items || unit.target.is_bin())
492 {
493 let mut args = vec!["--document-private-items".into()];
497 if unit.target.is_bin() {
498 args.push("-Arustdoc::private-intra-doc-links".into());
502 }
503 extra_compiler_args
504 .entry(unit.clone())
505 .or_default()
506 .extend(args);
507 }
508
509 if honor_rust_version.unwrap_or(true) {
510 let rustc_version = target_data.rustc.version.clone().into();
511
512 let mut incompatible = Vec::new();
513 let mut local_incompatible = false;
514 for unit in unit_graph.keys() {
515 let Some(pkg_msrv) = unit.pkg.rust_version() else {
516 continue;
517 };
518
519 if pkg_msrv.is_compatible_with(&rustc_version) {
520 continue;
521 }
522
523 local_incompatible |= unit.is_local();
524 incompatible.push((unit, pkg_msrv));
525 }
526 if !incompatible.is_empty() {
527 use std::fmt::Write as _;
528
529 let plural = if incompatible.len() == 1 { "" } else { "s" };
530 let mut message = format!(
531 "rustc {rustc_version} is not supported by the following package{plural}:\n"
532 );
533 incompatible.sort_by_key(|(unit, _)| (unit.pkg.name(), unit.pkg.version()));
534 for (unit, msrv) in incompatible {
535 let name = &unit.pkg.name();
536 let version = &unit.pkg.version();
537 writeln!(&mut message, " {name}@{version} requires rustc {msrv}").unwrap();
538 }
539 if ws.is_ephemeral() {
540 if ws.ignore_lock() {
541 writeln!(
542 &mut message,
543 "Try re-running `cargo install` with `--locked`"
544 )
545 .unwrap();
546 }
547 } else if !local_incompatible {
548 writeln!(
549 &mut message,
550 "Either upgrade rustc or select compatible dependency versions with
551`cargo update <name>@<current-ver> --precise <compatible-ver>`
552where `<compatible-ver>` is the latest version supporting rustc {rustc_version}",
553 )
554 .unwrap();
555 }
556 return Err(anyhow::Error::msg(message));
557 }
558 }
559
560 let bcx = BuildContext::new(
561 ws,
562 pkg_set,
563 build_config,
564 profiles,
565 extra_compiler_args,
566 target_data,
567 units,
568 unit_graph,
569 scrape_units,
570 )?;
571
572 Ok(bcx)
573}
574
575fn rebuild_unit_graph_shared(
610 interner: &UnitInterner,
611 unit_graph: UnitGraph,
612 roots: &[Unit],
613 scrape_units: &[Unit],
614 to_host: Option<CompileKind>,
615 compile_time_deps_only: bool,
616) -> (Vec<Unit>, Vec<Unit>, UnitGraph) {
617 let mut result = UnitGraph::new();
618 let mut memo = HashMap::new();
621 let new_roots = roots
622 .iter()
623 .map(|root| {
624 traverse_and_share(
625 interner,
626 &mut memo,
627 &mut result,
628 &unit_graph,
629 root,
630 true,
631 false,
632 to_host,
633 compile_time_deps_only,
634 )
635 })
636 .collect();
637 let new_scrape_units = scrape_units
641 .iter()
642 .map(|unit| memo.get(unit).unwrap().clone())
643 .collect();
644 (new_roots, new_scrape_units, result)
645}
646
647fn traverse_and_share(
653 interner: &UnitInterner,
654 memo: &mut HashMap<Unit, Unit>,
655 new_graph: &mut UnitGraph,
656 unit_graph: &UnitGraph,
657 unit: &Unit,
658 unit_is_root: bool,
659 unit_is_for_host: bool,
660 to_host: Option<CompileKind>,
661 compile_time_deps_only: bool,
662) -> Unit {
663 if let Some(new_unit) = memo.get(unit) {
664 return new_unit.clone();
666 }
667 let mut dep_hash = StableHasher::new();
668 let skip_non_compile_time_deps = compile_time_deps_only
669 && (!unit.target.is_compile_time_dependency() ||
670 unit_is_root);
673 let new_deps: Vec<_> = unit_graph[unit]
674 .iter()
675 .map(|dep| {
676 let new_dep_unit = traverse_and_share(
677 interner,
678 memo,
679 new_graph,
680 unit_graph,
681 &dep.unit,
682 false,
683 dep.unit_for.is_for_host(),
684 to_host,
685 skip_non_compile_time_deps,
689 );
690 new_dep_unit.hash(&mut dep_hash);
691 UnitDep {
692 unit: new_dep_unit,
693 ..dep.clone()
694 }
695 })
696 .collect();
697 let new_dep_hash = Hasher::finish(&dep_hash);
700
701 let canonical_kind = match to_host {
708 Some(to_host) if to_host == unit.kind => CompileKind::Host,
709 _ => unit.kind,
710 };
711
712 let mut profile = unit.profile.clone();
713 if profile.strip.is_deferred() {
714 if !profile.debuginfo.is_turned_on()
718 && new_deps
719 .iter()
720 .all(|dep| !dep.unit.profile.debuginfo.is_turned_on())
721 {
722 profile.strip = profile.strip.strip_debuginfo();
723 }
724 }
725
726 if unit_is_for_host
730 && to_host.is_some()
731 && profile.debuginfo.is_deferred()
732 && !unit.artifact.is_true()
733 {
734 let canonical_debuginfo = profile.debuginfo.finalize();
738 let mut canonical_profile = profile.clone();
739 canonical_profile.debuginfo = canonical_debuginfo;
740 let unit_probe = interner.intern(
741 &unit.pkg,
742 &unit.target,
743 canonical_profile,
744 to_host.unwrap(),
745 unit.mode,
746 unit.features.clone(),
747 unit.rustflags.clone(),
748 unit.rustdocflags.clone(),
749 unit.links_overrides.clone(),
750 unit.is_std,
751 unit.dep_hash,
752 unit.artifact,
753 unit.artifact_target_for_features,
754 unit.skip_non_compile_time_dep,
755 );
756
757 profile.debuginfo = if unit_graph.contains_key(&unit_probe) {
759 canonical_debuginfo
762 } else {
763 canonical_debuginfo.weaken()
766 }
767 }
768
769 let new_unit = interner.intern(
770 &unit.pkg,
771 &unit.target,
772 profile,
773 canonical_kind,
774 unit.mode,
775 unit.features.clone(),
776 unit.rustflags.clone(),
777 unit.rustdocflags.clone(),
778 unit.links_overrides.clone(),
779 unit.is_std,
780 new_dep_hash,
781 unit.artifact,
782 None,
785 skip_non_compile_time_deps,
786 );
787 if !unit_is_root || !compile_time_deps_only {
788 assert!(memo.insert(unit.clone(), new_unit.clone()).is_none());
789 }
790 new_graph.entry(new_unit.clone()).or_insert(new_deps);
791 new_unit
792}
793
794fn remove_duplicate_doc(
810 build_config: &BuildConfig,
811 root_units: &[Unit],
812 unit_graph: &mut UnitGraph,
813) {
814 let mut all_docs: HashMap<String, Vec<Unit>> = HashMap::new();
817 for unit in unit_graph.keys() {
818 if unit.mode.is_doc() {
819 all_docs
820 .entry(unit.target.crate_name())
821 .or_default()
822 .push(unit.clone());
823 }
824 }
825 let mut removed_units: HashSet<Unit> = HashSet::new();
828 let mut remove = |units: Vec<Unit>, reason: &str, cb: &dyn Fn(&Unit) -> bool| -> Vec<Unit> {
829 let (to_remove, remaining_units): (Vec<Unit>, Vec<Unit>) = units
830 .into_iter()
831 .partition(|unit| cb(unit) && !root_units.contains(unit));
832 for unit in to_remove {
833 tracing::debug!(
834 "removing duplicate doc due to {} for package {} target `{}`",
835 reason,
836 unit.pkg,
837 unit.target.name()
838 );
839 unit_graph.remove(&unit);
840 removed_units.insert(unit);
841 }
842 remaining_units
843 };
844 for (_crate_name, mut units) in all_docs {
846 if units.len() == 1 {
847 continue;
848 }
849 if build_config
851 .requested_kinds
852 .iter()
853 .all(CompileKind::is_host)
854 {
855 units = remove(units, "host/target merger", &|unit| unit.kind.is_host());
860 if units.len() == 1 {
861 continue;
862 }
863 }
864 let mut source_map: HashMap<(InternedString, SourceId, CompileKind), Vec<Unit>> =
866 HashMap::new();
867 for unit in units {
868 let pkg_id = unit.pkg.package_id();
869 source_map
871 .entry((pkg_id.name(), pkg_id.source_id(), unit.kind))
872 .or_default()
873 .push(unit);
874 }
875 let mut remaining_units = Vec::new();
876 for (_key, mut units) in source_map {
877 if units.len() > 1 {
878 units.sort_by(|a, b| a.pkg.version().partial_cmp(b.pkg.version()).unwrap());
879 let newest_version = units.last().unwrap().pkg.version().clone();
881 let keep_units = remove(units, "older version", &|unit| {
882 unit.pkg.version() < &newest_version
883 });
884 remaining_units.extend(keep_units);
885 } else {
886 remaining_units.extend(units);
887 }
888 }
889 if remaining_units.len() == 1 {
890 continue;
891 }
892 }
895 for unit_deps in unit_graph.values_mut() {
897 unit_deps.retain(|unit_dep| !removed_units.contains(&unit_dep.unit));
898 }
899 let mut visited = HashSet::new();
901 fn visit(unit: &Unit, graph: &UnitGraph, visited: &mut HashSet<Unit>) {
902 if !visited.insert(unit.clone()) {
903 return;
904 }
905 for dep in &graph[unit] {
906 visit(&dep.unit, graph, visited);
907 }
908 }
909 for unit in root_units {
910 visit(unit, unit_graph, &mut visited);
911 }
912 unit_graph.retain(|unit, _| visited.contains(unit));
913}
914
915fn override_rustc_crate_types(
919 units: &mut [Unit],
920 args: &[String],
921 interner: &UnitInterner,
922) -> CargoResult<()> {
923 if units.len() != 1 {
924 anyhow::bail!(
925 "crate types to rustc can only be passed to one \
926 target, consider filtering\nthe package by passing, \
927 e.g., `--lib` or `--example` to specify a single target"
928 );
929 }
930
931 let unit = &units[0];
932 let override_unit = |f: fn(Vec<CrateType>) -> TargetKind| {
933 let crate_types = args.iter().map(|s| s.into()).collect();
934 let mut target = unit.target.clone();
935 target.set_kind(f(crate_types));
936 interner.intern(
937 &unit.pkg,
938 &target,
939 unit.profile.clone(),
940 unit.kind,
941 unit.mode,
942 unit.features.clone(),
943 unit.rustflags.clone(),
944 unit.rustdocflags.clone(),
945 unit.links_overrides.clone(),
946 unit.is_std,
947 unit.dep_hash,
948 unit.artifact,
949 unit.artifact_target_for_features,
950 unit.skip_non_compile_time_dep,
951 )
952 };
953 units[0] = match unit.target.kind() {
954 TargetKind::Lib(_) => override_unit(TargetKind::Lib),
955 TargetKind::ExampleLib(_) => override_unit(TargetKind::ExampleLib),
956 _ => {
957 anyhow::bail!(
958 "crate types can only be specified for libraries and example libraries.\n\
959 Binaries, tests, and benchmarks are always the `bin` crate type"
960 );
961 }
962 };
963
964 Ok(())
965}
966
967pub fn resolve_all_features(
973 resolve_with_overrides: &Resolve,
974 resolved_features: &features::ResolvedFeatures,
975 package_set: &PackageSet<'_>,
976 package_id: PackageId,
977) -> HashSet<String> {
978 let mut features: HashSet<String> = resolved_features
979 .activated_features(package_id, FeaturesFor::NormalOrDev)
980 .iter()
981 .map(|s| s.to_string())
982 .collect();
983
984 for (dep_id, deps) in resolve_with_overrides.deps(package_id) {
987 let is_proc_macro = package_set
988 .get_one(dep_id)
989 .expect("packages downloaded")
990 .proc_macro();
991 for dep in deps {
992 let features_for = FeaturesFor::from_for_host(is_proc_macro || dep.is_build());
993 for feature in resolved_features
994 .activated_features_unverified(dep_id, features_for)
995 .unwrap_or_default()
996 {
997 features.insert(format!("{}/{}", dep.name_in_toml(), feature));
998 }
999 }
1000 }
1001
1002 features
1003}