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::BuildLogger;
57use crate::util::context::{GlobalContext, WarningHandling};
58use crate::util::interning::InternedString;
59use crate::util::log_message::LogMessage;
60use crate::util::{CargoResult, StableHasher};
61
62mod compile_filter;
63use annotate_snippets::Level;
64pub use compile_filter::{CompileFilter, FilterRule, LibRule};
65
66pub(super) mod unit_generator;
67use unit_generator::UnitGenerator;
68
69mod packages;
70
71pub use packages::Packages;
72
73#[derive(Debug, Clone)]
82pub struct CompileOptions {
83 pub build_config: BuildConfig,
85 pub cli_features: CliFeatures,
87 pub spec: Packages,
89 pub filter: CompileFilter,
92 pub target_rustdoc_args: Option<Vec<String>>,
94 pub target_rustc_args: Option<Vec<String>>,
97 pub target_rustc_crate_types: Option<Vec<String>>,
99 pub rustdoc_document_private_items: bool,
102 pub honor_rust_version: Option<bool>,
105}
106
107impl CompileOptions {
108 pub fn new(gctx: &GlobalContext, intent: UserIntent) -> CargoResult<CompileOptions> {
109 let jobs = None;
110 let keep_going = false;
111 Ok(CompileOptions {
112 build_config: BuildConfig::new(gctx, jobs, keep_going, &[], intent)?,
113 cli_features: CliFeatures::new_all(false),
114 spec: ops::Packages::Packages(Vec::new()),
115 filter: CompileFilter::Default {
116 required_features_filterable: false,
117 },
118 target_rustdoc_args: None,
119 target_rustc_args: None,
120 target_rustc_crate_types: None,
121 rustdoc_document_private_items: false,
122 honor_rust_version: None,
123 })
124 }
125}
126
127pub fn compile<'a>(ws: &Workspace<'a>, options: &CompileOptions) -> CargoResult<Compilation<'a>> {
131 let exec: Arc<dyn Executor> = Arc::new(DefaultExecutor);
132 compile_with_exec(ws, options, &exec)
133}
134
135pub fn compile_with_exec<'a>(
140 ws: &Workspace<'a>,
141 options: &CompileOptions,
142 exec: &Arc<dyn Executor>,
143) -> CargoResult<Compilation<'a>> {
144 ws.emit_warnings()?;
145 let compilation = compile_ws(ws, options, exec)?;
146 if ws.gctx().warning_handling()? == WarningHandling::Deny && compilation.lint_warning_count > 0
147 {
148 anyhow::bail!("warnings are denied by `build.warnings` configuration")
149 }
150 Ok(compilation)
151}
152
153#[tracing::instrument(skip_all)]
155pub fn compile_ws<'a>(
156 ws: &Workspace<'a>,
157 options: &CompileOptions,
158 exec: &Arc<dyn Executor>,
159) -> CargoResult<Compilation<'a>> {
160 let interner = UnitInterner::new();
161 let logger = BuildLogger::maybe_new(ws)?;
162
163 if let Some(ref logger) = logger {
164 let rustc = ws.gctx().load_global_rustc(Some(ws))?;
165 logger.log(LogMessage::BuildStarted {
166 cwd: ws.gctx().cwd().to_path_buf(),
167 host: rustc.host.to_string(),
168 jobs: options.build_config.jobs,
169 profile: options.build_config.requested_profile.to_string(),
170 rustc_version: rustc.version.to_string(),
171 rustc_version_verbose: rustc.verbose_version.clone(),
172 target_dir: ws.target_dir().as_path_unlocked().to_path_buf(),
173 workspace_root: ws.root().to_path_buf(),
174 });
175 }
176
177 let bcx = create_bcx(ws, options, &interner, logger.as_ref())?;
178
179 if options.build_config.unit_graph {
180 unit_graph::emit_serialized_unit_graph(&bcx.roots, &bcx.unit_graph, ws.gctx())?;
181 return Compilation::new(&bcx);
182 }
183 crate::core::gc::auto_gc(bcx.gctx);
184 let build_runner = BuildRunner::new(&bcx)?;
185 if options.build_config.dry_run {
186 build_runner.dry_run()
187 } else {
188 build_runner.compile(exec)
189 }
190}
191
192pub fn print<'a>(
196 ws: &Workspace<'a>,
197 options: &CompileOptions,
198 print_opt_value: &str,
199) -> CargoResult<()> {
200 let CompileOptions {
201 ref build_config,
202 ref target_rustc_args,
203 ..
204 } = *options;
205 let gctx = ws.gctx();
206 let rustc = gctx.load_global_rustc(Some(ws))?;
207 for (index, kind) in build_config.requested_kinds.iter().enumerate() {
208 if index != 0 {
209 drop_println!(gctx);
210 }
211 let target_info = TargetInfo::new(gctx, &build_config.requested_kinds, &rustc, *kind)?;
212 let mut process = rustc.process();
213 apply_env_config(gctx, &mut process)?;
214 process.args(&target_info.rustflags);
215 if let Some(args) = target_rustc_args {
216 process.args(args);
217 }
218 if let CompileKind::Target(t) = kind {
219 process.arg("--target").arg(t.rustc_target());
220 }
221 process.arg("--print").arg(print_opt_value);
222 process.exec()?;
223 }
224 Ok(())
225}
226
227#[tracing::instrument(skip_all)]
232pub fn create_bcx<'a, 'gctx>(
233 ws: &'a Workspace<'gctx>,
234 options: &'a CompileOptions,
235 interner: &'a UnitInterner,
236 logger: Option<&'a BuildLogger>,
237) -> CargoResult<BuildContext<'a, 'gctx>> {
238 let CompileOptions {
239 ref build_config,
240 ref spec,
241 ref cli_features,
242 ref filter,
243 ref target_rustdoc_args,
244 ref target_rustc_args,
245 ref target_rustc_crate_types,
246 rustdoc_document_private_items,
247 honor_rust_version,
248 } = *options;
249 let gctx = ws.gctx();
250
251 match build_config.intent {
253 UserIntent::Test | UserIntent::Build | UserIntent::Check { .. } | UserIntent::Bench => {
254 if ws.gctx().get_env("RUST_FLAGS").is_ok() {
255 gctx.shell().print_report(
256 &[Level::WARNING
257 .secondary_title("ignoring environment variable `RUST_FLAGS`")
258 .element(Level::HELP.message("rust flags are passed via `RUSTFLAGS`"))],
259 false,
260 )?;
261 }
262 }
263 UserIntent::Doc { .. } | UserIntent::Doctest => {
264 if ws.gctx().get_env("RUSTDOC_FLAGS").is_ok() {
265 gctx.shell().print_report(
266 &[Level::WARNING
267 .secondary_title("ignoring environment variable `RUSTDOC_FLAGS`")
268 .element(
269 Level::HELP.message("rustdoc flags are passed via `RUSTDOCFLAGS`"),
270 )],
271 false,
272 )?;
273 }
274 }
275 }
276 gctx.validate_term_config()?;
277
278 let mut target_data = RustcTargetData::new(ws, &build_config.requested_kinds)?;
279
280 let specs = spec.to_package_id_specs(ws)?;
281 let has_dev_units = {
282 let any_pkg_has_scrape_enabled = ws
286 .members_with_features(&specs, cli_features)?
287 .iter()
288 .any(|(pkg, _)| {
289 pkg.targets()
290 .iter()
291 .any(|target| target.is_example() && target.doc_scrape_examples().is_enabled())
292 });
293
294 if filter.need_dev_deps(build_config.intent)
295 || (build_config.intent.is_doc() && any_pkg_has_scrape_enabled)
296 {
297 HasDevUnits::Yes
298 } else {
299 HasDevUnits::No
300 }
301 };
302 let dry_run = false;
303 let resolve = ops::resolve_ws_with_opts(
304 ws,
305 &mut target_data,
306 &build_config.requested_kinds,
307 cli_features,
308 &specs,
309 has_dev_units,
310 crate::core::resolver::features::ForceAllTargets::No,
311 dry_run,
312 )?;
313 let WorkspaceResolve {
314 mut pkg_set,
315 workspace_resolve,
316 targeted_resolve: resolve,
317 specs_and_features,
318 } = resolve;
319
320 let std_resolve_features = if let Some(crates) = &gctx.cli_unstable().build_std {
321 let (std_package_set, std_resolve, std_features) = standard_lib::resolve_std(
322 ws,
323 &mut target_data,
324 &build_config,
325 crates,
326 &build_config.requested_kinds,
327 )?;
328 pkg_set.add_set(std_package_set);
329 Some((std_resolve, std_features))
330 } else {
331 None
332 };
333
334 let to_build_ids = resolve.specs_to_ids(&specs)?;
338 let mut to_builds = pkg_set.get_many(to_build_ids)?;
342
343 to_builds.sort_by_key(|p| p.package_id());
347
348 for pkg in to_builds.iter() {
349 pkg.manifest().print_teapot(gctx);
350
351 if build_config.intent.is_any_test()
352 && !ws.is_member(pkg)
353 && pkg.dependencies().iter().any(|dep| !dep.is_transitive())
354 {
355 anyhow::bail!(
356 "package `{}` cannot be tested because it requires dev-dependencies \
357 and is not a member of the workspace",
358 pkg.name()
359 );
360 }
361 }
362
363 let (extra_args, extra_args_name) = match (target_rustc_args, target_rustdoc_args) {
364 (Some(args), _) => (Some(args.clone()), "rustc"),
365 (_, Some(args)) => (Some(args.clone()), "rustdoc"),
366 _ => (None, ""),
367 };
368
369 if extra_args.is_some() && to_builds.len() != 1 {
370 panic!(
371 "`{}` should not accept multiple `-p` flags",
372 extra_args_name
373 );
374 }
375
376 let profiles = Profiles::new(ws, build_config.requested_profile)?;
377 profiles.validate_packages(
378 ws.profiles(),
379 &mut gctx.shell(),
380 workspace_resolve.as_ref().unwrap_or(&resolve),
381 )?;
382
383 let explicit_host_kind = CompileKind::Target(CompileTarget::new(&target_data.rustc.host)?);
387 let explicit_host_kinds: Vec<_> = build_config
388 .requested_kinds
389 .iter()
390 .map(|kind| match kind {
391 CompileKind::Host => explicit_host_kind,
392 CompileKind::Target(t) => CompileKind::Target(*t),
393 })
394 .collect();
395
396 let mut units = Vec::new();
397 let mut unit_graph = HashMap::new();
398 let mut scrape_units = Vec::new();
399
400 for SpecsAndResolvedFeatures {
401 specs,
402 resolved_features,
403 } in &specs_and_features
404 {
405 let spec_names = specs.iter().map(|spec| spec.name()).collect::<Vec<_>>();
411 let packages = to_builds
412 .iter()
413 .filter(|package| spec_names.contains(&package.name().as_str()))
414 .cloned()
415 .collect::<Vec<_>>();
416 let generator = UnitGenerator {
417 ws,
418 packages: &packages,
419 spec,
420 target_data: &target_data,
421 filter,
422 requested_kinds: &build_config.requested_kinds,
423 explicit_host_kind,
424 intent: build_config.intent,
425 resolve: &resolve,
426 workspace_resolve: &workspace_resolve,
427 resolved_features: &resolved_features,
428 package_set: &pkg_set,
429 profiles: &profiles,
430 interner,
431 has_dev_units,
432 };
433 let mut targeted_root_units = generator.generate_root_units()?;
434
435 if let Some(args) = target_rustc_crate_types {
436 override_rustc_crate_types(&mut targeted_root_units, args, interner)?;
437 }
438
439 let should_scrape =
440 build_config.intent.is_doc() && gctx.cli_unstable().rustdoc_scrape_examples;
441 let targeted_scrape_units = if should_scrape {
442 generator.generate_scrape_units(&targeted_root_units)?
443 } else {
444 Vec::new()
445 };
446
447 let std_roots = if let Some(crates) = gctx.cli_unstable().build_std.as_ref() {
448 let (std_resolve, std_features) = std_resolve_features.as_ref().unwrap();
449 standard_lib::generate_std_roots(
450 &crates,
451 &targeted_root_units,
452 std_resolve,
453 std_features,
454 &explicit_host_kinds,
455 &pkg_set,
456 interner,
457 &profiles,
458 &target_data,
459 )?
460 } else {
461 Default::default()
462 };
463
464 unit_graph.extend(build_unit_dependencies(
465 ws,
466 &pkg_set,
467 &resolve,
468 &resolved_features,
469 std_resolve_features.as_ref(),
470 &targeted_root_units,
471 &targeted_scrape_units,
472 &std_roots,
473 build_config.intent,
474 &target_data,
475 &profiles,
476 interner,
477 )?);
478 units.extend(targeted_root_units);
479 scrape_units.extend(targeted_scrape_units);
480 }
481
482 if build_config.intent.wants_deps_docs() {
485 remove_duplicate_doc(build_config, &units, &mut unit_graph);
486 }
487
488 let host_kind_requested = build_config
489 .requested_kinds
490 .iter()
491 .any(CompileKind::is_host);
492 (units, scrape_units, unit_graph) = rebuild_unit_graph_shared(
496 interner,
497 unit_graph,
498 &units,
499 &scrape_units,
500 host_kind_requested.then_some(explicit_host_kind),
501 build_config.compile_time_deps_only,
502 );
503
504 let mut extra_compiler_args = HashMap::new();
505 if let Some(args) = extra_args {
506 if units.len() != 1 {
507 anyhow::bail!(
508 "extra arguments to `{}` can only be passed to one \
509 target, consider filtering\nthe package by passing, \
510 e.g., `--lib` or `--bin NAME` to specify a single target",
511 extra_args_name
512 );
513 }
514 extra_compiler_args.insert(units[0].clone(), args);
515 }
516
517 for unit in units
518 .iter()
519 .filter(|unit| unit.mode.is_doc() || unit.mode.is_doc_test())
520 .filter(|unit| rustdoc_document_private_items || unit.target.is_bin())
521 {
522 let mut args = vec!["--document-private-items".into()];
526 if unit.target.is_bin() {
527 args.push("-Arustdoc::private-intra-doc-links".into());
531 }
532 extra_compiler_args
533 .entry(unit.clone())
534 .or_default()
535 .extend(args);
536 }
537
538 if honor_rust_version.unwrap_or(true) {
539 let rustc_version = target_data.rustc.version.clone().into();
540
541 let mut incompatible = Vec::new();
542 let mut local_incompatible = false;
543 for unit in unit_graph.keys() {
544 let Some(pkg_msrv) = unit.pkg.rust_version() else {
545 continue;
546 };
547
548 if pkg_msrv.is_compatible_with(&rustc_version) {
549 continue;
550 }
551
552 local_incompatible |= unit.is_local();
553 incompatible.push((unit, pkg_msrv));
554 }
555 if !incompatible.is_empty() {
556 use std::fmt::Write as _;
557
558 let plural = if incompatible.len() == 1 { "" } else { "s" };
559 let mut message = format!(
560 "rustc {rustc_version} is not supported by the following package{plural}:\n"
561 );
562 incompatible.sort_by_key(|(unit, _)| (unit.pkg.name(), unit.pkg.version()));
563 for (unit, msrv) in incompatible {
564 let name = &unit.pkg.name();
565 let version = &unit.pkg.version();
566 writeln!(&mut message, " {name}@{version} requires rustc {msrv}").unwrap();
567 }
568 if ws.is_ephemeral() {
569 if ws.ignore_lock() {
570 writeln!(
571 &mut message,
572 "Try re-running `cargo install` with `--locked`"
573 )
574 .unwrap();
575 }
576 } else if !local_incompatible {
577 writeln!(
578 &mut message,
579 "Either upgrade rustc or select compatible dependency versions with
580`cargo update <name>@<current-ver> --precise <compatible-ver>`
581where `<compatible-ver>` is the latest version supporting rustc {rustc_version}",
582 )
583 .unwrap();
584 }
585 return Err(anyhow::Error::msg(message));
586 }
587 }
588
589 let bcx = BuildContext::new(
590 ws,
591 logger,
592 pkg_set,
593 build_config,
594 profiles,
595 extra_compiler_args,
596 target_data,
597 units,
598 unit_graph,
599 scrape_units,
600 )?;
601
602 Ok(bcx)
603}
604
605fn rebuild_unit_graph_shared(
640 interner: &UnitInterner,
641 unit_graph: UnitGraph,
642 roots: &[Unit],
643 scrape_units: &[Unit],
644 to_host: Option<CompileKind>,
645 compile_time_deps_only: bool,
646) -> (Vec<Unit>, Vec<Unit>, UnitGraph) {
647 let mut result = UnitGraph::new();
648 let mut memo = HashMap::new();
651 let new_roots = roots
652 .iter()
653 .map(|root| {
654 traverse_and_share(
655 interner,
656 &mut memo,
657 &mut result,
658 &unit_graph,
659 root,
660 true,
661 false,
662 to_host,
663 compile_time_deps_only,
664 )
665 })
666 .collect();
667 let new_scrape_units = scrape_units
671 .iter()
672 .map(|unit| memo.get(unit).unwrap().clone())
673 .collect();
674 (new_roots, new_scrape_units, result)
675}
676
677fn traverse_and_share(
683 interner: &UnitInterner,
684 memo: &mut HashMap<Unit, Unit>,
685 new_graph: &mut UnitGraph,
686 unit_graph: &UnitGraph,
687 unit: &Unit,
688 unit_is_root: bool,
689 unit_is_for_host: bool,
690 to_host: Option<CompileKind>,
691 compile_time_deps_only: bool,
692) -> Unit {
693 if let Some(new_unit) = memo.get(unit) {
694 return new_unit.clone();
696 }
697 let mut dep_hash = StableHasher::new();
698 let skip_non_compile_time_deps = compile_time_deps_only
699 && (!unit.target.is_compile_time_dependency() ||
700 unit_is_root);
703 let new_deps: Vec<_> = unit_graph[unit]
704 .iter()
705 .map(|dep| {
706 let new_dep_unit = traverse_and_share(
707 interner,
708 memo,
709 new_graph,
710 unit_graph,
711 &dep.unit,
712 false,
713 dep.unit_for.is_for_host(),
714 to_host,
715 skip_non_compile_time_deps,
719 );
720 new_dep_unit.hash(&mut dep_hash);
721 UnitDep {
722 unit: new_dep_unit,
723 ..dep.clone()
724 }
725 })
726 .collect();
727 let new_dep_hash = Hasher::finish(&dep_hash);
730
731 let canonical_kind = match to_host {
738 Some(to_host) if to_host == unit.kind => CompileKind::Host,
739 _ => unit.kind,
740 };
741
742 let mut profile = unit.profile.clone();
743 if profile.strip.is_deferred() {
744 if !profile.debuginfo.is_turned_on()
748 && new_deps
749 .iter()
750 .all(|dep| !dep.unit.profile.debuginfo.is_turned_on())
751 {
752 profile.strip = profile.strip.strip_debuginfo();
753 }
754 }
755
756 if unit_is_for_host
760 && to_host.is_some()
761 && profile.debuginfo.is_deferred()
762 && !unit.artifact.is_true()
763 {
764 let canonical_debuginfo = profile.debuginfo.finalize();
768 let mut canonical_profile = profile.clone();
769 canonical_profile.debuginfo = canonical_debuginfo;
770 let unit_probe = interner.intern(
771 &unit.pkg,
772 &unit.target,
773 canonical_profile,
774 to_host.unwrap(),
775 unit.mode,
776 unit.features.clone(),
777 unit.rustflags.clone(),
778 unit.rustdocflags.clone(),
779 unit.links_overrides.clone(),
780 unit.is_std,
781 unit.dep_hash,
782 unit.artifact,
783 unit.artifact_target_for_features,
784 unit.skip_non_compile_time_dep,
785 );
786
787 profile.debuginfo = if unit_graph.contains_key(&unit_probe) {
789 canonical_debuginfo
792 } else {
793 canonical_debuginfo.weaken()
796 }
797 }
798
799 let new_unit = interner.intern(
800 &unit.pkg,
801 &unit.target,
802 profile,
803 canonical_kind,
804 unit.mode,
805 unit.features.clone(),
806 unit.rustflags.clone(),
807 unit.rustdocflags.clone(),
808 unit.links_overrides.clone(),
809 unit.is_std,
810 new_dep_hash,
811 unit.artifact,
812 None,
815 skip_non_compile_time_deps,
816 );
817 if !unit_is_root || !compile_time_deps_only {
818 assert!(memo.insert(unit.clone(), new_unit.clone()).is_none());
819 }
820 new_graph.entry(new_unit.clone()).or_insert(new_deps);
821 new_unit
822}
823
824fn remove_duplicate_doc(
840 build_config: &BuildConfig,
841 root_units: &[Unit],
842 unit_graph: &mut UnitGraph,
843) {
844 let mut all_docs: HashMap<String, Vec<Unit>> = HashMap::new();
847 for unit in unit_graph.keys() {
848 if unit.mode.is_doc() {
849 all_docs
850 .entry(unit.target.crate_name())
851 .or_default()
852 .push(unit.clone());
853 }
854 }
855 let mut removed_units: HashSet<Unit> = HashSet::new();
858 let mut remove = |units: Vec<Unit>, reason: &str, cb: &dyn Fn(&Unit) -> bool| -> Vec<Unit> {
859 let (to_remove, remaining_units): (Vec<Unit>, Vec<Unit>) = units
860 .into_iter()
861 .partition(|unit| cb(unit) && !root_units.contains(unit));
862 for unit in to_remove {
863 tracing::debug!(
864 "removing duplicate doc due to {} for package {} target `{}`",
865 reason,
866 unit.pkg,
867 unit.target.name()
868 );
869 unit_graph.remove(&unit);
870 removed_units.insert(unit);
871 }
872 remaining_units
873 };
874 for (_crate_name, mut units) in all_docs {
876 if units.len() == 1 {
877 continue;
878 }
879 if build_config
881 .requested_kinds
882 .iter()
883 .all(CompileKind::is_host)
884 {
885 units = remove(units, "host/target merger", &|unit| unit.kind.is_host());
890 if units.len() == 1 {
891 continue;
892 }
893 }
894 let mut source_map: HashMap<(InternedString, SourceId, CompileKind), Vec<Unit>> =
896 HashMap::new();
897 for unit in units {
898 let pkg_id = unit.pkg.package_id();
899 source_map
901 .entry((pkg_id.name(), pkg_id.source_id(), unit.kind))
902 .or_default()
903 .push(unit);
904 }
905 let mut remaining_units = Vec::new();
906 for (_key, mut units) in source_map {
907 if units.len() > 1 {
908 units.sort_by(|a, b| a.pkg.version().partial_cmp(b.pkg.version()).unwrap());
909 let newest_version = units.last().unwrap().pkg.version().clone();
911 let keep_units = remove(units, "older version", &|unit| {
912 unit.pkg.version() < &newest_version
913 });
914 remaining_units.extend(keep_units);
915 } else {
916 remaining_units.extend(units);
917 }
918 }
919 if remaining_units.len() == 1 {
920 continue;
921 }
922 }
925 for unit_deps in unit_graph.values_mut() {
927 unit_deps.retain(|unit_dep| !removed_units.contains(&unit_dep.unit));
928 }
929 let mut visited = HashSet::new();
931 fn visit(unit: &Unit, graph: &UnitGraph, visited: &mut HashSet<Unit>) {
932 if !visited.insert(unit.clone()) {
933 return;
934 }
935 for dep in &graph[unit] {
936 visit(&dep.unit, graph, visited);
937 }
938 }
939 for unit in root_units {
940 visit(unit, unit_graph, &mut visited);
941 }
942 unit_graph.retain(|unit, _| visited.contains(unit));
943}
944
945fn override_rustc_crate_types(
949 units: &mut [Unit],
950 args: &[String],
951 interner: &UnitInterner,
952) -> CargoResult<()> {
953 if units.len() != 1 {
954 anyhow::bail!(
955 "crate types to rustc can only be passed to one \
956 target, consider filtering\nthe package by passing, \
957 e.g., `--lib` or `--example` to specify a single target"
958 );
959 }
960
961 let unit = &units[0];
962 let override_unit = |f: fn(Vec<CrateType>) -> TargetKind| {
963 let crate_types = args.iter().map(|s| s.into()).collect();
964 let mut target = unit.target.clone();
965 target.set_kind(f(crate_types));
966 interner.intern(
967 &unit.pkg,
968 &target,
969 unit.profile.clone(),
970 unit.kind,
971 unit.mode,
972 unit.features.clone(),
973 unit.rustflags.clone(),
974 unit.rustdocflags.clone(),
975 unit.links_overrides.clone(),
976 unit.is_std,
977 unit.dep_hash,
978 unit.artifact,
979 unit.artifact_target_for_features,
980 unit.skip_non_compile_time_dep,
981 )
982 };
983 units[0] = match unit.target.kind() {
984 TargetKind::Lib(_) => override_unit(TargetKind::Lib),
985 TargetKind::ExampleLib(_) => override_unit(TargetKind::ExampleLib),
986 _ => {
987 anyhow::bail!(
988 "crate types can only be specified for libraries and example libraries.\n\
989 Binaries, tests, and benchmarks are always the `bin` crate type"
990 );
991 }
992 };
993
994 Ok(())
995}
996
997pub fn resolve_all_features(
1003 resolve_with_overrides: &Resolve,
1004 resolved_features: &features::ResolvedFeatures,
1005 package_set: &PackageSet<'_>,
1006 package_id: PackageId,
1007) -> HashSet<String> {
1008 let mut features: HashSet<String> = resolved_features
1009 .activated_features(package_id, FeaturesFor::NormalOrDev)
1010 .iter()
1011 .map(|s| s.to_string())
1012 .collect();
1013
1014 for (dep_id, deps) in resolve_with_overrides.deps(package_id) {
1017 let is_proc_macro = package_set
1018 .get_one(dep_id)
1019 .expect("packages downloaded")
1020 .proc_macro();
1021 for dep in deps {
1022 let features_for = FeaturesFor::from_for_host(is_proc_macro || dep.is_build());
1023 for feature in resolved_features
1024 .activated_features_unverified(dep_id, features_for)
1025 .unwrap_or_default()
1026 {
1027 features.insert(format!("{}/{}", dep.name_in_toml(), feature));
1028 }
1029 }
1030 }
1031
1032 features
1033}