#
cargo/core/compiler/
artifact.rs

    1//! Generate artifact information from unit dependencies for configuring the compiler environment.
    2
    3use 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
    11/// Return all environment variables for the given unit-dependencies
    12/// if artifacts are present.
    13pub 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            // In older releases, lib-targets defaulted to the name of the package. Newer releases
    40            // use the same name as default, but with dashes replaced. Hence, if the name of the
    41            // target was inferred by Cargo, we also set the env-var with the unconverted name for
    42            // backwards compatibility.
    43            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 the name of the target matches the name of the dependency, we strip the
    59            // repetition and provide the simpler env-var as well.
    60            // For backwards-compatibility of inferred names, we compare against the name of the
    61            // package as well, since that used to be the default for library targets.
    62            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
    85/// Given a dependency with an artifact `artifact_dep` and a set of available `targets`
    86/// of its package, find a target for each kind of artifacts that are to be built.
    87///
    88/// Failure to match any target results in an error mentioning the parent manifests
    89/// `parent_package` name.
    90pub(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}