cargo/core/compiler/
artifact.rs1use crate::CargoResult;
4use crate::core::compiler::unit_graph::UnitDep;
5use crate::core::compiler::{BuildRunner, CrateType, FileFlavor, Unit};
6use crate::core::dependency::ArtifactKind;
7use crate::core::{Dependency, Target, TargetKind};
8use std::collections::{HashMap, HashSet};
9use std::ffi::OsString;
10
11pub fn get_env(
14 build_runner: &BuildRunner<'_, '_>,
15 unit: &Unit,
16 dependencies: &[UnitDep],
17) -> CargoResult<HashMap<String, OsString>> {
18 let mut env = HashMap::new();
19
20 if unit.target.is_test() || unit.target.is_bench() {
24 for bin_target in unit
25 .pkg
26 .manifest()
27 .targets()
28 .iter()
29 .filter(|target| target.is_bin())
30 {
31 let name = bin_target
32 .binary_filename()
33 .unwrap_or_else(|| bin_target.name().to_string());
34
35 let exe_path = build_runner
39 .files()
40 .bin_link_for_target(bin_target, unit.kind, build_runner.bcx)?
41 .map(|path| path.as_os_str().to_os_string())
42 .unwrap_or_else(|| OsString::from(format!("placeholder:{name}")));
43
44 let key = format!("CARGO_BIN_EXE_{name}");
45 env.insert(key, exe_path);
46 }
47 }
48
49 for unit_dep in dependencies.iter().filter(|d| d.unit.artifact.is_true()) {
50 for artifact_path in build_runner
51 .outputs(&unit_dep.unit)?
52 .iter()
53 .filter_map(|f| (f.flavor == FileFlavor::Normal).then(|| &f.path))
54 {
55 let artifact_type_upper = unit_artifact_type_name_upper(&unit_dep.unit);
56 let dep_name = unit_dep.dep_name.unwrap_or(unit_dep.unit.pkg.name());
57 let dep_name_upper = dep_name.to_uppercase().replace("-", "_");
58
59 let var = format!("CARGO_{}_DIR_{}", artifact_type_upper, dep_name_upper);
60 let path = artifact_path.parent().expect("parent dir for artifacts");
61 env.insert(var, path.to_owned().into());
62
63 let var_file = format!(
64 "CARGO_{}_FILE_{}_{}",
65 artifact_type_upper,
66 dep_name_upper,
67 unit_dep.unit.target.name()
68 );
69
70 let need_compat = unit_dep.unit.target.is_lib() && unit_dep.unit.target.name_inferred();
75 if need_compat {
76 let var_compat = format!(
77 "CARGO_{}_FILE_{}_{}",
78 artifact_type_upper,
79 dep_name_upper,
80 unit_dep.unit.pkg.name(),
81 );
82 if var_compat != var_file {
83 env.insert(var_compat, artifact_path.to_owned().into());
84 }
85 }
86
87 env.insert(var_file, artifact_path.to_owned().into());
88
89 if unit_dep.unit.target.name() == dep_name.as_str()
94 || (need_compat && unit_dep.unit.pkg.name() == dep_name.as_str())
95 {
96 let var = format!("CARGO_{}_FILE_{}", artifact_type_upper, dep_name_upper,);
97 env.insert(var, artifact_path.to_owned().into());
98 }
99 }
100 }
101 Ok(env)
102}
103
104fn unit_artifact_type_name_upper(unit: &Unit) -> &'static str {
105 match unit.target.kind() {
106 TargetKind::Lib(kinds) => match kinds.as_slice() {
107 &[CrateType::Cdylib] => "CDYLIB",
108 &[CrateType::Staticlib] => "STATICLIB",
109 invalid => unreachable!("BUG: artifacts cannot be of type {:?}", invalid),
110 },
111 TargetKind::Bin => "BIN",
112 invalid => unreachable!("BUG: artifacts cannot be of type {:?}", invalid),
113 }
114}
115
116pub(crate) fn match_artifacts_kind_with_targets<'t, 'd>(
122 artifact_dep: &'d Dependency,
123 targets: &'t [Target],
124 parent_package: &str,
125) -> CargoResult<HashSet<(&'d ArtifactKind, &'t Target)>> {
126 let mut out = HashSet::new();
127 let artifact_requirements = artifact_dep.artifact().expect("artifact present");
128 for artifact_kind in artifact_requirements.kinds() {
129 let mut extend = |kind, filter: &dyn Fn(&&Target) -> bool| {
130 let mut iter = targets.iter().filter(filter).peekable();
131 let found = iter.peek().is_some();
132 out.extend(std::iter::repeat(kind).zip(iter));
133 found
134 };
135 let found = match artifact_kind {
136 ArtifactKind::Cdylib => extend(artifact_kind, &|t| t.is_cdylib()),
137 ArtifactKind::Staticlib => extend(artifact_kind, &|t| t.is_staticlib()),
138 ArtifactKind::AllBinaries => extend(artifact_kind, &|t| t.is_bin()),
139 ArtifactKind::SelectedBinary(bin_name) => extend(artifact_kind, &|t| {
140 t.is_bin() && t.name() == bin_name.as_str()
141 }),
142 };
143 if !found {
144 anyhow::bail!(
145 "dependency `{}` in package `{}` requires a `{}` artifact to be present.",
146 artifact_dep.name_in_toml(),
147 parent_package,
148 artifact_kind
149 );
150 }
151 }
152 Ok(out)
153}