1pub mod artifact;
35mod build_config;
36pub(crate) mod build_context;
37mod build_plan;
38pub(crate) mod build_runner;
39mod compilation;
40mod compile_kind;
41mod crate_type;
42mod custom_build;
43pub(crate) mod fingerprint;
44pub mod future_incompat;
45pub(crate) mod job_queue;
46pub(crate) mod layout;
47mod links;
48mod lto;
49mod output_depinfo;
50pub mod rustdoc;
51pub mod standard_lib;
52mod timings;
53mod unit;
54pub mod unit_dependencies;
55pub mod unit_graph;
56
57use std::borrow::Cow;
58use std::collections::{HashMap, HashSet};
59use std::env;
60use std::ffi::{OsStr, OsString};
61use std::fmt::Display;
62use std::fs::{self, File};
63use std::io::{BufRead, Write};
64use std::path::{Path, PathBuf};
65use std::sync::Arc;
66
67use anyhow::{Context as _, Error};
68use lazycell::LazyCell;
69use tracing::{debug, trace};
70
71pub use self::build_config::{BuildConfig, CompileMode, MessageFormat, TimingOutput};
72pub use self::build_context::{
73 BuildContext, FileFlavor, FileType, RustDocFingerprint, RustcTargetData, TargetInfo,
74};
75use self::build_plan::BuildPlan;
76pub use self::build_runner::{BuildRunner, Metadata, UnitHash};
77pub use self::compilation::{Compilation, Doctest, UnitOutput};
78pub use self::compile_kind::{CompileKind, CompileTarget};
79pub use self::crate_type::CrateType;
80pub use self::custom_build::LinkArgTarget;
81pub use self::custom_build::{BuildOutput, BuildScriptOutputs, BuildScripts};
82pub(crate) use self::fingerprint::DirtyReason;
83pub use self::job_queue::Freshness;
84use self::job_queue::{Job, JobQueue, JobState, Work};
85pub(crate) use self::layout::Layout;
86pub use self::lto::Lto;
87use self::output_depinfo::output_depinfo;
88use self::unit_graph::UnitDep;
89use crate::core::compiler::future_incompat::FutureIncompatReport;
90pub use crate::core::compiler::unit::{Unit, UnitInterner};
91use crate::core::manifest::TargetSourcePath;
92use crate::core::profiles::{PanicStrategy, Profile, StripInner};
93use crate::core::{Feature, PackageId, Target, Verbosity};
94use crate::util::context::WarningHandling;
95use crate::util::errors::{CargoResult, VerboseError};
96use crate::util::interning::InternedString;
97use crate::util::machine_message::{self, Message};
98use crate::util::{add_path_args, internal};
99use cargo_util::{paths, ProcessBuilder, ProcessError};
100use cargo_util_schemas::manifest::TomlDebugInfo;
101use cargo_util_schemas::manifest::TomlTrimPaths;
102use cargo_util_schemas::manifest::TomlTrimPathsValue;
103use rustfix::diagnostics::Applicability;
104
105const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version";
106
107pub trait Executor: Send + Sync + 'static {
111 fn init(&self, _build_runner: &BuildRunner<'_, '_>, _unit: &Unit) {}
115
116 fn exec(
119 &self,
120 cmd: &ProcessBuilder,
121 id: PackageId,
122 target: &Target,
123 mode: CompileMode,
124 on_stdout_line: &mut dyn FnMut(&str) -> CargoResult<()>,
125 on_stderr_line: &mut dyn FnMut(&str) -> CargoResult<()>,
126 ) -> CargoResult<()>;
127
128 fn force_rebuild(&self, _unit: &Unit) -> bool {
131 false
132 }
133}
134
135#[derive(Copy, Clone)]
138pub struct DefaultExecutor;
139
140impl Executor for DefaultExecutor {
141 fn exec(
142 &self,
143 cmd: &ProcessBuilder,
144 _id: PackageId,
145 _target: &Target,
146 _mode: CompileMode,
147 on_stdout_line: &mut dyn FnMut(&str) -> CargoResult<()>,
148 on_stderr_line: &mut dyn FnMut(&str) -> CargoResult<()>,
149 ) -> CargoResult<()> {
150 cmd.exec_with_streaming(on_stdout_line, on_stderr_line, false)
151 .map(drop)
152 }
153}
154
155#[tracing::instrument(skip(build_runner, jobs, plan, exec))]
165fn compile<'gctx>(
166 build_runner: &mut BuildRunner<'_, 'gctx>,
167 jobs: &mut JobQueue<'gctx>,
168 plan: &mut BuildPlan,
169 unit: &Unit,
170 exec: &Arc<dyn Executor>,
171 force_rebuild: bool,
172) -> CargoResult<()> {
173 let bcx = build_runner.bcx;
174 let build_plan = bcx.build_config.build_plan;
175 if !build_runner.compiled.insert(unit.clone()) {
176 return Ok(());
177 }
178
179 fingerprint::prepare_init(build_runner, unit)?;
182
183 let job = if unit.mode.is_run_custom_build() {
184 custom_build::prepare(build_runner, unit)?
185 } else if unit.mode.is_doc_test() {
186 Job::new_fresh()
188 } else if build_plan {
189 Job::new_dirty(
190 rustc(build_runner, unit, &exec.clone())?,
191 DirtyReason::FreshBuild,
192 )
193 } else {
194 let force = exec.force_rebuild(unit) || force_rebuild;
195 let mut job = fingerprint::prepare_target(build_runner, unit, force)?;
196 job.before(if job.freshness().is_dirty() {
197 let work = if unit.mode.is_doc() || unit.mode.is_doc_scrape() {
198 rustdoc(build_runner, unit)?
199 } else {
200 rustc(build_runner, unit, exec)?
201 };
202 work.then(link_targets(build_runner, unit, false)?)
203 } else {
204 let show_diagnostics = unit.show_warnings(bcx.gctx)
207 && build_runner.bcx.gctx.warning_handling()? != WarningHandling::Allow;
208 let work = replay_output_cache(
209 unit.pkg.package_id(),
210 PathBuf::from(unit.pkg.manifest_path()),
211 &unit.target,
212 build_runner.files().message_cache_path(unit),
213 build_runner.bcx.build_config.message_format,
214 show_diagnostics,
215 );
216 work.then(link_targets(build_runner, unit, true)?)
218 });
219
220 job
221 };
222 jobs.enqueue(build_runner, unit, job)?;
223
224 let deps = Vec::from(build_runner.unit_deps(unit)); for dep in deps {
227 compile(build_runner, jobs, plan, &dep.unit, exec, false)?;
228 }
229 if build_plan {
230 plan.add(build_runner, unit)?;
231 }
232
233 Ok(())
234}
235
236fn make_failed_scrape_diagnostic(
239 build_runner: &BuildRunner<'_, '_>,
240 unit: &Unit,
241 top_line: impl Display,
242) -> String {
243 let manifest_path = unit.pkg.manifest_path();
244 let relative_manifest_path = manifest_path
245 .strip_prefix(build_runner.bcx.ws.root())
246 .unwrap_or(&manifest_path);
247
248 format!(
249 "\
250{top_line}
251 Try running with `--verbose` to see the error message.
252 If an example should not be scanned, then consider adding `doc-scrape-examples = false` to its `[[example]]` definition in {}",
253 relative_manifest_path.display()
254 )
255}
256
257fn rustc(
259 build_runner: &mut BuildRunner<'_, '_>,
260 unit: &Unit,
261 exec: &Arc<dyn Executor>,
262) -> CargoResult<Work> {
263 let mut rustc = prepare_rustc(build_runner, unit)?;
264 let build_plan = build_runner.bcx.build_config.build_plan;
265
266 let name = unit.pkg.name();
267 let buildkey = unit.buildkey();
268
269 let outputs = build_runner.outputs(unit)?;
270 let root = build_runner.files().out_dir(unit);
271
272 let build_script_outputs = Arc::clone(&build_runner.build_script_outputs);
274 let current_id = unit.pkg.package_id();
275 let manifest_path = PathBuf::from(unit.pkg.manifest_path());
276 let build_scripts = build_runner.build_scripts.get(unit).cloned();
277
278 let pass_l_flag = unit.target.is_lib() || !unit.pkg.targets().iter().any(|t| t.is_lib());
281
282 let dep_info_name =
283 if let Some(c_extra_filename) = build_runner.files().metadata(unit).c_extra_filename() {
284 format!("{}-{}.d", unit.target.crate_name(), c_extra_filename)
285 } else {
286 format!("{}.d", unit.target.crate_name())
287 };
288 let rustc_dep_info_loc = root.join(dep_info_name);
289 let dep_info_loc = fingerprint::dep_info_loc(build_runner, unit);
290
291 let mut output_options = OutputOptions::new(build_runner, unit);
292 let package_id = unit.pkg.package_id();
293 let target = Target::clone(&unit.target);
294 let mode = unit.mode;
295
296 exec.init(build_runner, unit);
297 let exec = exec.clone();
298
299 let root_output = build_runner.files().host_dest().to_path_buf();
300 let target_dir = build_runner.bcx.ws.target_dir().into_path_unlocked();
301 let pkg_root = unit.pkg.root().to_path_buf();
302 let cwd = rustc
303 .get_cwd()
304 .unwrap_or_else(|| build_runner.bcx.gctx.cwd())
305 .to_path_buf();
306 let fingerprint_dir = build_runner.files().fingerprint_dir(unit);
307 let script_metadata = build_runner.find_build_script_metadata(unit);
308 let is_local = unit.is_local();
309 let artifact = unit.artifact;
310
311 let hide_diagnostics_for_scrape_unit = build_runner.bcx.unit_can_fail_for_docscraping(unit)
312 && !matches!(
313 build_runner.bcx.gctx.shell().verbosity(),
314 Verbosity::Verbose
315 );
316 let failed_scrape_diagnostic = hide_diagnostics_for_scrape_unit.then(|| {
317 let target_desc = unit.target.description_named();
320 let mut for_scrape_units = build_runner
321 .bcx
322 .scrape_units_have_dep_on(unit)
323 .into_iter()
324 .map(|unit| unit.target.description_named())
325 .collect::<Vec<_>>();
326 for_scrape_units.sort();
327 let for_scrape_units = for_scrape_units.join(", ");
328 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}"))
329 });
330 if hide_diagnostics_for_scrape_unit {
331 output_options.show_diagnostics = false;
332 }
333 let env_config = Arc::clone(build_runner.bcx.gctx.env_config()?);
334 return Ok(Work::new(move |state| {
335 if artifact.is_true() {
339 paths::create_dir_all(&root)?;
340 }
341
342 if let Some(build_scripts) = build_scripts {
350 let script_outputs = build_script_outputs.lock().unwrap();
351 if !build_plan {
352 add_native_deps(
353 &mut rustc,
354 &script_outputs,
355 &build_scripts,
356 pass_l_flag,
357 &target,
358 current_id,
359 )?;
360 add_plugin_deps(&mut rustc, &script_outputs, &build_scripts, &root_output)?;
361 }
362 add_custom_flags(&mut rustc, &script_outputs, script_metadata)?;
363 }
364
365 for output in outputs.iter() {
366 if output.path.extension() == Some(OsStr::new("rmeta")) {
370 let dst = root.join(&output.path).with_extension("rlib");
371 if dst.exists() {
372 paths::remove_file(&dst)?;
373 }
374 }
375
376 if output.hardlink.is_some() && output.path.exists() {
381 _ = paths::remove_file(&output.path).map_err(|e| {
382 tracing::debug!(
383 "failed to delete previous output file `{:?}`: {e:?}",
384 output.path
385 );
386 });
387 }
388 }
389
390 state.running(&rustc);
391 let timestamp = paths::set_invocation_time(&fingerprint_dir)?;
392 if build_plan {
393 state.build_plan(buildkey, rustc.clone(), outputs.clone());
394 } else {
395 let result = exec
396 .exec(
397 &rustc,
398 package_id,
399 &target,
400 mode,
401 &mut |line| on_stdout_line(state, line, package_id, &target),
402 &mut |line| {
403 on_stderr_line(
404 state,
405 line,
406 package_id,
407 &manifest_path,
408 &target,
409 &mut output_options,
410 )
411 },
412 )
413 .map_err(|e| {
414 if output_options.errors_seen == 0 {
415 e
420 } else {
421 verbose_if_simple_exit_code(e)
422 }
423 })
424 .with_context(|| {
425 let warnings = match output_options.warnings_seen {
427 0 => String::new(),
428 1 => "; 1 warning emitted".to_string(),
429 count => format!("; {} warnings emitted", count),
430 };
431 let errors = match output_options.errors_seen {
432 0 => String::new(),
433 1 => " due to 1 previous error".to_string(),
434 count => format!(" due to {} previous errors", count),
435 };
436 let name = descriptive_pkg_name(&name, &target, &mode);
437 format!("could not compile {name}{errors}{warnings}")
438 });
439
440 if let Err(e) = result {
441 if let Some(diagnostic) = failed_scrape_diagnostic {
442 state.warning(diagnostic)?;
443 }
444
445 return Err(e);
446 }
447
448 debug_assert_eq!(output_options.errors_seen, 0);
450 }
451
452 if rustc_dep_info_loc.exists() {
453 fingerprint::translate_dep_info(
454 &rustc_dep_info_loc,
455 &dep_info_loc,
456 &cwd,
457 &pkg_root,
458 &target_dir,
459 &rustc,
460 is_local,
462 &env_config,
463 )
464 .with_context(|| {
465 internal(format!(
466 "could not parse/generate dep info at: {}",
467 rustc_dep_info_loc.display()
468 ))
469 })?;
470 paths::set_file_time_no_err(dep_info_loc, timestamp);
473 }
474
475 Ok(())
476 }));
477
478 fn add_native_deps(
481 rustc: &mut ProcessBuilder,
482 build_script_outputs: &BuildScriptOutputs,
483 build_scripts: &BuildScripts,
484 pass_l_flag: bool,
485 target: &Target,
486 current_id: PackageId,
487 ) -> CargoResult<()> {
488 for key in build_scripts.to_link.iter() {
489 let output = build_script_outputs.get(key.1).ok_or_else(|| {
490 internal(format!(
491 "couldn't find build script output for {}/{}",
492 key.0, key.1
493 ))
494 })?;
495 for path in output.library_paths.iter() {
496 rustc.arg("-L").arg(path);
497 }
498
499 if key.0 == current_id {
500 if pass_l_flag {
501 for name in output.library_links.iter() {
502 rustc.arg("-l").arg(name);
503 }
504 }
505 }
506
507 for (lt, arg) in &output.linker_args {
508 if lt.applies_to(target) && (key.0 == current_id || *lt == LinkArgTarget::Cdylib) {
514 rustc.arg("-C").arg(format!("link-arg={}", arg));
515 }
516 }
517 }
518 Ok(())
519 }
520}
521
522fn verbose_if_simple_exit_code(err: Error) -> Error {
523 match err
526 .downcast_ref::<ProcessError>()
527 .as_ref()
528 .and_then(|perr| perr.code)
529 {
530 Some(n) if cargo_util::is_simple_exit_code(n) => VerboseError::new(err).into(),
531 _ => err,
532 }
533}
534
535fn link_targets(
538 build_runner: &mut BuildRunner<'_, '_>,
539 unit: &Unit,
540 fresh: bool,
541) -> CargoResult<Work> {
542 let bcx = build_runner.bcx;
543 let outputs = build_runner.outputs(unit)?;
544 let export_dir = build_runner.files().export_dir();
545 let package_id = unit.pkg.package_id();
546 let manifest_path = PathBuf::from(unit.pkg.manifest_path());
547 let profile = unit.profile.clone();
548 let unit_mode = unit.mode;
549 let features = unit.features.iter().map(|s| s.to_string()).collect();
550 let json_messages = bcx.build_config.emit_json();
551 let executable = build_runner.get_executable(unit)?;
552 let mut target = Target::clone(&unit.target);
553 if let TargetSourcePath::Metabuild = target.src_path() {
554 let path = unit
556 .pkg
557 .manifest()
558 .metabuild_path(build_runner.bcx.ws.target_dir());
559 target.set_src_path(TargetSourcePath::Path(path));
560 }
561
562 Ok(Work::new(move |state| {
563 let mut destinations = vec![];
568 for output in outputs.iter() {
569 let src = &output.path;
570 if !src.exists() {
573 continue;
574 }
575 let Some(dst) = output.hardlink.as_ref() else {
576 destinations.push(src.clone());
577 continue;
578 };
579 destinations.push(dst.clone());
580 paths::link_or_copy(src, dst)?;
581 if let Some(ref path) = output.export_path {
582 let export_dir = export_dir.as_ref().unwrap();
583 paths::create_dir_all(export_dir)?;
584
585 paths::link_or_copy(src, path)?;
586 }
587 }
588
589 if json_messages {
590 let debuginfo = match profile.debuginfo.into_inner() {
591 TomlDebugInfo::None => machine_message::ArtifactDebuginfo::Int(0),
592 TomlDebugInfo::Limited => machine_message::ArtifactDebuginfo::Int(1),
593 TomlDebugInfo::Full => machine_message::ArtifactDebuginfo::Int(2),
594 TomlDebugInfo::LineDirectivesOnly => {
595 machine_message::ArtifactDebuginfo::Named("line-directives-only")
596 }
597 TomlDebugInfo::LineTablesOnly => {
598 machine_message::ArtifactDebuginfo::Named("line-tables-only")
599 }
600 };
601 let art_profile = machine_message::ArtifactProfile {
602 opt_level: profile.opt_level.as_str(),
603 debuginfo: Some(debuginfo),
604 debug_assertions: profile.debug_assertions,
605 overflow_checks: profile.overflow_checks,
606 test: unit_mode.is_any_test(),
607 };
608
609 let msg = machine_message::Artifact {
610 package_id: package_id.to_spec(),
611 manifest_path,
612 target: &target,
613 profile: art_profile,
614 features,
615 filenames: destinations,
616 executable,
617 fresh,
618 }
619 .to_json_string();
620 state.stdout(msg)?;
621 }
622 Ok(())
623 }))
624}
625
626fn add_plugin_deps(
630 rustc: &mut ProcessBuilder,
631 build_script_outputs: &BuildScriptOutputs,
632 build_scripts: &BuildScripts,
633 root_output: &Path,
634) -> CargoResult<()> {
635 let var = paths::dylib_path_envvar();
636 let search_path = rustc.get_env(var).unwrap_or_default();
637 let mut search_path = env::split_paths(&search_path).collect::<Vec<_>>();
638 for (pkg_id, metadata) in &build_scripts.plugins {
639 let output = build_script_outputs
640 .get(*metadata)
641 .ok_or_else(|| internal(format!("couldn't find libs for plugin dep {}", pkg_id)))?;
642 search_path.append(&mut filter_dynamic_search_path(
643 output.library_paths.iter(),
644 root_output,
645 ));
646 }
647 let search_path = paths::join_paths(&search_path, var)?;
648 rustc.env(var, &search_path);
649 Ok(())
650}
651
652fn filter_dynamic_search_path<'a, I>(paths: I, root_output: &Path) -> Vec<PathBuf>
658where
659 I: Iterator<Item = &'a PathBuf>,
660{
661 let mut search_path = vec![];
662 for dir in paths {
663 let dir = match dir.to_str().and_then(|s| s.split_once("=")) {
664 Some(("native" | "crate" | "dependency" | "framework" | "all", path)) => path.into(),
665 _ => dir.clone(),
666 };
667 if dir.starts_with(&root_output) {
668 search_path.push(dir);
669 } else {
670 debug!(
671 "Not including path {} in runtime library search path because it is \
672 outside target root {}",
673 dir.display(),
674 root_output.display()
675 );
676 }
677 }
678 search_path
679}
680
681fn prepare_rustc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<ProcessBuilder> {
688 let is_primary = build_runner.is_primary_package(unit);
689 let is_workspace = build_runner.bcx.ws.is_member(&unit.pkg);
690
691 let mut base = build_runner
692 .compilation
693 .rustc_process(unit, is_primary, is_workspace)?;
694 build_base_args(build_runner, &mut base, unit)?;
695
696 base.inherit_jobserver(&build_runner.jobserver);
697 build_deps_args(&mut base, build_runner, unit)?;
698 add_cap_lints(build_runner.bcx, unit, &mut base);
699 if let Some(args) = build_runner.bcx.extra_args_for(unit) {
700 base.args(args);
701 }
702 base.args(&unit.rustflags);
703 if build_runner.bcx.gctx.cli_unstable().binary_dep_depinfo {
704 base.arg("-Z").arg("binary-dep-depinfo");
705 }
706 if build_runner.bcx.gctx.cli_unstable().checksum_freshness {
707 base.arg("-Z").arg("checksum-hash-algorithm=blake3");
708 }
709
710 if is_primary {
711 base.env("CARGO_PRIMARY_PACKAGE", "1");
712 }
713
714 if unit.target.is_test() || unit.target.is_bench() {
715 let tmp = build_runner.files().layout(unit.kind).prepare_tmp()?;
716 base.env("CARGO_TARGET_TMPDIR", tmp.display().to_string());
717 }
718
719 Ok(base)
720}
721
722fn prepare_rustdoc(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<ProcessBuilder> {
729 let bcx = build_runner.bcx;
730 let mut rustdoc = build_runner.compilation.rustdoc_process(unit, None)?;
732 rustdoc.inherit_jobserver(&build_runner.jobserver);
733 let crate_name = unit.target.crate_name();
734 rustdoc.arg("--crate-name").arg(&crate_name);
735 add_path_args(bcx.ws, unit, &mut rustdoc);
736 add_cap_lints(bcx, unit, &mut rustdoc);
737
738 if let CompileKind::Target(target) = unit.kind {
739 rustdoc.arg("--target").arg(target.rustc_target());
740 }
741 let doc_dir = build_runner.files().out_dir(unit);
742 rustdoc.arg("-o").arg(&doc_dir);
743 rustdoc.args(&features_args(unit));
744 rustdoc.args(&check_cfg_args(unit));
745
746 add_error_format_and_color(build_runner, &mut rustdoc);
747 add_allow_features(build_runner, &mut rustdoc);
748
749 if let Some(trim_paths) = unit.profile.trim_paths.as_ref() {
750 trim_paths_args_rustdoc(&mut rustdoc, build_runner, unit, trim_paths)?;
751 }
752
753 rustdoc.args(unit.pkg.manifest().lint_rustflags());
754
755 let metadata = build_runner.metadata_for_doc_units[unit];
756 rustdoc
757 .arg("-C")
758 .arg(format!("metadata={}", metadata.c_metadata()));
759
760 if unit.mode.is_doc_scrape() {
761 debug_assert!(build_runner.bcx.scrape_units.contains(unit));
762
763 if unit.target.is_test() {
764 rustdoc.arg("--scrape-tests");
765 }
766
767 rustdoc.arg("-Zunstable-options");
768
769 rustdoc
770 .arg("--scrape-examples-output-path")
771 .arg(scrape_output_path(build_runner, unit)?);
772
773 for pkg in build_runner.bcx.packages.packages() {
775 let names = pkg
776 .targets()
777 .iter()
778 .map(|target| target.crate_name())
779 .collect::<HashSet<_>>();
780 for name in names {
781 rustdoc.arg("--scrape-examples-target-crate").arg(name);
782 }
783 }
784 }
785
786 if should_include_scrape_units(build_runner.bcx, unit) {
787 rustdoc.arg("-Zunstable-options");
788 }
789
790 build_deps_args(&mut rustdoc, build_runner, unit)?;
791 rustdoc::add_root_urls(build_runner, unit, &mut rustdoc)?;
792
793 rustdoc::add_output_format(build_runner, unit, &mut rustdoc)?;
794
795 if let Some(args) = build_runner.bcx.extra_args_for(unit) {
796 rustdoc.args(args);
797 }
798 rustdoc.args(&unit.rustdocflags);
799
800 if !crate_version_flag_already_present(&rustdoc) {
801 append_crate_version_flag(unit, &mut rustdoc);
802 }
803
804 Ok(rustdoc)
805}
806
807fn rustdoc(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<Work> {
809 let mut rustdoc = prepare_rustdoc(build_runner, unit)?;
810
811 let crate_name = unit.target.crate_name();
812 let doc_dir = build_runner.files().out_dir(unit);
813 paths::create_dir_all(&doc_dir)?;
817
818 let target_desc = unit.target.description_named();
819 let name = unit.pkg.name();
820 let build_script_outputs = Arc::clone(&build_runner.build_script_outputs);
821 let package_id = unit.pkg.package_id();
822 let manifest_path = PathBuf::from(unit.pkg.manifest_path());
823 let target = Target::clone(&unit.target);
824 let mut output_options = OutputOptions::new(build_runner, unit);
825 let script_metadata = build_runner.find_build_script_metadata(unit);
826 let scrape_outputs = if should_include_scrape_units(build_runner.bcx, unit) {
827 Some(
828 build_runner
829 .bcx
830 .scrape_units
831 .iter()
832 .map(|unit| {
833 Ok((
834 build_runner.files().metadata(unit).unit_id(),
835 scrape_output_path(build_runner, unit)?,
836 ))
837 })
838 .collect::<CargoResult<HashMap<_, _>>>()?,
839 )
840 } else {
841 None
842 };
843
844 let failed_scrape_units = Arc::clone(&build_runner.failed_scrape_units);
845 let hide_diagnostics_for_scrape_unit = build_runner.bcx.unit_can_fail_for_docscraping(unit)
846 && !matches!(
847 build_runner.bcx.gctx.shell().verbosity(),
848 Verbosity::Verbose
849 );
850 let failed_scrape_diagnostic = hide_diagnostics_for_scrape_unit.then(|| {
851 make_failed_scrape_diagnostic(
852 build_runner,
853 unit,
854 format_args!("failed to scan {target_desc} in package `{name}` for example code usage"),
855 )
856 });
857 if hide_diagnostics_for_scrape_unit {
858 output_options.show_diagnostics = false;
859 }
860
861 Ok(Work::new(move |state| {
862 add_custom_flags(
863 &mut rustdoc,
864 &build_script_outputs.lock().unwrap(),
865 script_metadata,
866 )?;
867
868 if let Some(scrape_outputs) = scrape_outputs {
873 let failed_scrape_units = failed_scrape_units.lock().unwrap();
874 for (metadata, output_path) in &scrape_outputs {
875 if !failed_scrape_units.contains(metadata) {
876 rustdoc.arg("--with-examples").arg(output_path);
877 }
878 }
879 }
880
881 let crate_dir = doc_dir.join(&crate_name);
882 if crate_dir.exists() {
883 debug!("removing pre-existing doc directory {:?}", crate_dir);
886 paths::remove_dir_all(crate_dir)?;
887 }
888 state.running(&rustdoc);
889
890 let result = rustdoc
891 .exec_with_streaming(
892 &mut |line| on_stdout_line(state, line, package_id, &target),
893 &mut |line| {
894 on_stderr_line(
895 state,
896 line,
897 package_id,
898 &manifest_path,
899 &target,
900 &mut output_options,
901 )
902 },
903 false,
904 )
905 .map_err(verbose_if_simple_exit_code)
906 .with_context(|| format!("could not document `{}`", name));
907
908 if let Err(e) = result {
909 if let Some(diagnostic) = failed_scrape_diagnostic {
910 state.warning(diagnostic)?;
911 }
912
913 return Err(e);
914 }
915
916 Ok(())
917 }))
918}
919
920fn crate_version_flag_already_present(rustdoc: &ProcessBuilder) -> bool {
923 rustdoc.get_args().any(|flag| {
924 flag.to_str()
925 .map_or(false, |flag| flag.starts_with(RUSTDOC_CRATE_VERSION_FLAG))
926 })
927}
928
929fn append_crate_version_flag(unit: &Unit, rustdoc: &mut ProcessBuilder) {
930 rustdoc
931 .arg(RUSTDOC_CRATE_VERSION_FLAG)
932 .arg(unit.pkg.version().to_string());
933}
934
935fn add_cap_lints(bcx: &BuildContext<'_, '_>, unit: &Unit, cmd: &mut ProcessBuilder) {
939 if !unit.show_warnings(bcx.gctx) {
942 cmd.arg("--cap-lints").arg("allow");
943
944 } else if !unit.is_local() {
947 cmd.arg("--cap-lints").arg("warn");
948 }
949}
950
951fn add_allow_features(build_runner: &BuildRunner<'_, '_>, cmd: &mut ProcessBuilder) {
955 if let Some(allow) = &build_runner.bcx.gctx.cli_unstable().allow_features {
956 use std::fmt::Write;
957 let mut arg = String::from("-Zallow-features=");
958 for f in allow {
959 let _ = write!(&mut arg, "{f},");
960 }
961 cmd.arg(arg.trim_end_matches(','));
962 }
963}
964
965fn add_error_format_and_color(build_runner: &BuildRunner<'_, '_>, cmd: &mut ProcessBuilder) {
976 cmd.arg("--error-format=json");
977 let mut json = String::from("--json=diagnostic-rendered-ansi,artifacts,future-incompat");
978
979 match build_runner.bcx.build_config.message_format {
980 MessageFormat::Short | MessageFormat::Json { short: true, .. } => {
981 json.push_str(",diagnostic-short");
982 }
983 _ => {}
984 }
985 cmd.arg(json);
986
987 let gctx = build_runner.bcx.gctx;
988 if let Some(width) = gctx.shell().err_width().diagnostic_terminal_width() {
989 cmd.arg(format!("--diagnostic-width={width}"));
990 }
991}
992
993fn build_base_args(
995 build_runner: &BuildRunner<'_, '_>,
996 cmd: &mut ProcessBuilder,
997 unit: &Unit,
998) -> CargoResult<()> {
999 assert!(!unit.mode.is_run_custom_build());
1000
1001 let bcx = build_runner.bcx;
1002 let Profile {
1003 ref opt_level,
1004 codegen_backend,
1005 codegen_units,
1006 debuginfo,
1007 debug_assertions,
1008 split_debuginfo,
1009 overflow_checks,
1010 rpath,
1011 ref panic,
1012 incremental,
1013 strip,
1014 rustflags: profile_rustflags,
1015 trim_paths,
1016 ..
1017 } = unit.profile.clone();
1018 let test = unit.mode.is_any_test();
1019
1020 cmd.arg("--crate-name").arg(&unit.target.crate_name());
1021
1022 let edition = unit.target.edition();
1023 edition.cmd_edition_arg(cmd);
1024
1025 add_path_args(bcx.ws, unit, cmd);
1026 add_error_format_and_color(build_runner, cmd);
1027 add_allow_features(build_runner, cmd);
1028
1029 let mut contains_dy_lib = false;
1030 if !test {
1031 for crate_type in &unit.target.rustc_crate_types() {
1032 cmd.arg("--crate-type").arg(crate_type.as_str());
1033 contains_dy_lib |= crate_type == &CrateType::Dylib;
1034 }
1035 }
1036
1037 if unit.mode.is_check() {
1038 cmd.arg("--emit=dep-info,metadata");
1039 } else if !unit.requires_upstream_objects() {
1040 cmd.arg("--emit=dep-info,metadata,link");
1044 } else {
1045 cmd.arg("--emit=dep-info,link");
1046 }
1047
1048 let prefer_dynamic = (unit.target.for_host() && !unit.target.is_custom_build())
1049 || (contains_dy_lib && !build_runner.is_primary_package(unit));
1050 if prefer_dynamic {
1051 cmd.arg("-C").arg("prefer-dynamic");
1052 }
1053
1054 if opt_level.as_str() != "0" {
1055 cmd.arg("-C").arg(&format!("opt-level={}", opt_level));
1056 }
1057
1058 if *panic != PanicStrategy::Unwind {
1059 cmd.arg("-C").arg(format!("panic={}", panic));
1060 }
1061
1062 cmd.args(<o_args(build_runner, unit));
1063
1064 if let Some(backend) = codegen_backend {
1065 cmd.arg("-Z").arg(&format!("codegen-backend={}", backend));
1066 }
1067
1068 if let Some(n) = codegen_units {
1069 cmd.arg("-C").arg(&format!("codegen-units={}", n));
1070 }
1071
1072 let debuginfo = debuginfo.into_inner();
1073 if debuginfo != TomlDebugInfo::None {
1075 cmd.arg("-C").arg(format!("debuginfo={debuginfo}"));
1076 if let Some(split) = split_debuginfo {
1083 if build_runner
1084 .bcx
1085 .target_data
1086 .info(unit.kind)
1087 .supports_debuginfo_split(split)
1088 {
1089 cmd.arg("-C").arg(format!("split-debuginfo={split}"));
1090 }
1091 }
1092 }
1093
1094 if let Some(trim_paths) = trim_paths {
1095 trim_paths_args(cmd, build_runner, unit, &trim_paths)?;
1096 }
1097
1098 cmd.args(unit.pkg.manifest().lint_rustflags());
1099 cmd.args(&profile_rustflags);
1100
1101 if opt_level.as_str() != "0" {
1105 if debug_assertions {
1106 cmd.args(&["-C", "debug-assertions=on"]);
1107 if !overflow_checks {
1108 cmd.args(&["-C", "overflow-checks=off"]);
1109 }
1110 } else if overflow_checks {
1111 cmd.args(&["-C", "overflow-checks=on"]);
1112 }
1113 } else if !debug_assertions {
1114 cmd.args(&["-C", "debug-assertions=off"]);
1115 if overflow_checks {
1116 cmd.args(&["-C", "overflow-checks=on"]);
1117 }
1118 } else if !overflow_checks {
1119 cmd.args(&["-C", "overflow-checks=off"]);
1120 }
1121
1122 if test && unit.target.harness() {
1123 cmd.arg("--test");
1124
1125 if *panic == PanicStrategy::Abort {
1133 cmd.arg("-Z").arg("panic-abort-tests");
1134 }
1135 } else if test {
1136 cmd.arg("--cfg").arg("test");
1137 }
1138
1139 cmd.args(&features_args(unit));
1140 cmd.args(&check_cfg_args(unit));
1141
1142 let meta = build_runner.files().metadata(unit);
1143 cmd.arg("-C")
1144 .arg(&format!("metadata={}", meta.c_metadata()));
1145 if let Some(c_extra_filename) = meta.c_extra_filename() {
1146 cmd.arg("-C")
1147 .arg(&format!("extra-filename=-{c_extra_filename}"));
1148 }
1149
1150 if rpath {
1151 cmd.arg("-C").arg("rpath");
1152 }
1153
1154 cmd.arg("--out-dir")
1155 .arg(&build_runner.files().out_dir(unit));
1156
1157 fn opt(cmd: &mut ProcessBuilder, key: &str, prefix: &str, val: Option<&OsStr>) {
1158 if let Some(val) = val {
1159 let mut joined = OsString::from(prefix);
1160 joined.push(val);
1161 cmd.arg(key).arg(joined);
1162 }
1163 }
1164
1165 if let CompileKind::Target(n) = unit.kind {
1166 cmd.arg("--target").arg(n.rustc_target());
1167 }
1168
1169 opt(
1170 cmd,
1171 "-C",
1172 "linker=",
1173 build_runner
1174 .compilation
1175 .target_linker(unit.kind)
1176 .as_ref()
1177 .map(|s| s.as_ref()),
1178 );
1179 if incremental {
1180 let dir = build_runner
1181 .files()
1182 .layout(unit.kind)
1183 .incremental()
1184 .as_os_str();
1185 opt(cmd, "-C", "incremental=", Some(dir));
1186 }
1187
1188 let strip = strip.into_inner();
1189 if strip != StripInner::None {
1190 cmd.arg("-C").arg(format!("strip={}", strip));
1191 }
1192
1193 if unit.is_std {
1194 cmd.arg("-Z")
1200 .arg("force-unstable-if-unmarked")
1201 .env("RUSTC_BOOTSTRAP", "1");
1202 }
1203
1204 if unit.target.is_test() || unit.target.is_bench() {
1206 for bin_target in unit
1207 .pkg
1208 .manifest()
1209 .targets()
1210 .iter()
1211 .filter(|target| target.is_bin())
1212 {
1213 let exe_path = build_runner.files().bin_link_for_target(
1214 bin_target,
1215 unit.kind,
1216 build_runner.bcx,
1217 )?;
1218 let name = bin_target
1219 .binary_filename()
1220 .unwrap_or(bin_target.name().to_string());
1221 let key = format!("CARGO_BIN_EXE_{}", name);
1222 cmd.env(&key, exe_path);
1223 }
1224 }
1225 Ok(())
1226}
1227
1228fn features_args(unit: &Unit) -> Vec<OsString> {
1230 let mut args = Vec::with_capacity(unit.features.len() * 2);
1231
1232 for feat in &unit.features {
1233 args.push(OsString::from("--cfg"));
1234 args.push(OsString::from(format!("feature=\"{}\"", feat)));
1235 }
1236
1237 args
1238}
1239
1240fn trim_paths_args_rustdoc(
1242 cmd: &mut ProcessBuilder,
1243 build_runner: &BuildRunner<'_, '_>,
1244 unit: &Unit,
1245 trim_paths: &TomlTrimPaths,
1246) -> CargoResult<()> {
1247 match trim_paths {
1248 TomlTrimPaths::Values(values) if !values.contains(&TomlTrimPathsValue::Diagnostics) => {
1250 return Ok(())
1251 }
1252 _ => {}
1253 }
1254
1255 cmd.arg("-Zunstable-options");
1257
1258 cmd.arg(package_remap(build_runner, unit));
1261 cmd.arg(sysroot_remap(build_runner, unit));
1262
1263 Ok(())
1264}
1265
1266fn trim_paths_args(
1272 cmd: &mut ProcessBuilder,
1273 build_runner: &BuildRunner<'_, '_>,
1274 unit: &Unit,
1275 trim_paths: &TomlTrimPaths,
1276) -> CargoResult<()> {
1277 if trim_paths.is_none() {
1278 return Ok(());
1279 }
1280
1281 cmd.arg("-Zunstable-options");
1283 cmd.arg(format!("-Zremap-path-scope={trim_paths}"));
1284
1285 cmd.arg(package_remap(build_runner, unit));
1288 cmd.arg(sysroot_remap(build_runner, unit));
1289
1290 Ok(())
1291}
1292
1293fn sysroot_remap(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OsString {
1298 let mut remap = OsString::from("--remap-path-prefix=");
1299 remap.push({
1300 let mut sysroot = build_runner.bcx.target_data.info(unit.kind).sysroot.clone();
1302 sysroot.push("lib");
1303 sysroot.push("rustlib");
1304 sysroot.push("src");
1305 sysroot.push("rust");
1306 sysroot
1307 });
1308 remap.push("=");
1309 remap.push("/rustc/");
1310 if let Some(commit_hash) = build_runner.bcx.rustc().commit_hash.as_ref() {
1311 remap.push(commit_hash);
1312 } else {
1313 remap.push(build_runner.bcx.rustc().version.to_string());
1314 }
1315 remap
1316}
1317
1318fn package_remap(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OsString {
1326 let pkg_root = unit.pkg.root();
1327 let ws_root = build_runner.bcx.ws.root();
1328 let mut remap = OsString::from("--remap-path-prefix=");
1329 let source_id = unit.pkg.package_id().source_id();
1330 if source_id.is_git() {
1331 remap.push(
1332 build_runner
1333 .bcx
1334 .gctx
1335 .git_checkouts_path()
1336 .as_path_unlocked(),
1337 );
1338 remap.push("=");
1339 } else if source_id.is_registry() {
1340 remap.push(
1341 build_runner
1342 .bcx
1343 .gctx
1344 .registry_source_path()
1345 .as_path_unlocked(),
1346 );
1347 remap.push("=");
1348 } else if pkg_root.strip_prefix(ws_root).is_ok() {
1349 remap.push(ws_root);
1350 remap.push("=."); } else {
1352 remap.push(pkg_root);
1353 remap.push("=");
1354 remap.push(unit.pkg.name());
1355 remap.push("-");
1356 remap.push(unit.pkg.version().to_string());
1357 }
1358 remap
1359}
1360
1361fn check_cfg_args(unit: &Unit) -> Vec<OsString> {
1363 let gross_cap_estimation = unit.pkg.summary().features().len() * 7 + 25;
1381 let mut arg_feature = OsString::with_capacity(gross_cap_estimation);
1382
1383 arg_feature.push("cfg(feature, values(");
1384 for (i, feature) in unit.pkg.summary().features().keys().enumerate() {
1385 if i != 0 {
1386 arg_feature.push(", ");
1387 }
1388 arg_feature.push("\"");
1389 arg_feature.push(feature);
1390 arg_feature.push("\"");
1391 }
1392 arg_feature.push("))");
1393
1394 vec![
1403 OsString::from("--check-cfg"),
1404 OsString::from("cfg(docsrs,test)"),
1405 OsString::from("--check-cfg"),
1406 arg_feature,
1407 ]
1408}
1409
1410fn lto_args(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> Vec<OsString> {
1412 let mut result = Vec::new();
1413 let mut push = |arg: &str| {
1414 result.push(OsString::from("-C"));
1415 result.push(OsString::from(arg));
1416 };
1417 match build_runner.lto[unit] {
1418 lto::Lto::Run(None) => push("lto"),
1419 lto::Lto::Run(Some(s)) => push(&format!("lto={}", s)),
1420 lto::Lto::Off => {
1421 push("lto=off");
1422 push("embed-bitcode=no");
1423 }
1424 lto::Lto::ObjectAndBitcode => {} lto::Lto::OnlyBitcode => push("linker-plugin-lto"),
1426 lto::Lto::OnlyObject => push("embed-bitcode=no"),
1427 }
1428 result
1429}
1430
1431fn build_deps_args(
1437 cmd: &mut ProcessBuilder,
1438 build_runner: &BuildRunner<'_, '_>,
1439 unit: &Unit,
1440) -> CargoResult<()> {
1441 let bcx = build_runner.bcx;
1442 cmd.arg("-L").arg(&{
1443 let mut deps = OsString::from("dependency=");
1444 deps.push(build_runner.files().deps_dir(unit));
1445 deps
1446 });
1447
1448 if !unit.kind.is_host() {
1451 cmd.arg("-L").arg(&{
1452 let mut deps = OsString::from("dependency=");
1453 deps.push(build_runner.files().host_deps());
1454 deps
1455 });
1456 }
1457
1458 let deps = build_runner.unit_deps(unit);
1459
1460 if !deps
1464 .iter()
1465 .any(|dep| !dep.unit.mode.is_doc() && dep.unit.target.is_linkable())
1466 {
1467 if let Some(dep) = deps.iter().find(|dep| {
1468 !dep.unit.mode.is_doc() && dep.unit.target.is_lib() && !dep.unit.artifact.is_true()
1469 }) {
1470 bcx.gctx.shell().warn(format!(
1471 "The package `{}` \
1472 provides no linkable target. The compiler might raise an error while compiling \
1473 `{}`. Consider adding 'dylib' or 'rlib' to key `crate-type` in `{}`'s \
1474 Cargo.toml. This warning might turn into a hard error in the future.",
1475 dep.unit.target.crate_name(),
1476 unit.target.crate_name(),
1477 dep.unit.target.crate_name()
1478 ))?;
1479 }
1480 }
1481
1482 let mut unstable_opts = false;
1483
1484 for dep in deps {
1485 if dep.unit.mode.is_run_custom_build() {
1486 cmd.env(
1487 "OUT_DIR",
1488 &build_runner.files().build_script_out_dir(&dep.unit),
1489 );
1490 }
1491 }
1492
1493 for arg in extern_args(build_runner, unit, &mut unstable_opts)? {
1494 cmd.arg(arg);
1495 }
1496
1497 for (var, env) in artifact::get_env(build_runner, deps)? {
1498 cmd.env(&var, env);
1499 }
1500
1501 if unstable_opts {
1504 cmd.arg("-Z").arg("unstable-options");
1505 }
1506
1507 Ok(())
1508}
1509
1510fn add_custom_flags(
1514 cmd: &mut ProcessBuilder,
1515 build_script_outputs: &BuildScriptOutputs,
1516 metadata: Option<UnitHash>,
1517) -> CargoResult<()> {
1518 if let Some(metadata) = metadata {
1519 if let Some(output) = build_script_outputs.get(metadata) {
1520 for cfg in output.cfgs.iter() {
1521 cmd.arg("--cfg").arg(cfg);
1522 }
1523 for check_cfg in &output.check_cfgs {
1524 cmd.arg("--check-cfg").arg(check_cfg);
1525 }
1526 for (name, value) in output.env.iter() {
1527 cmd.env(name, value);
1528 }
1529 }
1530 }
1531
1532 Ok(())
1533}
1534
1535pub fn extern_args(
1537 build_runner: &BuildRunner<'_, '_>,
1538 unit: &Unit,
1539 unstable_opts: &mut bool,
1540) -> CargoResult<Vec<OsString>> {
1541 let mut result = Vec::new();
1542 let deps = build_runner.unit_deps(unit);
1543
1544 let mut link_to =
1546 |dep: &UnitDep, extern_crate_name: InternedString, noprelude: bool| -> CargoResult<()> {
1547 let mut value = OsString::new();
1548 let mut opts = Vec::new();
1549 let is_public_dependency_enabled = unit
1550 .pkg
1551 .manifest()
1552 .unstable_features()
1553 .require(Feature::public_dependency())
1554 .is_ok()
1555 || build_runner.bcx.gctx.cli_unstable().public_dependency;
1556 if !dep.public && unit.target.is_lib() && is_public_dependency_enabled {
1557 opts.push("priv");
1558 *unstable_opts = true;
1559 }
1560 if noprelude {
1561 opts.push("noprelude");
1562 *unstable_opts = true;
1563 }
1564 if !opts.is_empty() {
1565 value.push(opts.join(","));
1566 value.push(":");
1567 }
1568 value.push(extern_crate_name.as_str());
1569 value.push("=");
1570
1571 let mut pass = |file| {
1572 let mut value = value.clone();
1573 value.push(file);
1574 result.push(OsString::from("--extern"));
1575 result.push(value);
1576 };
1577
1578 let outputs = build_runner.outputs(&dep.unit)?;
1579
1580 if build_runner.only_requires_rmeta(unit, &dep.unit) || dep.unit.mode.is_check() {
1581 let output = outputs
1583 .iter()
1584 .find(|output| output.flavor == FileFlavor::Rmeta)
1585 .expect("failed to find rmeta dep for pipelined dep");
1586 pass(&output.path);
1587 } else {
1588 for output in outputs.iter() {
1590 if output.flavor == FileFlavor::Linkable {
1591 pass(&output.path);
1592 }
1593 }
1594 }
1595 Ok(())
1596 };
1597
1598 for dep in deps {
1599 if dep.unit.target.is_linkable() && !dep.unit.mode.is_doc() {
1600 link_to(dep, dep.extern_crate_name, dep.noprelude)?;
1601 }
1602 }
1603 if unit.target.proc_macro() {
1604 result.push(OsString::from("--extern"));
1606 result.push(OsString::from("proc_macro"));
1607 }
1608
1609 Ok(result)
1610}
1611
1612fn envify(s: &str) -> String {
1613 s.chars()
1614 .flat_map(|c| c.to_uppercase())
1615 .map(|c| if c == '-' { '_' } else { c })
1616 .collect()
1617}
1618
1619struct OutputOptions {
1622 format: MessageFormat,
1624 cache_cell: Option<(PathBuf, LazyCell<File>)>,
1629 show_diagnostics: bool,
1637 warnings_seen: usize,
1639 errors_seen: usize,
1641}
1642
1643impl OutputOptions {
1644 fn new(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> OutputOptions {
1645 let path = build_runner.files().message_cache_path(unit);
1646 drop(fs::remove_file(&path));
1648 let cache_cell = Some((path, LazyCell::new()));
1649 let show_diagnostics =
1650 build_runner.bcx.gctx.warning_handling().unwrap_or_default() != WarningHandling::Allow;
1651 OutputOptions {
1652 format: build_runner.bcx.build_config.message_format,
1653 cache_cell,
1654 show_diagnostics,
1655 warnings_seen: 0,
1656 errors_seen: 0,
1657 }
1658 }
1659}
1660
1661fn on_stdout_line(
1662 state: &JobState<'_, '_>,
1663 line: &str,
1664 _package_id: PackageId,
1665 _target: &Target,
1666) -> CargoResult<()> {
1667 state.stdout(line.to_string())?;
1668 Ok(())
1669}
1670
1671fn on_stderr_line(
1672 state: &JobState<'_, '_>,
1673 line: &str,
1674 package_id: PackageId,
1675 manifest_path: &std::path::Path,
1676 target: &Target,
1677 options: &mut OutputOptions,
1678) -> CargoResult<()> {
1679 if on_stderr_line_inner(state, line, package_id, manifest_path, target, options)? {
1680 if let Some((path, cell)) = &mut options.cache_cell {
1682 let f = cell.try_borrow_mut_with(|| paths::create(path))?;
1684 debug_assert!(!line.contains('\n'));
1685 f.write_all(line.as_bytes())?;
1686 f.write_all(&[b'\n'])?;
1687 }
1688 }
1689 Ok(())
1690}
1691
1692fn on_stderr_line_inner(
1694 state: &JobState<'_, '_>,
1695 line: &str,
1696 package_id: PackageId,
1697 manifest_path: &std::path::Path,
1698 target: &Target,
1699 options: &mut OutputOptions,
1700) -> CargoResult<bool> {
1701 if !line.starts_with('{') {
1707 state.stderr(line.to_string())?;
1708 return Ok(true);
1709 }
1710
1711 let mut compiler_message: Box<serde_json::value::RawValue> = match serde_json::from_str(line) {
1712 Ok(msg) => msg,
1713
1714 Err(e) => {
1718 debug!("failed to parse json: {:?}", e);
1719 state.stderr(line.to_string())?;
1720 return Ok(true);
1721 }
1722 };
1723
1724 let count_diagnostic = |level, options: &mut OutputOptions| {
1725 if level == "warning" {
1726 options.warnings_seen += 1;
1727 } else if level == "error" {
1728 options.errors_seen += 1;
1729 }
1730 };
1731
1732 if let Ok(report) = serde_json::from_str::<FutureIncompatReport>(compiler_message.get()) {
1733 for item in &report.future_incompat_report {
1734 count_diagnostic(&*item.diagnostic.level, options);
1735 }
1736 state.future_incompat_report(report.future_incompat_report);
1737 return Ok(true);
1738 }
1739
1740 match options.format {
1743 MessageFormat::Human
1748 | MessageFormat::Short
1749 | MessageFormat::Json {
1750 render_diagnostics: true,
1751 ..
1752 } => {
1753 #[derive(serde::Deserialize)]
1754 struct CompilerMessage<'a> {
1755 rendered: String,
1759 #[serde(borrow)]
1760 message: Cow<'a, str>,
1761 #[serde(borrow)]
1762 level: Cow<'a, str>,
1763 children: Vec<PartialDiagnostic>,
1764 }
1765
1766 #[derive(serde::Deserialize)]
1775 struct PartialDiagnostic {
1776 spans: Vec<PartialDiagnosticSpan>,
1777 }
1778
1779 #[derive(serde::Deserialize)]
1781 struct PartialDiagnosticSpan {
1782 suggestion_applicability: Option<Applicability>,
1783 }
1784
1785 if let Ok(mut msg) = serde_json::from_str::<CompilerMessage<'_>>(compiler_message.get())
1786 {
1787 if msg.message.starts_with("aborting due to")
1788 || msg.message.ends_with("warning emitted")
1789 || msg.message.ends_with("warnings emitted")
1790 {
1791 return Ok(true);
1793 }
1794 if msg.rendered.ends_with('\n') {
1796 msg.rendered.pop();
1797 }
1798 let rendered = msg.rendered;
1799 if options.show_diagnostics {
1800 let machine_applicable: bool = msg
1801 .children
1802 .iter()
1803 .map(|child| {
1804 child
1805 .spans
1806 .iter()
1807 .filter_map(|span| span.suggestion_applicability)
1808 .any(|app| app == Applicability::MachineApplicable)
1809 })
1810 .any(|b| b);
1811 count_diagnostic(&msg.level, options);
1812 state.emit_diag(&msg.level, rendered, machine_applicable)?;
1813 }
1814 return Ok(true);
1815 }
1816 }
1817
1818 MessageFormat::Json { ansi: false, .. } => {
1822 #[derive(serde::Deserialize, serde::Serialize)]
1823 struct CompilerMessage<'a> {
1824 rendered: String,
1825 #[serde(flatten, borrow)]
1826 other: std::collections::BTreeMap<Cow<'a, str>, serde_json::Value>,
1827 }
1828 if let Ok(mut error) =
1829 serde_json::from_str::<CompilerMessage<'_>>(compiler_message.get())
1830 {
1831 error.rendered = anstream::adapter::strip_str(&error.rendered).to_string();
1832 let new_line = serde_json::to_string(&error)?;
1833 compiler_message = serde_json::value::RawValue::from_string(new_line)?;
1834 }
1835 }
1836
1837 MessageFormat::Json { ansi: true, .. } => {}
1840 }
1841
1842 #[derive(serde::Deserialize)]
1849 struct ArtifactNotification<'a> {
1850 #[serde(borrow)]
1851 artifact: Cow<'a, str>,
1852 }
1853
1854 if let Ok(artifact) = serde_json::from_str::<ArtifactNotification<'_>>(compiler_message.get()) {
1855 trace!("found directive from rustc: `{}`", artifact.artifact);
1856 if artifact.artifact.ends_with(".rmeta") {
1857 debug!("looks like metadata finished early!");
1858 state.rmeta_produced();
1859 }
1860 return Ok(false);
1861 }
1862
1863 if !options.show_diagnostics {
1868 return Ok(true);
1869 }
1870
1871 #[derive(serde::Deserialize)]
1872 struct CompilerMessage<'a> {
1873 #[serde(borrow)]
1874 message: Cow<'a, str>,
1875 #[serde(borrow)]
1876 level: Cow<'a, str>,
1877 }
1878
1879 if let Ok(msg) = serde_json::from_str::<CompilerMessage<'_>>(compiler_message.get()) {
1880 if msg.message.starts_with("aborting due to")
1881 || msg.message.ends_with("warning emitted")
1882 || msg.message.ends_with("warnings emitted")
1883 {
1884 return Ok(true);
1886 }
1887 count_diagnostic(&msg.level, options);
1888 }
1889
1890 let msg = machine_message::FromCompiler {
1891 package_id: package_id.to_spec(),
1892 manifest_path,
1893 target,
1894 message: compiler_message,
1895 }
1896 .to_json_string();
1897
1898 state.stdout(msg)?;
1902 Ok(true)
1903}
1904
1905fn replay_output_cache(
1909 package_id: PackageId,
1910 manifest_path: PathBuf,
1911 target: &Target,
1912 path: PathBuf,
1913 format: MessageFormat,
1914 show_diagnostics: bool,
1915) -> Work {
1916 let target = target.clone();
1917 let mut options = OutputOptions {
1918 format,
1919 cache_cell: None,
1920 show_diagnostics,
1921 warnings_seen: 0,
1922 errors_seen: 0,
1923 };
1924 Work::new(move |state| {
1925 if !path.exists() {
1926 return Ok(());
1928 }
1929 let file = paths::open(&path)?;
1933 let mut reader = std::io::BufReader::new(file);
1934 let mut line = String::new();
1935 loop {
1936 let length = reader.read_line(&mut line)?;
1937 if length == 0 {
1938 break;
1939 }
1940 let trimmed = line.trim_end_matches(&['\n', '\r'][..]);
1941 on_stderr_line(
1942 state,
1943 trimmed,
1944 package_id,
1945 &manifest_path,
1946 &target,
1947 &mut options,
1948 )?;
1949 line.clear();
1950 }
1951 Ok(())
1952 })
1953}
1954
1955fn descriptive_pkg_name(name: &str, target: &Target, mode: &CompileMode) -> String {
1958 let desc_name = target.description_named();
1959 let mode = if mode.is_rustc_test() && !(target.is_test() || target.is_bench()) {
1960 " test"
1961 } else if mode.is_doc_test() {
1962 " doctest"
1963 } else if mode.is_doc() {
1964 " doc"
1965 } else {
1966 ""
1967 };
1968 format!("`{name}` ({desc_name}{mode})")
1969}
1970
1971pub(crate) fn apply_env_config(
1973 gctx: &crate::GlobalContext,
1974 cmd: &mut ProcessBuilder,
1975) -> CargoResult<()> {
1976 for (key, value) in gctx.env_config()?.iter() {
1977 if cmd.get_envs().contains_key(key) {
1979 continue;
1980 }
1981 cmd.env(key, value);
1982 }
1983 Ok(())
1984}
1985
1986fn should_include_scrape_units(bcx: &BuildContext<'_, '_>, unit: &Unit) -> bool {
1988 unit.mode.is_doc() && bcx.scrape_units.len() > 0 && bcx.ws.unit_needs_doc_scrape(unit)
1989}
1990
1991fn scrape_output_path(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<PathBuf> {
1993 assert!(unit.mode.is_doc() || unit.mode.is_doc_scrape());
1994 build_runner
1995 .outputs(unit)
1996 .map(|outputs| outputs[0].path.clone())
1997}