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