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 env.insert(var_file, artifact_path.to_owned().into());
70
71 if unit_dep.unit.target.name() == dep_name.as_str() {
76 let var = format!("CARGO_{}_FILE_{}", artifact_type_upper, dep_name_upper,);
77 env.insert(var, artifact_path.to_owned().into());
78 }
79 }
80 }
81 Ok(env)
82}
83
84fn unit_artifact_type_name_upper(unit: &Unit) -> &'static str {
85 match unit.target.kind() {
86 TargetKind::Lib(kinds) => match kinds.as_slice() {
87 &[CrateType::Cdylib] => "CDYLIB",
88 &[CrateType::Staticlib] => "STATICLIB",
89 invalid => unreachable!("BUG: artifacts cannot be of type {:?}", invalid),
90 },
91 TargetKind::Bin => "BIN",
92 invalid => unreachable!("BUG: artifacts cannot be of type {:?}", invalid),
93 }
94}
95
96pub(crate) fn match_artifacts_kind_with_targets<'t, 'd>(
102 artifact_dep: &'d Dependency,
103 targets: &'t [Target],
104 parent_package: &str,
105) -> CargoResult<HashSet<(&'d ArtifactKind, &'t Target)>> {
106 let mut out = HashSet::new();
107 let artifact_requirements = artifact_dep.artifact().expect("artifact present");
108 for artifact_kind in artifact_requirements.kinds() {
109 let mut extend = |kind, filter: &dyn Fn(&&Target) -> bool| {
110 let mut iter = targets.iter().filter(filter).peekable();
111 let found = iter.peek().is_some();
112 out.extend(std::iter::repeat(kind).zip(iter));
113 found
114 };
115 let found = match artifact_kind {
116 ArtifactKind::Cdylib => extend(artifact_kind, &|t| t.is_cdylib()),
117 ArtifactKind::Staticlib => extend(artifact_kind, &|t| t.is_staticlib()),
118 ArtifactKind::AllBinaries => extend(artifact_kind, &|t| t.is_bin()),
119 ArtifactKind::SelectedBinary(bin_name) => extend(artifact_kind, &|t| {
120 t.is_bin() && t.name() == bin_name.as_str()
121 }),
122 };
123 if !found {
124 anyhow::bail!(
125 "dependency `{}` in package `{}` requires a `{}` artifact to be present.",
126 artifact_dep.name_in_toml(),
127 parent_package,
128 artifact_kind
129 );
130 }
131 }
132 Ok(out)
133}