#
cargo/core/compiler/
links.rs

    1use super::unit_graph::UnitGraph;
    2use crate::core::resolver::errors::describe_path;
    3use crate::core::{PackageId, Resolve};
    4use crate::util::errors::CargoResult;
    5use std::collections::{HashMap, HashSet};
    6
    7/// Validates [`package.links`] field in the manifest file does not conflict
    8/// between packages.
    9///
    10/// NOTE: This is the *old* links validator. Links are usually validated in the
    11/// resolver. However, the `links` field was added to the index in early 2018
    12/// (see [rust-lang/cargo#4978]). However, `links` has been around since 2014,
    13/// so there are still many crates in the index that don't have `links`
    14/// properly set in the index (over 600 at the time of this writing in 2019).
    15/// This can probably be removed at some point in the future, though it might
    16/// be worth considering fixing the index.
    17///
    18/// [rust-lang/cargo#4978]: https://github.com/rust-lang/cargo/pull/4978
    19/// [`package.links`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#the-links-manifest-key
    20pub fn validate_links(resolve: &Resolve, unit_graph: &UnitGraph) -> CargoResult<()> {
    21    let mut validated: HashSet<PackageId> = HashSet::new();
    22    let mut links: HashMap<String, PackageId> = HashMap::new();
    23    let mut units: Vec<_> = unit_graph.keys().collect();
    24    // Sort primarily to make testing easier.
    25    units.sort_unstable();
    26    for unit in units {
    27        if !validated.insert(unit.pkg.package_id()) {
    28            continue;
    29        }
    30        let Some(lib) = unit.pkg.manifest().links() else {
    31            continue;
    32        };
    33        if let Some(&prev) = links.get(lib) {
    34            let prev_path = resolve
    35                .path_to_top(&prev)
    36                .into_iter()
    37                .map(|(p, d)| (p, d.and_then(|d| d.iter().next())));
    38            let pkg = unit.pkg.package_id();
    39            let path = resolve
    40                .path_to_top(&pkg)
    41                .into_iter()
    42                .map(|(p, d)| (p, d.and_then(|d| d.iter().next())));
    43            anyhow::bail!(
    44                "multiple packages link to native library `{}`, \
    45                 but a native library can be linked only once\n\
    46                 \n\
    47                 {}\nlinks to native library `{}`\n\
    48                 \n\
    49                 {}\nalso links to native library `{}`",
    50                lib,
    51                describe_path(prev_path),
    52                lib,
    53                describe_path(path),
    54                lib
    55            )
    56        }
    57        links.insert(lib.to_string(), unit.pkg.package_id());
    58    }
    59    Ok(())
    60}