1pub mod artifact;
32mod build_config;
33pub(crate) mod build_context;
34pub(crate) mod build_runner;
35mod compilation;
36mod compile_kind;
37mod crate_type;
38mod custom_build;
39pub(crate) mod fingerprint;
40pub mod future_incompat;
41pub(crate) mod job_queue;
42pub(crate) mod layout;
43mod links;
44mod locking;
45mod lto;
46mod output_depinfo;
47mod output_sbom;
48pub mod rustdoc;
49pub mod standard_lib;
50pub mod timings;
51pub(crate) mod trim_paths;
52mod unit;
53pub mod unit_dependencies;
54pub mod unit_graph;
55pub mod unused_deps;
56
57use crate::util::data_structures::{HashMap, HashSet};
58use std::borrow::Cow;
59use std::cell::OnceCell;
60use std::env;
61use std::ffi::{OsStr, OsString};
62use std::fmt::Display;
63use std::fs::{self, File};
64use std::io::{BufRead, BufWriter, Write};
65use std::ops::{Deref, Range};
66use std::path::{Path, PathBuf};
67use std::sync::{Arc, LazyLock};
68
69use anyhow::{Context as _, Error};
70use cargo_platform::{Cfg, Platform};
71use cargo_util_terminal::report::{AnnotationKind, Group, Level, Renderer, Snippet};
72use regex::Regex;
73use tracing::{debug, instrument, trace};
74
75pub use self::build_config::UserIntent;
76pub use self::build_config::{BuildConfig, CompileMode, MessageFormat};
77pub use self::build_context::BuildContext;
78pub use self::build_context::DepKindSet;
79pub use self::build_context::FileFlavor;
80pub use self::build_context::FileType;
81pub use self::build_context::RustcTargetData;
82pub use self::build_context::TargetInfo;
83pub use self::build_runner::{BuildRunner, Metadata, UnitHash};
84pub use self::compilation::{Compilation, Doctest, UnitOutput};
85pub use self::compile_kind::{CompileKind, CompileKindFallback, CompileTarget};
86pub use self::crate_type::CrateType;
87pub use self::custom_build::LinkArgTarget;
88pub use self::custom_build::{BuildOutput, BuildScriptOutputs, BuildScripts, LibraryPath};
89pub(crate) use self::fingerprint::DirtyReason;
90pub use self::fingerprint::RustdocFingerprint;
91pub use self::job_queue::Freshness;
92use self::job_queue::{Job, JobQueue, JobState, Work};
93pub(crate) use self::layout::Layout;
94pub use self::lto::Lto;
95use self::output_depinfo::output_depinfo;
96use self::output_sbom::build_sbom;
97use self::trim_paths::trim_paths_args;
98use self::trim_paths::trim_paths_args_rustdoc;
99use self::unit_graph::UnitDep;
100
101use crate::compiler::future_incompat::FutureIncompatReport;
102use crate::compiler::locking::LockKey;
103use crate::compiler::timings::SectionTiming;
104pub use crate::compiler::unit::Unit;
105pub use crate::compiler::unit::UnitIndex;
106pub use crate::compiler::unit::UnitInterner;
107use crate::context::FingerprintMethod;
108use crate::diagnostics::get_key_value;
109use crate::util::OnceExt;
110use crate::util::errors::{CargoResult, VerboseError};
111use crate::util::interning::InternedString;
112use crate::util::machine_message::{self, Message};
113use crate::util::{add_path_args, internal, path_args};
114use crate::workspace::Feature;
115use crate::workspace::PackageId;
116use crate::workspace::Target;
117use crate::workspace::TargetKind;
118use crate::workspace::manifest::TargetSourcePath;
119use crate::workspace::profiles::{PanicStrategy, Profile, StripInner};
120
121use cargo_util::{ProcessBuilder, ProcessError, paths};
122use cargo_util_schemas::manifest::TomlDebugInfo;
123use cargo_util_terminal::Verbosity;
124use rustfix::diagnostics::Applicability;
125
126const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version";
127
128pub trait Executor: Send + Sync + 'static {
132 fn init(&self, _build_runner: &BuildRunner<'_, '_>, _unit: &Unit) {}
136
137 fn exec(
140 &self,
141 cmd: &ProcessBuilder,
142 id: PackageId,
143 target: &Target,
144 mode: CompileMode,
145 on_stdout_line: &mut dyn FnMut(&str) -> CargoResult<()>,
146 on_stderr_line: &mut dyn FnMut(&str) -> CargoResult<()>,
147 ) -> CargoResult<()>;
148
149 fn force_rebuild(&self, _unit: &Unit) -> bool {
152 false
153 }
154}
155
156#[derive(Copy, Clone)]
159pub struct DefaultExecutor;
160
161impl Executor for DefaultExecutor {
162 #[instrument(name = "rustc", skip_all, fields(package = id.name().as_str(), process = cmd.to_string()))]
163 fn exec(
164 &self,
165 cmd: &ProcessBuilder,
166 id: PackageId,
167 _target: &Target,
168 _mode: CompileMode,
169 on_stdout_line: &mut dyn FnMut(&str) -> CargoResult<()>,
170 on_stderr_line: &mut dyn FnMut(&str) -> CargoResult<()>,
171 ) -> CargoResult<()> {
172 cmd.exec_with_streaming(on_stdout_line, on_stderr_line, false)
173 .map(drop)
174 }
175}
176
177#[tracing::instrument(skip(build_runner, jobs, exec))]
187fn compile<'gctx>(
188 build_runner: &mut BuildRunner<'_, 'gctx>,
189 jobs: &mut JobQueue<'gctx>,
190 unit: &Unit,
191 exec: &Arc<dyn Executor>,
192 force_rebuild: bool,
193) -> CargoResult<()> {
194 if !build_runner.compiled.insert(unit.clone()) {
195 return Ok(());
196 }
197
198 let lock = if build_runner.bcx.gctx.cli_unstable().fine_grain_locking {
199 Some(build_runner.lock_manager.lock_shared(build_runner, unit)?)
200 } else {
201 None
202 };
203
204 match build_runner
205 .bcx
206 .gctx
207 .build_config()?
208 .fingerprint
209 .unwrap_or_default()
210 {
211 FingerprintMethod::Content => {
212 if !build_runner.bcx.gctx.cli_unstable().checksum_freshness {
213 build_runner.bcx.gctx.shell().warn(
214 r#"ignoring `build.fingerprint = "content"` without `-Zchecksum-freshness`"#,
215 )?;
216 }
217 }
218 FingerprintMethod::Mtime => {}
219 }
220
221 if !unit.skip_non_compile_time_dep {
225 fingerprint::prepare_init(build_runner, unit)?;
228
229 let job = if unit.mode.is_run_custom_build() {
230 custom_build::prepare(build_runner, unit)?
231 } else if unit.mode.is_doc_test() {
232 Job::new_fresh()
234 } else {
235 let force = exec.force_rebuild(unit) || force_rebuild;
236 let mut job = fingerprint::prepare_target(build_runner, unit, force)?;
237 job.before(if job.freshness().is_dirty() {
238 let work = if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
239 rustdoc(build_runner, unit)?
240 } else {
241 rustc(build_runner, unit, exec)?
242 };
243 work.then(link_targets(build_runner, unit, false)?)
244 } else {
245 let output_options = OutputOptions::for_fresh(build_runner, unit);
246 let manifest = ManifestErrorContext::new(build_runner, unit);
247 let work = replay_output_cache(
248 unit.pkg.package_id(),
249 manifest,
250 &unit.target,
251 build_runner.files().message_cache_path(unit),
252 output_options,
253 );
254 work.then(link_targets(build_runner, unit, true)?)
256 });
257
258 if build_runner.bcx.gctx.cli_unstable().fine_grain_locking && job.freshness().is_dirty()
261 {
262 if let Some(lock) = lock {
263 build_runner.lock_manager.unlock(&lock)?;
270 job.before(prebuild_lock_exclusive(lock.clone()));
271 job.after(downgrade_lock_to_shared(lock));
272 }
273 }
274
275 job
276 };
277 jobs.enqueue(build_runner, unit, job)?;
278 }
279
280 let deps = Vec::from(build_runner.unit_deps(unit)); for dep in deps {
283 compile(build_runner, jobs, &dep.unit, exec, false)?;
284 }
285
286 Ok(())
287}
288
289fn make_failed_scrape_diagnostic(
292 build_runner: &BuildRunner<'_, '_>,
293 unit: &Unit,
294 top_line: impl Display,
295) -> String {
296 let manifest_path = unit.pkg.manifest_path();
297 let relative_manifest_path = manifest_path
298 .strip_prefix(build_runner.bcx.ws.root())
299 .unwrap_or(&manifest_path);
300
301 format!(
302 "\
303{top_line}
304 Try running with `--verbose` to see the error message.
305 If an example should not be scanned, then consider adding `doc-scrape-examples = false` to its `[[example]]` definition in {}",
306 relative_manifest_path.display()
307 )
308}
309
310#[tracing::instrument(skip_all)]
312fn rustc(
313 build_runner: &mut BuildRunner<'_, '_>,
314 unit: &Unit,
315 exec: &Arc<dyn Executor>,
316) -> CargoResult<Work> {
317 let mut rustc = prepare_rustc(build_runner, unit)?;
318
319 let name = unit.pkg.name();
320
321 let outputs = build_runner.outputs(unit)?;
322 let root = build_runner.files().output_dir(unit);
323
324 let build_script_outputs = Arc::clone(&build_runner.build_script_outputs);
326 let current_id = unit.pkg.package_id();
327 let manifest = ManifestErrorContext::new(build_runner, unit);
328 let build_scripts = build_runner.build_scripts.get(unit).cloned();
329
330 let pass_l_flag = unit.target.is_lib() || !unit.pkg.targets().iter().any(|t| t.is_lib());
333
334 let dep_info_name =
335 if let Some(c_extra_filename) = build_runner.files().metadata(unit).c_extra_filename() {
336 format!("{}-{}.d", unit.target.crate_name(), c_extra_filename)
337 } else {
338 format!("{}.d", unit.target.crate_name())
339 };
340 let rustc_dep_info_loc = root.join(dep_info_name);
341 let dep_info_loc = fingerprint::dep_info_loc(build_runner, unit);
342
343 let mut output_options = OutputOptions::for_dirty(build_runner, unit);
344 let package_id = unit.pkg.package_id();
345 let target = Target::clone(&unit.target);
346 let mode = unit.mode;
347
348 exec.init(build_runner, unit);
349 let exec = exec.clone();
350
351 let root_output = build_runner.files().host_dest().map(|v| v.to_path_buf());
352 let build_dir = build_runner.bcx.ws.build_dir().into_path_unlocked();
353 let pkg_root = unit.pkg.root().to_path_buf();
354 let cwd = rustc
355 .get_cwd()
356 .unwrap_or_else(|| build_runner.bcx.gctx.cwd())
357 .to_path_buf();
358 let fingerprint_dir = build_runner.files().fingerprint_dir(unit);
359 let script_metadatas = build_runner.find_build_script_metadatas(unit);
360 let is_local = unit.is_local();
361 let artifact = unit.artifact;
362 let sbom_files = build_runner.sbom_output_files(unit)?;
363 let sbom = if !sbom_files.is_empty() {
364 Some(build_sbom(build_runner, unit)?)
365 } else {
366 None
367 };
368
369 let unremap_files = build_runner.unremap_output_files(unit)?;
370 let unremap_content = if unremap_files.is_empty() {
371 None
372 } else {
373 let mut buf = Vec::new();
374 trim_paths::write_unremap_file(&mut buf, build_runner, unit)?;
375 Some(buf)
376 };
377
378 let hide_diagnostics_for_scrape_unit = build_runner.bcx.unit_can_fail_for_docscraping(unit)
379 && !matches!(
380 build_runner.bcx.gctx.shell().verbosity(),
381 Verbosity::Verbose
382 );
383 let failed_scrape_diagnostic = hide_diagnostics_for_scrape_unit.then(|| {
384 let target_desc = unit.target.description_named();
387 let mut for_scrape_units = build_runner
388 .bcx
389 .scrape_units_have_dep_on(unit)
390 .into_iter()
391 .map(|unit| unit.target.description_named())
392 .collect::<Vec<_>>();
393 for_scrape_units.sort();
394 let for_scrape_units = for_scrape_units.join(", ");
395 make_failed_scrape_diagnostic(build_runner, unit, format_args!("failed to check {target_desc} in package `{name}` as a prerequisite for scraping examples from: {for_scrape_units}"))
396 });
397 if hide_diagnostics_for_scrape_unit {
398 output_options.show_diagnostics = false;
399 }
400 let env_config = Arc::clone(build_runner.bcx.gctx.env_config()?);
401 return Ok(Work::new(move |state| {
402 if artifact.is_true() {
406 paths::create_dir_all(&root)?;
407 }
408
409 if let Some(build_scripts) = build_scripts {
417 let script_outputs = build_script_outputs.lock().unwrap();
418 add_native_deps(
419 &mut rustc,
420 &script_outputs,
421 &build_scripts,
422 pass_l_flag,
423 &target,
424 current_id,
425 mode,
426 )?;
427 if let Some(ref root_output) = root_output {
428 add_plugin_deps(&mut rustc, &script_outputs, &build_scripts, root_output)?;
429 }
430 add_custom_flags(&mut rustc, &script_outputs, script_metadatas)?;
431 }
432
433 for output in outputs.iter() {
434 if output.path.extension() == Some(OsStr::new("rmeta")) {
438 let dst = root.join(&output.path).with_extension("rlib");
439 if dst.exists() {
440 paths::remove_file(&dst)?;
441 }
442 }
443
444 if output.hardlink.is_some() && output.path.exists() {
449 _ = paths::remove_file(&output.path).map_err(|e| {
450 tracing::debug!(
451 "failed to delete previous output file `{:?}`: {e:?}",
452 output.path
453 );
454 });
455 }
456 }
457
458 state.running(&rustc);
459 let timestamp = paths::set_invocation_time(&fingerprint_dir)?;
460 if let Some(sbom) = sbom {
461 for file in sbom_files {
462 tracing::debug!("writing sbom to {}", file.display());
463 let outfile = BufWriter::new(paths::create(&file)?);
464 serde_json::to_writer(outfile, &sbom)?;
465 }
466 }
467
468 if let Some(content) = &unremap_content {
469 for file in &unremap_files {
470 tracing::debug!("writing unremap file to {}", file.display());
471 paths::write_atomic(file, content)?;
472 }
473 }
474
475 let result = exec
476 .exec(
477 &rustc,
478 package_id,
479 &target,
480 mode,
481 &mut |line| on_stdout_line(state, line, package_id, &target),
482 &mut |line| {
483 on_stderr_line(
484 state,
485 line,
486 package_id,
487 &manifest,
488 &target,
489 &mut output_options,
490 )
491 },
492 )
493 .map_err(|e| {
494 if output_options.errors_seen == 0 {
495 e
500 } else {
501 verbose_if_simple_exit_code(e)
502 }
503 })
504 .with_context(|| {
505 let warnings = match output_options.warnings_seen {
507 0 => String::new(),
508 1 => "; 1 warning emitted".to_string(),
509 count => format!("; {} warnings emitted", count),
510 };
511 let errors = match output_options.errors_seen {
512 0 => String::new(),
513 1 => " due to 1 previous error".to_string(),
514 count => format!(" due to {} previous errors", count),
515 };
516 let name = descriptive_pkg_name(&name, &target, &mode);
517 format!("could not compile {name}{errors}{warnings}")
518 });
519
520 if let Err(e) = result {
521 if let Some(diagnostic) = failed_scrape_diagnostic {
522 state.warning(diagnostic);
523 }
524
525 return Err(e);
526 }
527
528 debug_assert_eq!(output_options.errors_seen, 0);
530
531 if rustc_dep_info_loc.exists() {
532 fingerprint::translate_dep_info(
533 &rustc_dep_info_loc,
534 &dep_info_loc,
535 &cwd,
536 &pkg_root,
537 &build_dir,
538 &rustc,
539 is_local,
541 &env_config,
542 )
543 .with_context(|| {
544 internal(format!(
545 "could not parse/generate dep info at: {}",
546 rustc_dep_info_loc.display()
547 ))
548 })?;
549 paths::set_file_time_no_err(dep_info_loc, timestamp);
552 }
553
554 if mode.is_check() {
568 for output in outputs.iter() {
569 paths::set_file_time_no_err(&output.path, timestamp);
570 }
571 }
572
573 Ok(())
574 }));
575
576 fn add_native_deps(
579 rustc: &mut ProcessBuilder,
580 build_script_outputs: &BuildScriptOutputs,
581 build_scripts: &BuildScripts,
582 pass_l_flag: bool,
583 target: &Target,
584 current_id: PackageId,
585 mode: CompileMode,
586 ) -> CargoResult<()> {
587 let mut library_paths = vec![];
588
589 for key in build_scripts.to_link.iter() {
590 let output = build_script_outputs.get(key.1).ok_or_else(|| {
591 internal(format!(
592 "couldn't find build script output for {}/{}",
593 key.0, key.1
594 ))
595 })?;
596 library_paths.extend(output.library_paths.iter());
597 }
598
599 library_paths.sort_by_key(|p| match p {
605 LibraryPath::CargoArtifact(_) => 0,
606 LibraryPath::External(_) => 1,
607 });
608
609 for path in library_paths.iter() {
610 rustc.arg("-L").arg(path.as_ref());
611 }
612
613 for key in build_scripts.to_link.iter() {
614 let output = build_script_outputs.get(key.1).ok_or_else(|| {
615 internal(format!(
616 "couldn't find build script output for {}/{}",
617 key.0, key.1
618 ))
619 })?;
620
621 if key.0 == current_id {
622 if pass_l_flag {
623 for name in output.library_links.iter() {
624 rustc.arg("-l").arg(name);
625 }
626 }
627 }
628
629 for (lt, arg) in &output.linker_args {
630 if lt.applies_to(target, mode)
636 && (key.0 == current_id || *lt == LinkArgTarget::Cdylib)
637 {
638 rustc.arg("-C").arg(format!("link-arg={}", arg));
639 }
640 }
641 }
642 Ok(())
643 }
644}
645
646fn verbose_if_simple_exit_code(err: Error) -> Error {
647 match err
650 .downcast_ref::<ProcessError>()
651 .as_ref()
652 .and_then(|perr| perr.code)
653 {
654 Some(n) if cargo_util::is_simple_exit_code(n) => VerboseError::new(err).into(),
655 _ => err,
656 }
657}
658
659fn prebuild_lock_exclusive(lock: LockKey) -> Work {
660 Work::new(move |state| {
661 state.lock_exclusive(&lock)?;
662 Ok(())
663 })
664}
665
666fn downgrade_lock_to_shared(lock: LockKey) -> Work {
667 Work::new(move |state| {
668 state.downgrade_to_shared(&lock)?;
669 Ok(())
670 })
671}
672
673fn link_targets(
676 build_runner: &mut BuildRunner<'_, '_>,
677 unit: &Unit,
678 fresh: bool,
679) -> CargoResult<Work> {
680 let bcx = build_runner.bcx;
681 let outputs = build_runner.outputs(unit)?;
682 let export_dir = build_runner.files().export_dir();
683 let package_id = unit.pkg.package_id();
684 let manifest_path = PathBuf::from(unit.pkg.manifest_path());
685 let profile = unit.profile.clone();
686 let unit_mode = unit.mode;
687 let features = unit.features.iter().map(|s| s.to_string()).collect();
688 let json_messages = bcx.build_config.emit_json();
689 let executable = build_runner.get_executable(unit)?;
690 let mut target = Target::clone(&unit.target);
691 if let TargetSourcePath::Metabuild = target.src_path() {
692 let path = unit
694 .pkg
695 .manifest()
696 .metabuild_path(build_runner.bcx.ws.build_dir());
697 target.set_src_path(TargetSourcePath::Path(path));
698 }
699
700 Ok(Work::new(move |state| {
701 let mut destinations = vec![];
706 for output in outputs.iter() {
707 let src = &output.path;
708 if !src.exists() {
711 continue;
712 }
713 let Some(dst) = output.hardlink.as_ref() else {
714 destinations.push(src.clone());
715 continue;
716 };
717 destinations.push(dst.clone());
718 paths::link_or_copy(src, dst)?;
719 if let Some(ref path) = output.export_path {
720 let export_dir = export_dir.as_ref().unwrap();
721 paths::create_dir_all(export_dir)?;
722
723 paths::link_or_copy(src, path)?;
724 }
725 }
726
727 if json_messages {
728 let debuginfo = match profile.debuginfo.into_inner() {
729 TomlDebugInfo::None => machine_message::ArtifactDebuginfo::Int(0),
730 TomlDebugInfo::Limited => machine_message::ArtifactDebuginfo::Int(1),
731 TomlDebugInfo::Full => machine_message::ArtifactDebuginfo::Int(2),
732 TomlDebugInfo::LineDirectivesOnly => {
733 machine_message::ArtifactDebuginfo::Named("line-directives-only")
734 }
735 TomlDebugInfo::LineTablesOnly => {
736 machine_message::ArtifactDebuginfo::Named("line-tables-only")
737 }
738 };
739 let art_profile = machine_message::ArtifactProfile {
740 opt_level: profile.opt_level.as_str(),
741 debuginfo: Some(debuginfo),
742 debug_assertions: profile.debug_assertions,
743 overflow_checks: profile.overflow_checks,
744 test: unit_mode.is_any_test(),
745 };
746
747 let msg = machine_message::Artifact {
748 package_id: package_id.to_spec(),
749 manifest_path,
750 target: &target,
751 profile: art_profile,
752 features,
753 filenames: destinations,
754 executable,
755 fresh,
756 }
757 .to_json_string();
758 state.stdout(msg)?;
759 }
760 Ok(())
761 }))
762}
763
764fn add_plugin_deps(
768 rustc: &mut ProcessBuilder,
769 build_script_outputs: &BuildScriptOutputs,
770 build_scripts: &BuildScripts,
771 root_output: &Path,
772) -> CargoResult<()> {
773 let var = paths::dylib_path_envvar();
774 let search_path = rustc.get_env(var).unwrap_or_default();
775 let mut search_path = env::split_paths(&search_path).collect::<Vec<_>>();
776 for (pkg_id, metadata) in &build_scripts.plugins {
777 let output = build_script_outputs
778 .get(*metadata)
779 .ok_or_else(|| internal(format!("couldn't find libs for plugin dep {}", pkg_id)))?;
780 search_path.append(&mut filter_dynamic_search_path(
781 output.library_paths.iter().map(AsRef::as_ref),
782 root_output,
783 ));
784 }
785 let search_path = paths::join_paths(&search_path, var)?;
786 rustc.env(var, &search_path);
787 Ok(())
788}
789
790fn get_dynamic_search_path(path: &Path) -> &Path {
791 match path.to_str().and_then(|s| s.split_once("=")) {
792 Some(("native" | "crate" | "dependency" | "framework" | "all", path)) => Path::new(path),
793 _ => path,
794 }
795}
796
797fn filter_dynamic_search_path<'a, I>(paths: I, root_output: &Path) -> Vec<PathBuf>
803where
804 I: Iterator<Item = &'a PathBuf>,
805{
806 let mut search_path = vec![];
807 for dir in paths {
808 let dir = get_dynamic_search_path(dir);
809 if dir.starts_with(&root_output) {
810 search_path.push(dir.to_path_buf());
811 } else {
812 debug!(
813 "Not including path {} in runtime library search path because it is \
814 outside target root {}",
815 dir.display(),
816 root_output.display()
817 );
818 }
819 }
820 search_path
821}
822
823#[tracing::instrument(skip_all)]
830fn prepare_rustc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<ProcessBuilder> {
831 let gctx = build_runner.bcx.gctx;
832 let is_primary = build_runner.is_primary_package(unit);
833 let is_workspace = build_runner.bcx.ws.is_member(&unit.pkg);
834
835 let mut base = build_runner
836 .compilation
837 .rustc_process(unit, is_primary, is_workspace)?;
838 build_base_args(build_runner, &mut base, unit)?;
839 if unit.pkg.manifest().is_embedded() {
840 if !gctx.cli_unstable().script {
841 anyhow::bail!(
842 "parsing `{}` requires `-Zscript`",
843 unit.pkg.manifest_path().display()
844 );
845 }
846 base.arg("-Z").arg("crate-attr=feature(frontmatter)");
847 base.arg("-Z").arg("crate-attr=allow(unused_features)");
848 }
849
850 base.inherit_jobserver(&build_runner.jobserver);
851 build_deps_args(&mut base, build_runner, unit)?;
852 add_cap_lints(build_runner.bcx, unit, &mut base);
853 if let Some(args) = build_runner.bcx.extra_args_for(unit) {
854 base.args(args);
855 }
856 base.args(&unit.rustflags);
857 if gctx.cli_unstable().binary_dep_depinfo {
858 base.arg("-Z").arg("binary-dep-depinfo");
859 }
860 if build_runner.bcx.gctx.cli_unstable().checksum_freshness {
861 match build_runner
862 .bcx
863 .gctx
864 .build_config()?
865 .fingerprint
866 .unwrap_or_default()
867 {
868 FingerprintMethod::Content => {
869 base.arg("-Z").arg("checksum-hash-algorithm=blake3");
870 }
871 FingerprintMethod::Mtime => {}
872 }
873 }
874
875 if is_primary {
876 base.env("CARGO_PRIMARY_PACKAGE", "1");
877 let file_list = build_runner.sbom_output_files(unit)?;
878 if !file_list.is_empty() {
879 let file_list = std::env::join_paths(file_list)?;
880 base.env("CARGO_SBOM_PATH", file_list);
881 }
882 }
883
884 if unit.target.is_test() || unit.target.is_bench() {
885 let tmp = build_runner
886 .files()
887 .layout(unit.kind)
888 .build_dir()
889 .prepare_tmp()?;
890 base.env("CARGO_TARGET_TMPDIR", tmp.display().to_string());
891 }
892
893 base.arg("--force-warn=unused_crate_dependencies");
896
897 Ok(base)
898}
899
900#[tracing::instrument(skip_all)]
907fn prepare_rustdoc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<ProcessBuilder> {
908 let bcx = build_runner.bcx;
909 let mut rustdoc = build_runner.compilation.rustdoc_process(unit, None)?;
911 let wants_json_output = build_runner.bcx.build_config.intent.wants_doc_json_output();
912 if unit.pkg.manifest().is_embedded() {
913 if !bcx.gctx.cli_unstable().script {
914 anyhow::bail!(
915 "parsing `{}` requires `-Zscript`",
916 unit.pkg.manifest_path().display()
917 );
918 }
919 rustdoc.arg("-Z").arg("crate-attr=feature(frontmatter)");
920 rustdoc.arg("-Z").arg("crate-attr=allow(unused_features)");
921 }
922 rustdoc.inherit_jobserver(&build_runner.jobserver);
923 let crate_name = unit.target.crate_name();
924 rustdoc.arg("--crate-name").arg(&crate_name);
925 add_path_args(bcx.ws, unit, &mut rustdoc);
926 add_cap_lints(bcx, unit, &mut rustdoc);
927
928 unit.kind.add_target_arg(&mut rustdoc);
929
930 let doc_dir = if wants_json_output {
931 build_runner.files().out_dir_new_layout(unit)
935 } else {
936 build_runner.files().output_dir(unit)
937 };
938
939 rustdoc.arg("-o").arg(&doc_dir);
940 rustdoc.args(&features_args(unit));
941 rustdoc.args(&check_cfg_args(unit));
942
943 add_error_format_and_color(build_runner, &mut rustdoc);
944 add_allow_features(build_runner, &mut rustdoc);
945
946 if build_runner.bcx.gctx.cli_unstable().rustdoc_depinfo {
947 let mut arg = if wants_json_output {
950 OsString::from("--emit=dep-info=")
951 } else if build_runner.bcx.gctx.cli_unstable().rustdoc_mergeable_info {
952 OsString::from("--emit=html-non-static-files,dep-info=")
954 } else {
955 OsString::from("--emit=html-static-files,html-non-static-files,dep-info=")
957 };
958 arg.push(rustdoc_dep_info_loc(build_runner, unit));
959 rustdoc.arg(arg);
960
961 if build_runner.bcx.gctx.cli_unstable().checksum_freshness {
962 match build_runner
963 .bcx
964 .gctx
965 .build_config()?
966 .fingerprint
967 .unwrap_or_default()
968 {
969 FingerprintMethod::Content => {
970 rustdoc.arg("-Z").arg("checksum-hash-algorithm=blake3");
971 }
972 FingerprintMethod::Mtime => {}
973 }
974 }
975 } else if build_runner.bcx.gctx.cli_unstable().rustdoc_mergeable_info && !wants_json_output {
976 rustdoc.arg("--emit=html-non-static-files");
978 }
979
980 if build_runner.bcx.gctx.cli_unstable().rustdoc_mergeable_info && !wants_json_output {
981 rustdoc.arg("-Zunstable-options");
983 let mut arg = OsString::from("--write-doc-meta-dir=");
984 arg.push(build_runner.files().out_dir_new_layout(unit));
986 rustdoc.arg(arg);
987 }
988
989 trim_paths_args_rustdoc(&mut rustdoc, build_runner, unit, &unit.profile.trim_paths)?;
990
991 rustdoc.args(unit.pkg.manifest().lint_rustflags());
992
993 let metadata = build_runner.metadata_for_doc_units[unit];
994 rustdoc
995 .arg("-C")
996 .arg(format!("metadata={}", metadata.c_metadata()));
997
998 if unit.mode.is_doc_scrape() {
999 debug_assert!(build_runner.bcx.scrape_units.contains(unit));
1000
1001 if unit.target.is_test() {
1002 rustdoc.arg("--scrape-tests");
1003 }
1004
1005 rustdoc.arg("-Zunstable-options");
1006
1007 rustdoc
1008 .arg("--scrape-examples-output-path")
1009 .arg(scrape_output_path(build_runner, unit)?);
1010
1011 for pkg in build_runner.bcx.packages.packages() {
1013 let names = pkg
1014 .targets()
1015 .iter()
1016 .map(|target| target.crate_name())
1017 .collect::<HashSet<_>>();
1018 for name in names {
1019 rustdoc.arg("--scrape-examples-target-crate").arg(name);
1020 }
1021 }
1022 }
1023
1024 if should_include_scrape_units(build_runner.bcx, unit) {
1025 rustdoc.arg("-Zunstable-options");
1026 }
1027
1028 build_deps_args(&mut rustdoc, build_runner, unit)?;
1029 rustdoc::add_root_urls(build_runner, unit, &mut rustdoc)?;
1030
1031 rustdoc::add_output_format(build_runner, &mut rustdoc)?;
1032
1033 if let Some(args) = build_runner.bcx.extra_args_for(unit) {
1034 rustdoc.args(args);
1035 }
1036 rustdoc.args(&unit.rustdocflags);
1037
1038 if !crate_version_flag_already_present(&rustdoc) {
1039 append_crate_version_flag(unit, &mut rustdoc);
1040 }
1041
1042 Ok(rustdoc)
1043}
1044
1045#[tracing::instrument(skip_all)]
1047fn rustdoc(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<Work> {
1048 let mut rustdoc = prepare_rustdoc(build_runner, unit)?;
1049
1050 let crate_name = unit.target.crate_name();
1051 let is_json_output = build_runner.bcx.build_config.intent.wants_doc_json_output();
1052 let doc_dir = build_runner.files().output_dir(unit);
1053 paths::create_dir_all(&doc_dir)?;
1057
1058 let target_desc = unit.target.description_named();
1059 let name = unit.pkg.name();
1060 let build_script_outputs = Arc::clone(&build_runner.build_script_outputs);
1061 let package_id = unit.pkg.package_id();
1062 let target = Target::clone(&unit.target);
1063 let manifest = ManifestErrorContext::new(build_runner, unit);
1064
1065 let rustdoc_dep_info_loc = rustdoc_dep_info_loc(build_runner, unit);
1066 let dep_info_loc = fingerprint::dep_info_loc(build_runner, unit);
1067 let build_dir = build_runner.bcx.ws.build_dir().into_path_unlocked();
1068 let pkg_root = unit.pkg.root().to_path_buf();
1069 let cwd = rustdoc
1070 .get_cwd()
1071 .unwrap_or_else(|| build_runner.bcx.gctx.cwd())
1072 .to_path_buf();
1073 let fingerprint_dir = build_runner.files().fingerprint_dir(unit);
1074 let is_local = unit.is_local();
1075 let env_config = Arc::clone(build_runner.bcx.gctx.env_config()?);
1076 let rustdoc_depinfo_enabled = build_runner.bcx.gctx.cli_unstable().rustdoc_depinfo;
1077
1078 let mut output_options = OutputOptions::for_dirty(build_runner, unit);
1079 let script_metadatas = build_runner.find_build_script_metadatas(unit);
1080 let scrape_outputs = if should_include_scrape_units(build_runner.bcx, unit) {
1081 Some(
1082 build_runner
1083 .bcx
1084 .scrape_units
1085 .iter()
1086 .map(|unit| {
1087 Ok((
1088 build_runner.files().metadata(unit).unit_id(),
1089 scrape_output_path(build_runner, unit)?,
1090 ))
1091 })
1092 .collect::<CargoResult<HashMap<_, _>>>()?,
1093 )
1094 } else {
1095 None
1096 };
1097
1098 let failed_scrape_units = Arc::clone(&build_runner.failed_scrape_units);
1099 let hide_diagnostics_for_scrape_unit = build_runner.bcx.unit_can_fail_for_docscraping(unit)
1100 && !matches!(
1101 build_runner.bcx.gctx.shell().verbosity(),
1102 Verbosity::Verbose
1103 );
1104 let failed_scrape_diagnostic = hide_diagnostics_for_scrape_unit.then(|| {
1105 make_failed_scrape_diagnostic(
1106 build_runner,
1107 unit,
1108 format_args!("failed to scan {target_desc} in package `{name}` for example code usage"),
1109 )
1110 });
1111 if hide_diagnostics_for_scrape_unit {
1112 output_options.show_diagnostics = false;
1113 }
1114
1115 Ok(Work::new(move |state| {
1116 add_custom_flags(
1117 &mut rustdoc,
1118 &build_script_outputs.lock().unwrap(),
1119 script_metadatas,
1120 )?;
1121
1122 if let Some(scrape_outputs) = scrape_outputs {
1127 let failed_scrape_units = failed_scrape_units.lock().unwrap();
1128 for (metadata, output_path) in &scrape_outputs {
1129 if !failed_scrape_units.contains(metadata) {
1130 rustdoc.arg("--with-examples").arg(output_path);
1131 }
1132 }
1133 }
1134
1135 if !is_json_output {
1136 let crate_dir = doc_dir.join(&crate_name);
1137 if crate_dir.exists() {
1138 debug!("removing pre-existing doc directory {:?}", crate_dir);
1141 paths::remove_dir_all(&crate_dir)?;
1142 }
1143 };
1144 state.running(&rustdoc);
1145 let timestamp = paths::set_invocation_time(&fingerprint_dir)?;
1146
1147 let result = rustdoc
1148 .exec_with_streaming(
1149 &mut |line| on_stdout_line(state, line, package_id, &target),
1150 &mut |line| {
1151 on_stderr_line(
1152 state,
1153 line,
1154 package_id,
1155 &manifest,
1156 &target,
1157 &mut output_options,
1158 )
1159 },
1160 false,
1161 )
1162 .map_err(verbose_if_simple_exit_code)
1163 .with_context(|| format!("could not document `{}`", name));
1164
1165 if let Err(e) = result {
1166 if let Some(diagnostic) = failed_scrape_diagnostic {
1167 state.warning(diagnostic);
1168 }
1169
1170 return Err(e);
1171 }
1172
1173 if rustdoc_depinfo_enabled && rustdoc_dep_info_loc.exists() {
1174 fingerprint::translate_dep_info(
1175 &rustdoc_dep_info_loc,
1176 &dep_info_loc,
1177 &cwd,
1178 &pkg_root,
1179 &build_dir,
1180 &rustdoc,
1181 is_local,
1183 &env_config,
1184 )
1185 .with_context(|| {
1186 internal(format_args!(
1187 "could not parse/generate dep info at: {}",
1188 rustdoc_dep_info_loc.display()
1189 ))
1190 })?;
1191 paths::set_file_time_no_err(dep_info_loc, timestamp);
1194 }
1195
1196 Ok(())
1197 }))
1198}
1199
1200fn crate_version_flag_already_present(rustdoc: &ProcessBuilder) -> bool {
1203 rustdoc.get_args().any(|flag| {
1204 flag.to_str()
1205 .map_or(false, |flag| flag.starts_with(RUSTDOC_CRATE_VERSION_FLAG))
1206 })
1207}
1208
1209fn append_crate_version_flag(unit: &Unit, rustdoc: &mut ProcessBuilder) {
1210 rustdoc
1211 .arg(RUSTDOC_CRATE_VERSION_FLAG)
1212 .arg(unit.pkg.version().to_string());
1213}
1214
1215enum CapLints {
1216 Allow,
1217 Warn,
1218}
1219
1220fn compute_cap_lints(bcx: &BuildContext<'_, '_>, unit: &Unit) -> Option<CapLints> {
1221 if !unit.show_warnings(bcx.gctx) {
1224 Some(CapLints::Allow)
1225 } else if !unit.is_local() {
1228 Some(CapLints::Warn)
1229 } else {
1230 None
1231 }
1232}
1233
1234fn add_cap_lints(bcx: &BuildContext<'_, '_>, unit: &Unit, cmd: &mut ProcessBuilder) {
1238 if let Some(cap_lints) = compute_cap_lints(bcx, unit) {
1239 match cap_lints {
1240 CapLints::Allow => {
1241 cmd.arg("--cap-lints").arg("allow");
1242 }
1243 CapLints::Warn => {
1244 cmd.arg("--cap-lints").arg("warn");
1245 }
1246 }
1247 }
1248}
1249
1250fn add_allow_features(build_runner: &BuildRunner<'_, '_>, cmd: &mut ProcessBuilder) {
1254 if let Some(allow) = &build_runner.bcx.gctx.cli_unstable().allow_features {
1255 use std::fmt::Write;
1256 let mut arg = String::from("-Zallow-features=");
1257 for f in allow {
1258 let _ = write!(&mut arg, "{f},");
1259 }
1260 cmd.arg(arg.trim_end_matches(','));
1261 }
1262}
1263
1264fn add_error_format_and_color(build_runner: &BuildRunner<'_, '_>, cmd: &mut ProcessBuilder) {
1275 let enable_timings =
1276 build_runner.bcx.gctx.cli_unstable().section_timings && build_runner.bcx.logger.is_some();
1277 if enable_timings {
1278 cmd.arg("-Zunstable-options");
1279 }
1280
1281 cmd.arg("--error-format=json");
1282
1283 let mut json = String::from(
1284 "--json=diagnostic-rendered-ansi,artifacts,future-incompat,unused-externs-silent",
1285 );
1286 if let MessageFormat::Short | MessageFormat::Json { short: true, .. } =
1287 build_runner.bcx.build_config.message_format
1288 {
1289 json.push_str(",diagnostic-short");
1290 } else if build_runner.bcx.gctx.shell().err_unicode()
1291 && build_runner.bcx.gctx.cli_unstable().rustc_unicode
1292 {
1293 json.push_str(",diagnostic-unicode");
1294 }
1295 if enable_timings {
1296 json.push_str(",timings");
1297 }
1298 cmd.arg(json);
1299
1300 let gctx = build_runner.bcx.gctx;
1301 if let Some(width) = gctx.shell().err_width().diagnostic_terminal_width() {
1302 cmd.arg(format!("--diagnostic-width={width}"));
1303 }
1304}
1305
1306fn build_base_args(
1308 build_runner: &BuildRunner<'_, '_>,
1309 cmd: &mut ProcessBuilder,
1310 unit: &Unit,
1311) -> CargoResult<()> {
1312 assert!(!unit.mode.is_run_custom_build());
1313
1314 let bcx = build_runner.bcx;
1315 let Profile {
1316 ref opt_level,
1317 codegen_backend,
1318 codegen_units,
1319 debuginfo,
1320 debug_assertions,
1321 split_debuginfo,
1322 overflow_checks,
1323 rpath,
1324 ref panic,
1325 incremental,
1326 strip,
1327 rustflags: profile_rustflags,
1328 trim_paths,
1329 hint_mostly_unused: profile_hint_mostly_unused,
1330 ..
1331 } = unit.profile.clone();
1332 let hints = unit.pkg.hints().cloned().unwrap_or_default();
1333 let test = unit.mode.is_any_test();
1334
1335 cmd.arg("--crate-name").arg(&unit.target.crate_name());
1336
1337 let edition = unit.target.edition();
1338 edition.cmd_edition_arg(cmd);
1339
1340 add_path_args(bcx.ws, unit, cmd);
1341 add_error_format_and_color(build_runner, cmd);
1342 add_allow_features(build_runner, cmd);
1343
1344 let mut contains_dy_lib = false;
1345 if !test {
1346 for crate_type in &unit.target.rustc_crate_types() {
1347 cmd.arg("--crate-type").arg(crate_type.as_str());
1348 contains_dy_lib |= crate_type == &CrateType::Dylib;
1349 }
1350 }
1351
1352 if unit.mode.is_check() {
1353 cmd.arg("--emit=dep-info,metadata");
1354 } else if !build_runner
1355 .bcx
1356 .target_data
1357 .info(unit.kind)
1358 .should_embed_metadata()
1359 {
1360 if unit.benefits_from_no_embed_metadata() {
1370 cmd.arg("--emit=dep-info,metadata,link");
1371 cmd.args(&["-Z", "embed-metadata=no"]);
1372 } else {
1373 cmd.arg("--emit=dep-info,link");
1374 }
1375 } else {
1376 if !unit.requires_upstream_objects() {
1380 cmd.arg("--emit=dep-info,metadata,link");
1381 } else {
1382 cmd.arg("--emit=dep-info,link");
1383 }
1384 }
1385
1386 let prefer_dynamic = (unit.target.for_host() && !unit.target.is_custom_build())
1387 || (contains_dy_lib && !build_runner.is_primary_package(unit));
1388 if prefer_dynamic {
1389 cmd.arg("-C").arg("prefer-dynamic");
1390 }
1391
1392 if opt_level.as_str() != "0" {
1393 cmd.arg("-C").arg(&format!("opt-level={}", opt_level));
1394 }
1395
1396 if *panic != PanicStrategy::Unwind {
1397 cmd.arg("-C").arg(format!("panic={}", panic));
1398 }
1399 if *panic == PanicStrategy::ImmediateAbort {
1400 cmd.arg("-Z").arg("unstable-options");
1401 }
1402
1403 cmd.args(<o_args(build_runner, unit));
1404
1405 if let Some(backend) = codegen_backend {
1406 cmd.arg("-Z").arg(&format!("codegen-backend={}", backend));
1407 }
1408
1409 if let Some(n) = codegen_units {
1410 cmd.arg("-C").arg(&format!("codegen-units={}", n));
1411 }
1412
1413 let debuginfo = debuginfo.into_inner();
1414 if debuginfo != TomlDebugInfo::None {
1416 cmd.arg("-C").arg(format!("debuginfo={debuginfo}"));
1417 if let Some(split) = split_debuginfo {
1424 if build_runner
1425 .bcx
1426 .target_data
1427 .info(unit.kind)
1428 .supports_debuginfo_split(split)
1429 {
1430 cmd.arg("-C").arg(format!("split-debuginfo={split}"));
1431 }
1432 }
1433 }
1434
1435 trim_paths_args(cmd, build_runner, unit, &trim_paths)?;
1436
1437 match compute_cap_lints(bcx, unit) {
1438 None | Some(CapLints::Warn) => {
1439 cmd.args(unit.pkg.manifest().lint_rustflags());
1440 }
1441 Some(CapLints::Allow) => {}
1444 }
1445 cmd.args(&profile_rustflags);
1446
1447 if opt_level.as_str() != "0" {
1451 if debug_assertions {
1452 cmd.args(&["-C", "debug-assertions=on"]);
1453 if !overflow_checks {
1454 cmd.args(&["-C", "overflow-checks=off"]);
1455 }
1456 } else if overflow_checks {
1457 cmd.args(&["-C", "overflow-checks=on"]);
1458 }
1459 } else if !debug_assertions {
1460 cmd.args(&["-C", "debug-assertions=off"]);
1461 if overflow_checks {
1462 cmd.args(&["-C", "overflow-checks=on"]);
1463 }
1464 } else if !overflow_checks {
1465 cmd.args(&["-C", "overflow-checks=off"]);
1466 }
1467
1468 if test && unit.target.harness() {
1469 cmd.arg("--test");
1470
1471 if *panic == PanicStrategy::Abort || *panic == PanicStrategy::ImmediateAbort {
1479 cmd.arg("-Z").arg("panic-abort-tests");
1480 }
1481 } else if test {
1482 cmd.arg("--cfg").arg("test");
1483 }
1484
1485 cmd.args(&features_args(unit));
1486 cmd.args(&check_cfg_args(unit));
1487
1488 let meta = build_runner.files().metadata(unit);
1489 cmd.arg("-C")
1490 .arg(&format!("metadata={}", meta.c_metadata()));
1491 if let Some(c_extra_filename) = meta.c_extra_filename() {
1492 cmd.arg("-C")
1493 .arg(&format!("extra-filename=-{c_extra_filename}"));
1494 }
1495
1496 if rpath {
1497 cmd.arg("-C").arg("rpath");
1498 }
1499
1500 cmd.arg("--out-dir")
1501 .arg(&build_runner.files().output_dir(unit));
1502
1503 unit.kind.add_target_arg(cmd);
1504
1505 add_codegen_linker(cmd, build_runner, unit, bcx.gctx.target_applies_to_host()?);
1506
1507 if incremental {
1508 add_codegen_incremental(cmd, build_runner, unit)
1509 }
1510
1511 let pkg_hint_mostly_unused = match hints.mostly_unused {
1512 Some(toml::Value::Boolean(b)) => Some(b),
1513 _ => None,
1516 };
1517 if profile_hint_mostly_unused
1518 .or(pkg_hint_mostly_unused)
1519 .unwrap_or(false)
1520 && bcx.gctx.cli_unstable().profile_hint_mostly_unused
1521 {
1522 cmd.arg("-Zhint-mostly-unused");
1523 }
1524
1525 let strip = strip.into_inner();
1526 if strip != StripInner::None {
1527 cmd.arg("-C").arg(format!("strip={}", strip));
1528 }
1529
1530 if unit.is_std {
1531 cmd.arg("-Z")
1537 .arg("force-unstable-if-unmarked")
1538 .env("RUSTC_BOOTSTRAP", "1");
1539 }
1540
1541 if let Some(version) = unit.pkg.manifest().rust_version()
1542 && bcx.gctx.cli_unstable().hint_msrv
1543 {
1544 cmd.arg("-Z").arg(format!("hint-msrv={version}"));
1545 }
1546
1547 Ok(())
1548}
1549
1550fn features_args(unit: &Unit) -> Vec<OsString> {
1552 let mut args = Vec::with_capacity(unit.features.len() * 2);
1553
1554 for feat in &unit.features {
1555 args.push(OsString::from("--cfg"));
1556 args.push(OsString::from(format!("feature=\"{}\"", feat)));
1557 }
1558
1559 args
1560}
1561
1562fn check_cfg_args(unit: &Unit) -> Vec<OsString> {
1564 let gross_cap_estimation = unit.pkg.summary().features().len() * 7 + 25;
1582 let mut arg_feature = OsString::with_capacity(gross_cap_estimation);
1583
1584 arg_feature.push("cfg(feature, values(");
1585 for (i, feature) in unit.pkg.summary().features().keys().enumerate() {
1586 if i != 0 {
1587 arg_feature.push(", ");
1588 }
1589 arg_feature.push("\"");
1590 arg_feature.push(feature);
1591 arg_feature.push("\"");
1592 }
1593 arg_feature.push("))");
1594
1595 vec![
1604 OsString::from("--check-cfg"),
1605 OsString::from("cfg(docsrs,test)"),
1606 OsString::from("--check-cfg"),
1607 arg_feature,
1608 ]
1609}
1610
1611fn lto_args(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> Vec<OsString> {
1613 let mut result = Vec::new();
1614 let mut push = |arg: &str| {
1615 result.push(OsString::from("-C"));
1616 result.push(OsString::from(arg));
1617 };
1618 match build_runner.lto[unit] {
1619 lto::Lto::Run(None) => push("lto"),
1620 lto::Lto::Run(Some(s)) => push(&format!("lto={}", s)),
1621 lto::Lto::Off => {
1622 push("lto=off");
1623 push("embed-bitcode=no");
1624 }
1625 lto::Lto::ObjectAndBitcode => {} lto::Lto::OnlyBitcode => push("linker-plugin-lto"),
1627 lto::Lto::OnlyObject => push("embed-bitcode=no"),
1628 }
1629 result
1630}
1631
1632fn build_deps_args(
1638 cmd: &mut ProcessBuilder,
1639 build_runner: &BuildRunner<'_, '_>,
1640 unit: &Unit,
1641) -> CargoResult<()> {
1642 let bcx = build_runner.bcx;
1643
1644 for arg in lib_search_paths(build_runner, unit)? {
1645 cmd.arg(arg);
1646 }
1647
1648 let deps = build_runner.unit_deps(unit);
1649
1650 if !deps
1654 .iter()
1655 .any(|dep| !dep.unit.mode.is_doc() && dep.unit.target.is_linkable())
1656 {
1657 if let Some(dep) = deps.iter().find(|dep| {
1658 !dep.unit.mode.is_doc() && dep.unit.target.is_lib() && !dep.unit.artifact.is_true()
1659 }) {
1660 let dep_name = dep.unit.target.crate_name();
1661 let name = unit.target.crate_name();
1662 bcx.gctx.shell().print_report(&[
1663 Level::WARNING.secondary_title(format!("the package `{dep_name}` provides no linkable target"))
1664 .elements([
1665 Level::NOTE.message(format!("this might cause `{name}` to fail compilation")),
1666 Level::NOTE.message("this warning might turn into a hard error in the future"),
1667 Level::HELP.message(format!("consider adding 'dylib' or 'rlib' to key 'crate-type' in `{dep_name}`'s Cargo.toml"))
1668 ])
1669 ], false)?;
1670 }
1671 }
1672
1673 let mut unstable_opts = false;
1674
1675 let first_custom_build_dep = deps.iter().find(|dep| dep.unit.mode.is_run_custom_build());
1677 if let Some(dep) = first_custom_build_dep {
1678 let out_dir = if bcx.gctx.cli_unstable().build_dir_new_layout {
1679 build_runner.files().out_dir_new_layout(&dep.unit)
1680 } else {
1681 build_runner.files().build_script_out_dir(&dep.unit)
1682 };
1683 cmd.env("OUT_DIR", &out_dir);
1684 }
1685
1686 let is_multiple_build_scripts_enabled = unit
1688 .pkg
1689 .manifest()
1690 .unstable_features()
1691 .require(Feature::multiple_build_scripts())
1692 .is_ok();
1693
1694 if is_multiple_build_scripts_enabled {
1695 for dep in deps {
1696 if dep.unit.mode.is_run_custom_build() {
1697 let out_dir = if bcx.gctx.cli_unstable().build_dir_new_layout {
1698 build_runner.files().out_dir_new_layout(&dep.unit)
1699 } else {
1700 build_runner.files().build_script_out_dir(&dep.unit)
1701 };
1702 let target_name = dep.unit.target.name();
1703 let out_dir_prefix = target_name
1704 .strip_prefix("build-script-")
1705 .unwrap_or(target_name);
1706 let out_dir_name = format!("{out_dir_prefix}_OUT_DIR");
1707 cmd.env(&out_dir_name, &out_dir);
1708 }
1709 }
1710 }
1711 for arg in extern_args(build_runner, unit, &mut unstable_opts)? {
1712 cmd.arg(arg);
1713 }
1714
1715 for (var, env) in artifact::get_env(build_runner, unit, deps)? {
1716 cmd.env(&var, env);
1717 }
1718
1719 if unstable_opts {
1722 cmd.arg("-Z").arg("unstable-options");
1723 }
1724
1725 Ok(())
1726}
1727
1728fn add_custom_flags(
1732 cmd: &mut ProcessBuilder,
1733 build_script_outputs: &BuildScriptOutputs,
1734 metadata_vec: Option<Vec<UnitHash>>,
1735) -> CargoResult<()> {
1736 if let Some(metadata_vec) = metadata_vec {
1737 for metadata in metadata_vec {
1738 if let Some(output) = build_script_outputs.get(metadata) {
1739 for cfg in output.cfgs.iter() {
1740 cmd.arg("--cfg").arg(cfg);
1741 }
1742 for check_cfg in &output.check_cfgs {
1743 cmd.arg("--check-cfg").arg(check_cfg);
1744 }
1745 for (name, value) in output.env.iter() {
1746 cmd.env(name, value);
1747 }
1748 }
1749 }
1750 }
1751
1752 Ok(())
1753}
1754
1755#[tracing::instrument(skip_all)]
1757pub fn lib_search_paths(
1758 build_runner: &BuildRunner<'_, '_>,
1759 unit: &Unit,
1760) -> CargoResult<Vec<OsString>> {
1761 let mut lib_search_paths = Vec::new();
1762 if build_runner.bcx.gctx.cli_unstable().build_dir_new_layout {
1763 let paths = dep_paths_for_args(unit, build_runner);
1765
1766 for path in paths {
1767 let mut deps = OsString::from("dependency=");
1768 deps.push(path);
1769 lib_search_paths.extend(["-L".into(), deps]);
1770 }
1771 } else {
1772 let mut deps = OsString::from("dependency=");
1773 deps.push(build_runner.files().deps_dir(unit));
1774 lib_search_paths.extend(["-L".into(), deps]);
1775 }
1776
1777 if !unit.kind.is_host() {
1780 let mut deps = OsString::from("dependency=");
1781 deps.push(build_runner.files().host_deps(unit));
1782 lib_search_paths.extend(["-L".into(), deps]);
1783 }
1784
1785 Ok(lib_search_paths)
1786}
1787
1788fn dep_paths_for_args(unit: &Unit, build_runner: &BuildRunner<'_, '_>) -> Vec<PathBuf> {
1802 let direct = build_runner.unit_deps(unit);
1803 if direct.is_empty() {
1804 return Vec::new();
1805 }
1806
1807 let is_proc_macro = |u: &Unit| match u.target.kind() {
1811 TargetKind::Lib(kinds) => kinds.contains(&CrateType::ProcMacro),
1812 _ => false,
1813 };
1814
1815 let mut indirect = HashSet::default();
1816 let mut visited = HashSet::default();
1817 let mut stack: Vec<&Unit> = direct
1818 .iter()
1819 .filter(|d| !d.unit.target.is_custom_build())
1820 .map(|d| &d.unit)
1821 .collect();
1822 while let Some(u) = stack.pop() {
1823 if !visited.insert(u.clone()) {
1824 continue;
1825 }
1826 if is_proc_macro(u) {
1827 continue;
1828 }
1829 for dep in build_runner.unit_deps(u) {
1830 let v = &dep.unit;
1831 if v.target.is_custom_build() {
1832 continue;
1833 }
1834 indirect.insert(v.clone());
1835 if is_proc_macro(v) {
1836 continue;
1837 }
1838 if !visited.contains(v) {
1839 stack.push(v);
1840 }
1841 }
1842 }
1843
1844 let mut paths: Vec<PathBuf> = indirect
1845 .into_iter()
1846 .map(|u| build_runner.files().deps_dir(&u))
1847 .collect();
1848
1849 paths.sort_unstable_by(|a, b| match (a.to_str(), b.to_str()) {
1858 (Some(a), Some(b)) => a.cmp(b),
1859 (Some(_), None) => std::cmp::Ordering::Less,
1860 (None, Some(_)) => std::cmp::Ordering::Greater,
1861 (None, None) => std::cmp::Ordering::Less,
1862 });
1863 paths.dedup_by(|a, b| matches!((a.to_str(), b.to_str()), (Some(x), Some(y)) if x == y));
1864
1865 paths
1866}
1867
1868fn is_public_dependency_enabled(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> bool {
1869 unit.pkg
1870 .manifest()
1871 .unstable_features()
1872 .require(Feature::public_dependency())
1873 .is_ok()
1874 || build_runner.bcx.gctx.cli_unstable().public_dependency
1875}
1876
1877pub fn extern_args(
1879 build_runner: &BuildRunner<'_, '_>,
1880 unit: &Unit,
1881 unstable_opts: &mut bool,
1882) -> CargoResult<Vec<OsString>> {
1883 let mut result = Vec::new();
1884 let deps = build_runner.unit_deps(unit);
1885
1886 let no_embed_metadata = !build_runner
1887 .bcx
1888 .target_data
1889 .info(unit.kind)
1890 .should_embed_metadata();
1891 let public_dependency_enabled = is_public_dependency_enabled(build_runner, unit);
1892
1893 let mut link_to = |dep: &UnitDep,
1895 extern_crate_name: InternedString,
1896 noprelude: bool,
1897 nounused: bool|
1898 -> CargoResult<()> {
1899 let mut value = OsString::new();
1900 let mut opts = Vec::new();
1901 if !dep.public && unit.target.is_lib() && public_dependency_enabled {
1902 opts.push("priv");
1903 *unstable_opts = true;
1904 }
1905 if noprelude {
1906 opts.push("noprelude");
1907 *unstable_opts = true;
1908 }
1909 if nounused {
1910 opts.push("nounused");
1911 *unstable_opts = true;
1912 }
1913 if !opts.is_empty() {
1914 value.push(opts.join(","));
1915 value.push(":");
1916 }
1917 value.push(extern_crate_name.as_str());
1918 value.push("=");
1919
1920 let mut pass = |file| {
1921 let mut value = value.clone();
1922 value.push(file);
1923 result.push(OsString::from("--extern"));
1924 result.push(value);
1925 };
1926
1927 let outputs = build_runner.outputs(&dep.unit)?;
1928
1929 if build_runner.only_requires_rmeta(unit, &dep.unit) || dep.unit.mode.is_check() {
1930 let output = outputs
1932 .iter()
1933 .find(|output| output.flavor == FileFlavor::Rmeta)
1934 .expect("failed to find rmeta dep for pipelined dep");
1935 pass(&output.path);
1936 } else {
1937 for output in outputs.iter() {
1939 if output.flavor == FileFlavor::Linkable {
1940 pass(&output.path);
1941 }
1942 else if no_embed_metadata && output.flavor == FileFlavor::Rmeta {
1946 pass(&output.path);
1947 }
1948 }
1949 }
1950 Ok(())
1951 };
1952
1953 for dep in deps {
1954 if dep.unit.target.is_linkable() && !dep.unit.mode.is_doc() {
1955 link_to(dep, dep.extern_crate_name, dep.noprelude, dep.nounused)?;
1956 }
1957 }
1958 if unit.target.proc_macro() {
1959 result.push(OsString::from("--extern"));
1961 result.push(OsString::from("proc_macro"));
1962 }
1963
1964 Ok(result)
1965}
1966
1967fn add_codegen_linker(
1969 cmd: &mut ProcessBuilder,
1970 build_runner: &BuildRunner<'_, '_>,
1971 unit: &Unit,
1972 target_applies_to_host: bool,
1973) {
1974 let linker = if unit.target.for_host() && !target_applies_to_host {
1975 build_runner
1976 .compilation
1977 .host_linker()
1978 .map(|s| s.as_os_str())
1979 } else {
1980 build_runner
1981 .compilation
1982 .target_linker(unit.kind)
1983 .map(|s| s.as_os_str())
1984 };
1985
1986 if let Some(linker) = linker {
1987 let mut arg = OsString::from("linker=");
1988 arg.push(linker);
1989 cmd.arg("-C").arg(arg);
1990 }
1991}
1992
1993fn add_codegen_incremental(
1995 cmd: &mut ProcessBuilder,
1996 build_runner: &BuildRunner<'_, '_>,
1997 unit: &Unit,
1998) {
1999 let dir = build_runner.files().incremental_dir(&unit);
2000 let mut arg = OsString::from("incremental=");
2001 arg.push(dir.as_os_str());
2002 cmd.arg("-C").arg(arg);
2003}
2004
2005fn envify(s: &str) -> String {
2006 s.chars()
2007 .flat_map(|c| c.to_uppercase())
2008 .map(|c| if c == '-' { '_' } else { c })
2009 .collect()
2010}
2011
2012struct OutputOptions {
2015 format: MessageFormat,
2017 cache_cell: Option<(PathBuf, OnceCell<File>)>,
2022 show_diagnostics: bool,
2030 warnings_seen: usize,
2032 errors_seen: usize,
2034}
2035
2036impl OutputOptions {
2037 fn for_dirty(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OutputOptions {
2038 let path = build_runner.files().message_cache_path(unit);
2039 drop(fs::remove_file(&path));
2041 let cache_cell = Some((path, OnceCell::new()));
2042
2043 let show_diagnostics = true;
2044
2045 let format = build_runner.bcx.build_config.message_format;
2046
2047 OutputOptions {
2048 format,
2049 cache_cell,
2050 show_diagnostics,
2051 warnings_seen: 0,
2052 errors_seen: 0,
2053 }
2054 }
2055
2056 fn for_fresh(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OutputOptions {
2057 let cache_cell = None;
2058
2059 let show_diagnostics = unit.show_warnings(build_runner.bcx.gctx);
2062
2063 let format = build_runner.bcx.build_config.message_format;
2064
2065 OutputOptions {
2066 format,
2067 cache_cell,
2068 show_diagnostics,
2069 warnings_seen: 0,
2070 errors_seen: 0,
2071 }
2072 }
2073}
2074
2075struct ManifestErrorContext {
2081 path: PathBuf,
2083 spans: Option<Arc<toml::Spanned<toml::de::DeTable<'static>>>>,
2085 contents: Option<String>,
2087 rename_table: HashMap<InternedString, InternedString>,
2090 requested_kinds: Vec<CompileKind>,
2093 cfgs: Vec<Vec<Cfg>>,
2096 host_name: InternedString,
2097 cwd: PathBuf,
2099 term_width: usize,
2101}
2102
2103fn on_stdout_line(
2104 state: &JobState<'_, '_>,
2105 line: &str,
2106 _package_id: PackageId,
2107 _target: &Target,
2108) -> CargoResult<()> {
2109 state.stdout(line.to_string())?;
2110 Ok(())
2111}
2112
2113fn on_stderr_line(
2114 state: &JobState<'_, '_>,
2115 line: &str,
2116 package_id: PackageId,
2117 manifest: &ManifestErrorContext,
2118 target: &Target,
2119 options: &mut OutputOptions,
2120) -> CargoResult<()> {
2121 if on_stderr_line_inner(state, line, package_id, manifest, target, options)? {
2122 if let Some((path, cell)) = &mut options.cache_cell {
2124 let f = cell.try_borrow_mut_with(|| paths::create(path))?;
2126 debug_assert!(!line.contains('\n'));
2127 f.write_all(line.as_bytes())?;
2128 f.write_all(&[b'\n'])?;
2129 }
2130 }
2131 Ok(())
2132}
2133
2134fn on_stderr_line_inner(
2136 state: &JobState<'_, '_>,
2137 line: &str,
2138 package_id: PackageId,
2139 manifest: &ManifestErrorContext,
2140 target: &Target,
2141 options: &mut OutputOptions,
2142) -> CargoResult<bool> {
2143 if !line.starts_with('{') {
2149 state.stderr(line.to_string())?;
2150 return Ok(true);
2151 }
2152
2153 let mut compiler_message: Box<serde_json::value::RawValue> = match serde_json::from_str(line) {
2154 Ok(msg) => msg,
2155
2156 Err(e) => {
2160 debug!("failed to parse json: {:?}", e);
2161 state.stderr(line.to_string())?;
2162 return Ok(true);
2163 }
2164 };
2165
2166 let count_diagnostic = |level, options: &mut OutputOptions| {
2167 if level == "warning" {
2168 options.warnings_seen += 1;
2169 } else if level == "error" {
2170 options.errors_seen += 1;
2171 }
2172 };
2173
2174 if let Ok(report) = serde_json::from_str::<FutureIncompatReport>(compiler_message.get()) {
2175 for item in &report.future_incompat_report {
2176 count_diagnostic(&*item.diagnostic.level, options);
2177 }
2178 state.future_incompat_report(report.future_incompat_report);
2179 return Ok(true);
2180 }
2181
2182 let res = serde_json::from_str::<SectionTiming>(compiler_message.get());
2183 if let Ok(timing_record) = res {
2184 state.on_section_timing_emitted(timing_record);
2185 return Ok(false);
2186 }
2187
2188 let add_pub_in_priv_diagnostic = |diag: &mut String| -> bool {
2190 static PRIV_DEP_REGEX: LazyLock<Regex> =
2199 LazyLock::new(|| Regex::new("from private dependency '([A-Za-z0-9-_]+)'").unwrap());
2200 if let Some(crate_name) = PRIV_DEP_REGEX.captures(diag).and_then(|m| m.get(1))
2201 && let Some(ref contents) = manifest.contents
2202 && let Some(span) = manifest.find_crate_span(crate_name.as_str())
2203 {
2204 let rel_path = pathdiff::diff_paths(&manifest.path, &manifest.cwd)
2205 .unwrap_or_else(|| manifest.path.clone())
2206 .display()
2207 .to_string();
2208 let report = [Group::with_title(Level::NOTE.secondary_title(format!(
2209 "dependency `{}` declared here",
2210 crate_name.as_str()
2211 )))
2212 .element(
2213 Snippet::source(contents)
2214 .path(rel_path)
2215 .annotation(AnnotationKind::Context.span(span)),
2216 )];
2217
2218 let rendered = Renderer::styled()
2219 .term_width(manifest.term_width)
2220 .render(&report);
2221 diag.push_str(&rendered);
2222 diag.push('\n');
2223 return true;
2224 }
2225 false
2226 };
2227
2228 match options.format {
2231 MessageFormat::Human
2236 | MessageFormat::Short
2237 | MessageFormat::Json {
2238 render_diagnostics: true,
2239 ..
2240 } => {
2241 #[derive(serde::Deserialize)]
2242 struct CompilerMessage<'a> {
2243 rendered: String,
2247 #[serde(borrow)]
2248 message: Cow<'a, str>,
2249 #[serde(borrow)]
2250 level: Cow<'a, str>,
2251 children: Vec<PartialDiagnostic>,
2252 code: Option<DiagnosticCode>,
2253 }
2254
2255 #[derive(serde::Deserialize)]
2264 struct PartialDiagnostic {
2265 spans: Vec<PartialDiagnosticSpan>,
2266 }
2267
2268 #[derive(serde::Deserialize)]
2270 struct PartialDiagnosticSpan {
2271 suggestion_applicability: Option<Applicability>,
2272 }
2273
2274 #[derive(serde::Deserialize)]
2275 struct DiagnosticCode {
2276 code: String,
2277 }
2278
2279 if let Ok(mut msg) = serde_json::from_str::<CompilerMessage<'_>>(compiler_message.get())
2280 {
2281 if msg.message.starts_with("aborting due to")
2282 || msg.message.ends_with("warning emitted")
2283 || msg.message.ends_with("warnings emitted")
2284 {
2285 return Ok(true);
2287 }
2288 if msg.rendered.ends_with('\n') {
2290 msg.rendered.pop();
2291 }
2292 let mut rendered = msg.rendered;
2293 if options.show_diagnostics {
2294 let machine_applicable: bool = msg
2295 .children
2296 .iter()
2297 .map(|child| {
2298 child
2299 .spans
2300 .iter()
2301 .filter_map(|span| span.suggestion_applicability)
2302 .any(|app| app == Applicability::MachineApplicable)
2303 })
2304 .any(|b| b);
2305 count_diagnostic(&msg.level, options);
2306 if msg
2307 .code
2308 .as_ref()
2309 .is_some_and(|c| c.code == "exported_private_dependencies")
2310 && options.format != MessageFormat::Short
2311 {
2312 add_pub_in_priv_diagnostic(&mut rendered);
2313 }
2314 let lint = msg.code.is_some();
2315 state.emit_diag(&msg.level, rendered, lint, machine_applicable)?;
2316 }
2317 return Ok(true);
2318 }
2319 }
2320
2321 MessageFormat::Json { ansi, .. } => {
2322 #[derive(serde::Deserialize, serde::Serialize)]
2323 struct CompilerMessage<'a> {
2324 rendered: String,
2325 #[serde(flatten, borrow)]
2326 other: std::collections::BTreeMap<Cow<'a, str>, serde_json::Value>,
2327 code: Option<DiagnosticCode<'a>>,
2328 }
2329
2330 #[derive(serde::Deserialize, serde::Serialize)]
2331 struct DiagnosticCode<'a> {
2332 code: String,
2333 #[serde(flatten, borrow)]
2334 other: std::collections::BTreeMap<Cow<'a, str>, serde_json::Value>,
2335 }
2336
2337 if let Ok(mut error) =
2338 serde_json::from_str::<CompilerMessage<'_>>(compiler_message.get())
2339 {
2340 let modified_diag = if error
2341 .code
2342 .as_ref()
2343 .is_some_and(|c| c.code == "exported_private_dependencies")
2344 {
2345 add_pub_in_priv_diagnostic(&mut error.rendered)
2346 } else {
2347 false
2348 };
2349
2350 if !ansi {
2354 error.rendered = anstream::adapter::strip_str(&error.rendered).to_string();
2355 }
2356 if !ansi || modified_diag {
2357 let new_line = serde_json::to_string(&error)?;
2358 compiler_message = serde_json::value::RawValue::from_string(new_line)?;
2359 }
2360 }
2361 }
2362 }
2363
2364 #[derive(serde::Deserialize)]
2371 struct ArtifactNotification<'a> {
2372 #[serde(borrow)]
2373 artifact: Cow<'a, str>,
2374 }
2375
2376 if let Ok(artifact) = serde_json::from_str::<ArtifactNotification<'_>>(compiler_message.get()) {
2377 trace!("found directive from rustc: `{}`", artifact.artifact);
2378 if artifact.artifact.ends_with(".rmeta") {
2379 debug!("looks like metadata finished early!");
2380 state.rmeta_produced();
2381 }
2382 return Ok(false);
2383 }
2384
2385 #[derive(serde::Deserialize)]
2386 struct UnusedExterns {
2387 unused_extern_names: std::collections::BTreeSet<InternedString>,
2388 }
2389 if let Ok(uext) = serde_json::from_str::<UnusedExterns>(compiler_message.get()) {
2390 trace!(
2391 "obtained unused externs list from rustc: `{:?}`",
2392 uext.unused_extern_names
2393 );
2394 state.unused_externs(uext.unused_extern_names);
2395 return Ok(true);
2396 }
2397
2398 if !options.show_diagnostics {
2403 return Ok(true);
2404 }
2405
2406 #[derive(serde::Deserialize)]
2407 struct CompilerMessage<'a> {
2408 #[serde(borrow)]
2409 message: Cow<'a, str>,
2410 #[serde(borrow)]
2411 level: Cow<'a, str>,
2412 }
2413
2414 if let Ok(msg) = serde_json::from_str::<CompilerMessage<'_>>(compiler_message.get()) {
2415 if msg.message.starts_with("aborting due to")
2416 || msg.message.ends_with("warning emitted")
2417 || msg.message.ends_with("warnings emitted")
2418 {
2419 return Ok(true);
2421 }
2422 count_diagnostic(&msg.level, options);
2423 }
2424
2425 let msg = machine_message::FromCompiler {
2426 package_id: package_id.to_spec(),
2427 manifest_path: &manifest.path,
2428 target,
2429 message: compiler_message,
2430 }
2431 .to_json_string();
2432
2433 state.stdout(msg)?;
2437 Ok(true)
2438}
2439
2440impl ManifestErrorContext {
2441 fn new(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> ManifestErrorContext {
2442 let mut duplicates = HashSet::default();
2443 let mut rename_table = HashMap::default();
2444
2445 for dep in build_runner.unit_deps(unit) {
2446 let unrenamed_id = dep.unit.pkg.package_id().name();
2447 if duplicates.contains(&unrenamed_id) {
2448 continue;
2449 }
2450 match rename_table.entry(unrenamed_id) {
2451 std::collections::hash_map::Entry::Occupied(occ) => {
2452 occ.remove_entry();
2453 duplicates.insert(unrenamed_id);
2454 }
2455 std::collections::hash_map::Entry::Vacant(vac) => {
2456 vac.insert(dep.extern_crate_name);
2457 }
2458 }
2459 }
2460
2461 let bcx = build_runner.bcx;
2462 ManifestErrorContext {
2463 path: unit.pkg.manifest_path().to_owned(),
2464 spans: unit.pkg.manifest().document_rc(),
2465 contents: unit.pkg.manifest().contents().map(String::from),
2466 requested_kinds: bcx.target_data.requested_kinds().to_owned(),
2467 host_name: bcx.rustc().host,
2468 rename_table,
2469 cwd: path_args(build_runner.bcx.ws, unit).1,
2470 cfgs: bcx
2471 .target_data
2472 .requested_kinds()
2473 .iter()
2474 .map(|k| bcx.target_data.cfg(*k).to_owned())
2475 .collect(),
2476 term_width: bcx
2477 .gctx
2478 .shell()
2479 .err_width()
2480 .diagnostic_terminal_width()
2481 .unwrap_or(cargo_util_terminal::report::renderer::DEFAULT_TERM_WIDTH),
2482 }
2483 }
2484
2485 fn requested_target_names(&self) -> impl Iterator<Item = &str> {
2486 self.requested_kinds.iter().map(|kind| match kind {
2487 CompileKind::Host => &self.host_name,
2488 CompileKind::Target(target) => target.short_name(),
2489 })
2490 }
2491
2492 fn find_crate_span(&self, unrenamed: &str) -> Option<Range<usize>> {
2506 let Some(ref spans) = self.spans else {
2507 return None;
2508 };
2509
2510 let orig_name = self.rename_table.get(unrenamed)?.as_str();
2511
2512 if let Some((k, v)) = get_key_value(&spans, &["dependencies", orig_name]) {
2513 if let Some(package) = v.get_ref().as_table().and_then(|t| t.get("package")) {
2522 return Some(package.span());
2523 } else {
2524 return Some(k.span());
2525 }
2526 }
2527
2528 if let Some(target) = spans
2533 .deref()
2534 .as_ref()
2535 .get("target")
2536 .and_then(|t| t.as_ref().as_table())
2537 {
2538 for (platform, platform_table) in target.iter() {
2539 match platform.as_ref().parse::<Platform>() {
2540 Ok(Platform::Name(name)) => {
2541 if !self.requested_target_names().any(|n| n == name) {
2542 continue;
2543 }
2544 }
2545 Ok(Platform::Cfg(cfg_expr)) => {
2546 if !self.cfgs.iter().any(|cfgs| cfg_expr.matches(cfgs)) {
2547 continue;
2548 }
2549 }
2550 Err(_) => continue,
2551 }
2552
2553 let Some(platform_table) = platform_table.as_ref().as_table() else {
2554 continue;
2555 };
2556
2557 if let Some(deps) = platform_table
2558 .get("dependencies")
2559 .and_then(|d| d.as_ref().as_table())
2560 {
2561 if let Some((k, v)) = deps.get_key_value(orig_name) {
2562 if let Some(package) = v.get_ref().as_table().and_then(|t| t.get("package"))
2563 {
2564 return Some(package.span());
2565 } else {
2566 return Some(k.span());
2567 }
2568 }
2569 }
2570 }
2571 }
2572 None
2573 }
2574}
2575
2576fn replay_output_cache(
2580 package_id: PackageId,
2581 manifest: ManifestErrorContext,
2582 target: &Target,
2583 path: PathBuf,
2584 mut output_options: OutputOptions,
2585) -> Work {
2586 let target = target.clone();
2587 Work::new(move |state| {
2588 if !path.exists() {
2589 return Ok(());
2591 }
2592 let file = paths::open(&path)?;
2596 let mut reader = std::io::BufReader::new(file);
2597 let mut line = String::new();
2598 loop {
2599 let length = reader.read_line(&mut line)?;
2600 if length == 0 {
2601 break;
2602 }
2603 let trimmed = line.trim_end_matches(&['\n', '\r'][..]);
2604 on_stderr_line(
2605 state,
2606 trimmed,
2607 package_id,
2608 &manifest,
2609 &target,
2610 &mut output_options,
2611 )?;
2612 line.clear();
2613 }
2614 Ok(())
2615 })
2616}
2617
2618fn descriptive_pkg_name(name: &str, target: &Target, mode: &CompileMode) -> String {
2621 let desc_name = target.description_named();
2622 let mode = if mode.is_rustc_test() && !(target.is_test() || target.is_bench()) {
2623 " test"
2624 } else if mode.is_doc_test() {
2625 " doctest"
2626 } else if mode.is_doc() {
2627 " doc"
2628 } else {
2629 ""
2630 };
2631 format!("`{name}` ({desc_name}{mode})")
2632}
2633
2634pub(crate) fn apply_env_config(
2636 gctx: &crate::GlobalContext,
2637 cmd: &mut ProcessBuilder,
2638) -> CargoResult<()> {
2639 for (key, value) in gctx.env_config()?.iter() {
2640 if cmd.get_envs().contains_key(key) {
2642 continue;
2643 }
2644 cmd.env(key, value);
2645 }
2646 Ok(())
2647}
2648
2649fn should_include_scrape_units(bcx: &BuildContext<'_, '_>, unit: &Unit) -> bool {
2651 unit.mode.is_doc() && bcx.scrape_units.len() > 0 && bcx.ws.unit_needs_doc_scrape(unit)
2652}
2653
2654fn scrape_output_path(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<PathBuf> {
2656 assert!(unit.mode.is_doc() || unit.mode.is_doc_scrape());
2657 build_runner
2658 .outputs(unit)
2659 .map(|outputs| outputs[0].path.clone())
2660}
2661
2662fn rustdoc_dep_info_loc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> PathBuf {
2664 let mut loc = build_runner.files().fingerprint_file_path(unit, "");
2665 loc.set_extension("d");
2666 loc
2667}