cargo/core/compiler/
artifact.rs1use crate::core::compiler::unit_graph::UnitDep;
4use crate::core::compiler::{BuildRunner, CrateType, FileFlavor, Unit};
5use crate::core::dependency::ArtifactKind;
6use crate::core::{Dependency, Target, TargetKind};
7use crate::CargoResult;
8use std::collections::{HashMap, HashSet};
9use std::ffi::OsString;
10
11pub fn get_env(
14 build_runner: &BuildRunner<'_, '_>,
15 dependencies: &[UnitDep],
16) -> CargoResult<HashMap<String, OsString>> {
17 let mut env = HashMap::new();
18 for unit_dep in dependencies.iter().filter(|d| d.unit.artifact.is_true()) {
19 for artifact_path in build_runner
20 .outputs(&unit_dep.unit)?
21 .iter()
22 .filter_map(|f| (f.flavor == FileFlavor::Normal).then(|| &f.path))
23 {
24 let artifact_type_upper = unit_artifact_type_name_upper(&unit_dep.unit);
25 let dep_name = unit_dep.dep_name.unwrap_or(unit_dep.unit.pkg.name());
26 let dep_name_upper = dep_name.to_uppercase().replace("-", "_");
27
28 let var = format!("CARGO_{}_DIR_{}", artifact_type_upper, dep_name_upper);
29 let path = artifact_path.parent().expect("parent dir for artifacts");
30 env.insert(var, path.to_owned().into());
31
32 let var_file = format!(
33 "CARGO_{}_FILE_{}_{}",
34 artifact_type_upper,
35 dep_name_upper,
36 unit_dep.unit.target.name()
37 );
38
39 let need_compat = unit_dep.unit.target.is_lib() && unit_dep.unit.target.name_inferred();
44 if need_compat {
45 let var_compat = format!(
46 "CARGO_{}_FILE_{}_{}",
47 artifact_type_upper,
48 dep_name_upper,
49 unit_dep.unit.pkg.name(),
50 );
51 if var_compat != var_file {
52 env.insert(var_compat, artifact_path.to_owned().into());
53 }
54 }
55
56 env.insert(var_file, artifact_path.to_owned().into());
57
58 if unit_dep.unit.target.name() == dep_name.as_str()
63 || (need_compat && unit_dep.unit.pkg.name() == dep_name.as_str())
64 {
65 let var = format!("CARGO_{}_FILE_{}", artifact_type_upper, dep_name_upper,);
66 env.insert(var, artifact_path.to_owned().into());
67 }
68 }
69 }
70 Ok(env)
71}
72
73fn unit_artifact_type_name_upper(unit: &Unit) -> &'static str {
74 match unit.target.kind() {
75 TargetKind::Lib(kinds) => match kinds.as_slice() {
76 &[CrateType::Cdylib] => "CDYLIB",
77 &[CrateType::Staticlib] => "STATICLIB",
78 invalid => unreachable!("BUG: artifacts cannot be of type {:?}", invalid),
79 },
80 TargetKind::Bin => "BIN",
81 invalid => unreachable!("BUG: artifacts cannot be of type {:?}", invalid),
82 }
83}
84
85pub(crate) fn match_artifacts_kind_with_targets<'t, 'd>(
91 artifact_dep: &'d Dependency,
92 targets: &'t [Target],
93 parent_package: &str,
94) -> CargoResult<HashSet<(&'d ArtifactKind, &'t Target)>> {
95 let mut out = HashSet::new();
96 let artifact_requirements = artifact_dep.artifact().expect("artifact present");
97 for artifact_kind in artifact_requirements.kinds() {
98 let mut extend = |kind, filter: &dyn Fn(&&Target) -> bool| {
99 let mut iter = targets.iter().filter(filter).peekable();
100 let found = iter.peek().is_some();
101 out.extend(std::iter::repeat(kind).zip(iter));
102 found
103 };
104 let found = match artifact_kind {
105 ArtifactKind::Cdylib => extend(artifact_kind, &|t| t.is_cdylib()),
106 ArtifactKind::Staticlib => extend(artifact_kind, &|t| t.is_staticlib()),
107 ArtifactKind::AllBinaries => extend(artifact_kind, &|t| t.is_bin()),
108 ArtifactKind::SelectedBinary(bin_name) => extend(artifact_kind, &|t| {
109 t.is_bin() && t.name() == bin_name.as_str()
110 }),
111 };
112 if !found {
113 anyhow::bail!(
114 "dependency `{}` in package `{}` requires a `{}` artifact to be present.",
115 artifact_dep.name_in_toml(),
116 parent_package,
117 artifact_kind
118 );
119 }
120 }
121 Ok(out)
122}