cargo/compiler/
output_depinfo.rs1use crate::util::data_structures::HashSet;
5use cargo_util::paths::normalize_path;
6use std::collections::BTreeSet;
7use std::io::{BufWriter, Write};
8use std::path::{Path, PathBuf};
9
10use super::{BuildRunner, FileFlavor, Unit, fingerprint};
11use crate::util::{CargoResult, internal};
12use cargo_util::paths;
13use tracing::debug;
14
15fn render_filename<P: AsRef<Path>>(path: P, basedir: Option<&str>) -> CargoResult<String> {
17 fn wrap_path(path: &Path) -> CargoResult<String> {
18 path.to_str()
19 .ok_or_else(|| internal(format!("path `{:?}` not utf-8", path)))
20 .map(|f| f.replace(" ", "\\ "))
21 }
22
23 let path = path.as_ref();
24 if let Some(basedir) = basedir {
25 let norm_path = normalize_path(path);
26 let norm_basedir = normalize_path(basedir.as_ref());
27 match norm_path.strip_prefix(norm_basedir) {
28 Ok(relpath) => wrap_path(relpath),
29 _ => wrap_path(path),
30 }
31 } else {
32 wrap_path(path)
33 }
34}
35
36fn add_deps_for_unit(
46 deps: &mut BTreeSet<PathBuf>,
47 build_runner: &mut BuildRunner<'_, '_>,
48 unit: &Unit,
49 visited: &mut HashSet<Unit>,
50) -> CargoResult<()> {
51 if !visited.insert(unit.clone()) {
52 return Ok(());
53 }
54
55 if !unit.mode.is_run_custom_build() {
58 let dep_info_loc = fingerprint::dep_info_loc(build_runner, unit);
60 if let Some(paths) = fingerprint::parse_dep_info(
61 unit.pkg.root(),
62 build_runner.files().host_build_root(),
63 &dep_info_loc,
64 )? {
65 for path in paths.files.into_keys() {
66 deps.insert(path);
67 }
68 } else {
69 debug!(
70 "can't find dep_info for {:?} {}",
71 unit.pkg.package_id(),
72 unit.target
73 );
74 return Err(internal("dep_info missing"));
75 }
76 }
77
78 if let Some(metadata_vec) = build_runner.find_build_script_metadatas(unit) {
80 for metadata in metadata_vec {
81 if let Some(output) = build_runner
82 .build_script_outputs
83 .lock()
84 .unwrap()
85 .get(metadata)
86 {
87 for path in &output.rerun_if_changed {
88 let package_root = unit.pkg.root();
89
90 let path = if path.as_os_str().is_empty() {
91 package_root.to_path_buf()
94 } else {
95 package_root.join(path)
98 };
99
100 deps.insert(path);
101 }
102 }
103 }
104 }
105
106 let unit_deps = Vec::from(build_runner.unit_deps(unit)); for dep in unit_deps {
109 if dep.unit.is_local() {
110 add_deps_for_unit(deps, build_runner, &dep.unit, visited)?;
111 }
112 }
113 Ok(())
114}
115
116pub fn output_depinfo(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResult<()> {
134 let bcx = build_runner.bcx;
135 let mut deps = BTreeSet::new();
136 let mut visited = HashSet::default();
137 let success = add_deps_for_unit(&mut deps, build_runner, unit, &mut visited).is_ok();
138 let basedir_string;
139 let basedir = match bcx.gctx.build_config()?.dep_info_basedir.clone() {
140 Some(value) => {
141 basedir_string = value
142 .resolve_path(bcx.gctx)
143 .as_os_str()
144 .to_str()
145 .ok_or_else(|| anyhow::format_err!("build.dep-info-basedir path not utf-8"))?
146 .to_string();
147 Some(basedir_string.as_str())
148 }
149 None => None,
150 };
151 let deps = deps
152 .iter()
153 .map(|f| render_filename(f, basedir))
154 .collect::<CargoResult<Vec<_>>>()?;
155
156 for output in build_runner.outputs(unit)?.iter().filter(|o| {
157 !matches!(
158 o.flavor,
159 FileFlavor::DebugInfo | FileFlavor::Auxiliary | FileFlavor::Sbom
160 )
161 }) {
162 if let Some(ref link_dst) = output.hardlink {
163 let output_path = link_dst.with_extension("d");
164 if success {
165 let target_fn = render_filename(link_dst, basedir)?;
166
167 if let Ok(previous) = fingerprint::parse_rustc_dep_info(&output_path) {
170 if previous
171 .files
172 .iter()
173 .map(|(path, _checksum)| path)
174 .eq(deps.iter().map(Path::new))
175 {
176 continue;
177 }
178 }
179
180 let mut outfile = BufWriter::new(paths::create(output_path)?);
182 write!(outfile, "{}:", target_fn)?;
183 for dep in &deps {
184 write!(outfile, " {}", dep)?;
185 }
186 writeln!(outfile)?;
187
188 } else if output_path.exists() {
192 paths::remove_file(output_path)?;
193 }
194 }
195 }
196 Ok(())
197}