#
cargo/core/compiler/
unit_dependencies.rs

    1//! Constructs the dependency graph for compilation.
    2//!
    3//! Rust code is typically organized as a set of Cargo packages. The
    4//! dependencies between the packages themselves are stored in the
    5//! [`Resolve`] struct. However, we can't use that information as is for
    6//! compilation! A package typically contains several targets, or crates,
    7//! and these targets has inter-dependencies. For example, you need to
    8//! compile the `lib` target before the `bin` one, and you need to compile
    9//! `build.rs` before either of those.
    10//!
    11//! So, we need to lower the `Resolve`, which specifies dependencies between
    12//! *packages*, to a graph of dependencies between their *targets*, and this
    13//! is exactly what this module is doing! Well, almost exactly: another
    14//! complication is that we might want to compile the same target several times
    15//! (for example, with and without tests), so we actually build a dependency
    16//! graph of [`Unit`]s, which capture these properties.
    17
    18use std::collections::{HashMap, HashSet};
    19
    20use tracing::trace;
    21
    22use crate::CargoResult;
    23use crate::core::compiler::UserIntent;
    24use crate::core::compiler::artifact::match_artifacts_kind_with_targets;
    25use crate::core::compiler::unit_graph::{UnitDep, UnitGraph};
    26use crate::core::compiler::{
    27    CompileKind, CompileMode, CrateType, RustcTargetData, Unit, UnitInterner,
    28};
    29use crate::core::dependency::{Artifact, ArtifactKind, ArtifactTarget, DepKind};
    30use crate::core::profiles::{Profile, Profiles, UnitFor};
    31use crate::core::resolver::Resolve;
    32use crate::core::resolver::features::{FeaturesFor, ResolvedFeatures};
    33use crate::core::{
    34    Dependency, Feature, Package, PackageId, PackageSet, Target, TargetKind, Workspace,
    35};
    36use crate::ops::resolve_all_features;
    37use crate::util::GlobalContext;
    38use crate::util::interning::InternedString;
    39
    40const IS_NO_ARTIFACT_DEP: Option<&'static Artifact> = None;
    41
    42/// Collection of stuff used while creating the [`UnitGraph`].
    43struct State<'a, 'gctx> {
    44    ws: &'a Workspace<'gctx>,
    45    gctx: &'gctx GlobalContext,
    46    /// Stores the result of building the [`UnitGraph`].
    47    unit_dependencies: UnitGraph,
    48    package_set: &'a PackageSet<'gctx>,
    49    usr_resolve: &'a Resolve,
    50    usr_features: &'a ResolvedFeatures,
    51    /// Like `usr_resolve` but for building standard library (`-Zbuild-std`).
    52    std_resolve: Option<&'a Resolve>,
    53    /// Like `usr_features` but for building standard library (`-Zbuild-std`).
    54    std_features: Option<&'a ResolvedFeatures>,
    55    /// `true` while generating the dependencies for the standard library.
    56    is_std: bool,
    57    /// The high-level operation requested by the user.
    58    /// Used for preventing from building lib thrice.
    59    intent: UserIntent,
    60    target_data: &'a RustcTargetData<'gctx>,
    61    profiles: &'a Profiles,
    62    interner: &'a UnitInterner,
    63    // Units for `-Zrustdoc-scrape-examples`.
    64    scrape_units: &'a [Unit],
    65
    66    /// A set of edges in `unit_dependencies` where (a, b) means that the
    67    /// dependency from a to b was added purely because it was a dev-dependency.
    68    /// This is used during `connect_run_custom_build_deps`.
    69    dev_dependency_edges: HashSet<(Unit, Unit)>,
    70}
    71
    72/// A boolean-like to indicate if a `Unit` is an artifact or not.
    73#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
    74pub enum IsArtifact {
    75    Yes,
    76    No,
    77}
    78
    79impl IsArtifact {
    80    pub fn is_true(&self) -> bool {
    81        matches!(self, IsArtifact::Yes)
    82    }
    83}
    84
    85/// Then entry point for building a dependency graph of compilation units.
    86///
    87/// You can find some information for arguments from doc of [`State`].
    88#[tracing::instrument(skip_all)]
    89pub fn build_unit_dependencies<'a, 'gctx>(
    90    ws: &'a Workspace<'gctx>,
    91    package_set: &'a PackageSet<'gctx>,
    92    resolve: &'a Resolve,
    93    features: &'a ResolvedFeatures,
    94    std_resolve: Option<&'a (Resolve, ResolvedFeatures)>,
    95    roots: &[Unit],
    96    scrape_units: &[Unit],
    97    std_roots: &HashMap<CompileKind, Vec<Unit>>,
    98    intent: UserIntent,
    99    target_data: &'a RustcTargetData<'gctx>,
    100    profiles: &'a Profiles,
    101    interner: &'a UnitInterner,
    102) -> CargoResult<UnitGraph> {
    103    if roots.is_empty() {
    104        // If -Zbuild-std, don't attach units if there is nothing to build.
    105        // Otherwise, other parts of the code may be confused by seeing units
    106        // in the dep graph without a root.
    107        return Ok(HashMap::new());
    108    }
    109    let (std_resolve, std_features) = match std_resolve {
    110        Some((r, f)) => (Some(r), Some(f)),
    111        None => (None, None),
    112    };
    113    let mut state = State {
    114        ws,
    115        gctx: ws.gctx(),
    116        unit_dependencies: HashMap::new(),
    117        package_set,
    118        usr_resolve: resolve,
    119        usr_features: features,
    120        std_resolve,
    121        std_features,
    122        is_std: false,
    123        intent,
    124        target_data,
    125        profiles,
    126        interner,
    127        scrape_units,
    128        dev_dependency_edges: HashSet::new(),
    129    };
    130
    131    let std_unit_deps = calc_deps_of_std(&mut state, std_roots)?;
    132
    133    deps_of_roots(roots, &mut state)?;
    134    super::links::validate_links(state.resolve(), &state.unit_dependencies)?;
    135    // Hopefully there aren't any links conflicts with the standard library?
    136
    137    if let Some(std_unit_deps) = std_unit_deps {
    138        attach_std_deps(&mut state, std_roots, std_unit_deps);
    139    }
    140
    141    connect_run_custom_build_deps(&mut state);
    142
    143    // Dependencies are used in tons of places throughout the backend, many of
    144    // which affect the determinism of the build itself. As a result be sure
    145    // that dependency lists are always sorted to ensure we've always got a
    146    // deterministic output.
    147    for (unit, list) in &mut state.unit_dependencies {
    148        let is_multiple_build_scripts_enabled = unit
    149            .pkg
    150            .manifest()
    151            .unstable_features()
    152            .require(Feature::multiple_build_scripts())
    153            .is_ok();
    154
    155        if is_multiple_build_scripts_enabled {
    156            list.sort_by_key(|unit_dep| {
    157                if unit_dep.unit.target.is_custom_build() {
    158                    // We do not sort build scripts to preserve the user-defined order.
    159                    // In terms of determinism, we are assuming nothing interferes with order from when the user set it in `Cargo.toml` to here
    160                    (0, None)
    161                } else {
    162                    (1, Some(unit_dep.clone()))
    163                }
    164            });
    165        } else {
    166            list.sort();
    167        }
    168    }
    169    trace!("ALL UNIT DEPENDENCIES {:#?}", state.unit_dependencies);
    170
    171    Ok(state.unit_dependencies)
    172}
    173
    174/// Compute all the dependencies for the standard library.
    175fn calc_deps_of_std(
    176    state: &mut State<'_, '_>,
    177    std_roots: &HashMap<CompileKind, Vec<Unit>>,
    178) -> CargoResult<Option<UnitGraph>> {
    179    if std_roots.is_empty() {
    180        return Ok(None);
    181    }
    182    // Compute dependencies for the standard library.
    183    state.is_std = true;
    184    for roots in std_roots.values() {
    185        deps_of_roots(roots, state)?;
    186    }
    187    state.is_std = false;
    188    Ok(Some(std::mem::take(&mut state.unit_dependencies)))
    189}
    190
    191/// Add the standard library units to the `unit_dependencies`.
    192fn attach_std_deps(
    193    state: &mut State<'_, '_>,
    194    std_roots: &HashMap<CompileKind, Vec<Unit>>,
    195    std_unit_deps: UnitGraph,
    196) {
    197    // Attach the standard library as a dependency of every target unit.
    198    let mut found = false;
    199    for (unit, deps) in state.unit_dependencies.iter_mut() {
    200        if !unit.kind.is_host() && !unit.mode.is_run_custom_build() {
    201            deps.extend(std_roots[&unit.kind].iter().map(|unit| UnitDep {
    202                unit: unit.clone(),
    203                unit_for: UnitFor::new_normal(unit.kind),
    204                extern_crate_name: unit.pkg.name(),
    205                dep_name: None,
    206                // TODO: Does this `public` make sense?
    207                public: true,
    208                noprelude: true,
    209            }));
    210            found = true;
    211        }
    212    }
    213    // And also include the dependencies of the standard library itself. Don't
    214    // include these if no units actually needed the standard library.
    215    if found {
    216        for (unit, deps) in std_unit_deps.into_iter() {
    217            if let Some(other_unit) = state.unit_dependencies.insert(unit, deps) {
    218                panic!("std unit collision with existing unit: {:?}", other_unit);
    219            }
    220        }
    221    }
    222}
    223
    224/// Compute all the dependencies of the given root units.
    225/// The result is stored in `state.unit_dependencies`.
    226fn deps_of_roots(roots: &[Unit], state: &mut State<'_, '_>) -> CargoResult<()> {
    227    for unit in roots.iter() {
    228        // Dependencies of tests/benches should not have `panic` set.
    229        // We check the user intent to see if we are running in `cargo test` in
    230        // which case we ensure all dependencies have `panic` cleared, and
    231        // avoid building the lib thrice (once with `panic`, once without, once
    232        // for `--test`). In particular, the lib included for Doc tests and
    233        // examples are `Build` mode here.
    234        let root_compile_kind = unit.kind;
    235        let unit_for = if unit.mode.is_any_test() || state.intent.is_rustc_test() {
    236            if unit.target.proc_macro() {
    237                // Special-case for proc-macros, which are forced to for-host
    238                // since they need to link with the proc_macro crate.
    239                UnitFor::new_host_test(state.gctx, root_compile_kind)
    240            } else {
    241                UnitFor::new_test(state.gctx, root_compile_kind)
    242            }
    243        } else if unit.target.is_custom_build() {
    244            // This normally doesn't happen, except `clean` aggressively
    245            // generates all units.
    246            UnitFor::new_host(false, root_compile_kind)
    247        } else if unit.target.proc_macro() {
    248            UnitFor::new_host(true, root_compile_kind)
    249        } else if unit.target.for_host() {
    250            // Plugin should never have panic set.
    251            UnitFor::new_compiler(root_compile_kind)
    252        } else {
    253            UnitFor::new_normal(root_compile_kind)
    254        };
    255        deps_of(unit, state, unit_for)?;
    256    }
    257
    258    Ok(())
    259}
    260
    261/// Compute the dependencies of a single unit, recursively computing all
    262/// transitive dependencies.
    263///
    264/// The result is stored in `state.unit_dependencies`.
    265fn deps_of(unit: &Unit, state: &mut State<'_, '_>, unit_for: UnitFor) -> CargoResult<()> {
    266    // Currently the `unit_dependencies` map does not include `unit_for`. This should
    267    // be safe for now. `TestDependency` only exists to clear the `panic`
    268    // flag, and you'll never ask for a `unit` with `panic` set as a
    269    // `TestDependency`. `CustomBuild` should also be fine since if the
    270    // requested unit's settings are the same as `Any`, `CustomBuild` can't
    271    // affect anything else in the hierarchy.
    272    if !state.unit_dependencies.contains_key(unit) {
    273        let unit_deps = compute_deps(unit, state, unit_for)?;
    274        state
    275            .unit_dependencies
    276            .insert(unit.clone(), unit_deps.clone());
    277        for unit_dep in unit_deps {
    278            deps_of(&unit_dep.unit, state, unit_dep.unit_for)?;
    279        }
    280    }
    281    Ok(())
    282}
    283
    284/// Returns the direct unit dependencies for the given `Unit`.
    285fn compute_deps(
    286    unit: &Unit,
    287    state: &mut State<'_, '_>,
    288    unit_for: UnitFor,
    289) -> CargoResult<Vec<UnitDep>> {
    290    if unit.mode.is_run_custom_build() {
    291        return compute_deps_custom_build(unit, unit_for, state);
    292    } else if unit.mode.is_doc() {
    293        // Note: this does not include doc test.
    294        return compute_deps_doc(unit, state, unit_for);
    295    }
    296
    297    let mut ret = Vec::new();
    298    let mut dev_deps = Vec::new();
    299    for (dep_pkg_id, deps) in state.deps(unit, unit_for) {
    300        let Some(dep_lib) = calc_artifact_deps(unit, unit_for, dep_pkg_id, &deps, state, &mut ret)?
    301        else {
    302            continue;
    303        };
    304        let dep_pkg = state.get(dep_pkg_id);
    305        let mode = check_or_build_mode(unit.mode, dep_lib);
    306        let dep_unit_for = unit_for.with_dependency(unit, dep_lib, unit_for.root_compile_kind());
    307
    308        let start = ret.len();
    309        if state.gctx.cli_unstable().dual_proc_macros
    310            && dep_lib.proc_macro()
    311            && !unit.kind.is_host()
    312        {
    313            let unit_dep = new_unit_dep(
    314                state,
    315                unit,
    316                dep_pkg,
    317                dep_lib,
    318                dep_unit_for,
    319                unit.kind,
    320                mode,
    321                IS_NO_ARTIFACT_DEP,
    322            )?;
    323            ret.push(unit_dep);
    324            let unit_dep = new_unit_dep(
    325                state,
    326                unit,
    327                dep_pkg,
    328                dep_lib,
    329                dep_unit_for,
    330                CompileKind::Host,
    331                mode,
    332                IS_NO_ARTIFACT_DEP,
    333            )?;
    334            ret.push(unit_dep);
    335        } else {
    336            let unit_dep = new_unit_dep(
    337                state,
    338                unit,
    339                dep_pkg,
    340                dep_lib,
    341                dep_unit_for,
    342                unit.kind.for_target(dep_lib),
    343                mode,
    344                IS_NO_ARTIFACT_DEP,
    345            )?;
    346            ret.push(unit_dep);
    347        }
    348
    349        // If the unit added was a dev-dependency unit, then record that in the
    350        // dev-dependencies array. We'll add this to
    351        // `state.dev_dependency_edges` at the end and process it later in
    352        // `connect_run_custom_build_deps`.
    353        if deps.iter().all(|d| !d.is_transitive()) {
    354            for dep in ret[start..].iter() {
    355                dev_deps.push((unit.clone(), dep.unit.clone()));
    356            }
    357        }
    358    }
    359    state.dev_dependency_edges.extend(dev_deps);
    360
    361    // If this target is a build script, then what we've collected so far is
    362    // all we need. If this isn't a build script, then it depends on the
    363    // build script if there is one.
    364    if unit.target.is_custom_build() {
    365        return Ok(ret);
    366    }
    367    ret.extend(
    368        dep_build_script(unit, unit_for, state)?
    369            .into_iter()
    370            .flatten(),
    371    );
    372
    373    // If this target is a binary, test, example, etc, then it depends on
    374    // the library of the same package. The call to `resolve.deps` above
    375    // didn't include `pkg` in the return values, so we need to special case
    376    // it here and see if we need to push `(pkg, pkg_lib_target)`.
    377    if unit.target.is_lib() && unit.mode != CompileMode::Doctest {
    378        return Ok(ret);
    379    }
    380    ret.extend(maybe_lib(unit, state, unit_for)?);
    381
    382    // If any integration tests/benches are being run, make sure that
    383    // binaries are built as well.
    384    if !unit.mode.is_check()
    385        && unit.mode.is_any_test()
    386        && (unit.target.is_test() || unit.target.is_bench())
    387    {
    388        let id = unit.pkg.package_id();
    389        ret.extend(
    390            unit.pkg
    391                .targets()
    392                .iter()
    393                .filter(|t| {
    394                    // Skip binaries with required features that have not been selected.
    395                    match t.required_features() {
    396                        Some(rf) if t.is_bin() => {
    397                            let features = resolve_all_features(
    398                                state.resolve(),
    399                                state.features(),
    400                                state.package_set,
    401                                id,
    402                            );
    403                            rf.iter().all(|f| features.contains(f))
    404                        }
    405                        None if t.is_bin() => true,
    406                        _ => false,
    407                    }
    408                })
    409                .map(|t| {
    410                    new_unit_dep(
    411                        state,
    412                        unit,
    413                        &unit.pkg,
    414                        t,
    415                        UnitFor::new_normal(unit_for.root_compile_kind()),
    416                        unit.kind.for_target(t),
    417                        CompileMode::Build,
    418                        IS_NO_ARTIFACT_DEP,
    419                    )
    420                })
    421                .collect::<CargoResult<Vec<UnitDep>>>()?,
    422        );
    423    }
    424
    425    Ok(ret)
    426}
    427
    428/// Find artifacts for all `deps` of `unit` and add units that build these artifacts
    429/// to `ret`.
    430fn calc_artifact_deps<'a>(
    431    unit: &Unit,
    432    unit_for: UnitFor,
    433    dep_id: PackageId,
    434    deps: &[&Dependency],
    435    state: &State<'a, '_>,
    436    ret: &mut Vec<UnitDep>,
    437) -> CargoResult<Option<&'a Target>> {
    438    let mut has_artifact_lib = false;
    439    let mut maybe_non_artifact_lib = false;
    440    let artifact_pkg = state.get(dep_id);
    441    for dep in deps {
    442        let Some(artifact) = dep.artifact() else {
    443            maybe_non_artifact_lib = true;
    444            continue;
    445        };
    446        has_artifact_lib |= artifact.is_lib();
    447        // Custom build scripts (build/compile) never get artifact dependencies,
    448        // but the run-build-script step does (where it is handled).
    449        if !unit.target.is_custom_build() {
    450            debug_assert!(
    451                !unit.mode.is_run_custom_build(),
    452                "BUG: This should be handled in a separate branch"
    453            );
    454            ret.extend(artifact_targets_to_unit_deps(
    455                unit,
    456                unit_for.with_artifact_features(artifact),
    457                state,
    458                artifact
    459                    .target()
    460                    .and_then(|t| match t {
    461                        ArtifactTarget::BuildDependencyAssumeTarget => None,
    462                        ArtifactTarget::Force(kind) => Some(CompileKind::Target(kind)),
    463                    })
    464                    .unwrap_or(unit.kind),
    465                artifact_pkg,
    466                dep,
    467            )?);
    468        }
    469    }
    470    if has_artifact_lib || maybe_non_artifact_lib {
    471        Ok(artifact_pkg.targets().iter().find(|t| t.is_lib()))
    472    } else {
    473        Ok(None)
    474    }
    475}
    476
    477/// Returns the dependencies needed to run a build script.
    478///
    479/// The `unit` provided must represent an execution of a build script, and
    480/// the returned set of units must all be run before `unit` is run.
    481fn compute_deps_custom_build(
    482    unit: &Unit,
    483    unit_for: UnitFor,
    484    state: &State<'_, '_>,
    485) -> CargoResult<Vec<UnitDep>> {
    486    if let Some(links) = unit.pkg.manifest().links() {
    487        if unit.links_overrides.get(links).is_some() {
    488            // Overridden build scripts don't have any dependencies.
    489            return Ok(Vec::new());
    490        }
    491    }
    492    // All dependencies of this unit should use profiles for custom builds.
    493    // If this is a build script of a proc macro, make sure it uses host
    494    // features.
    495    let script_unit_for = unit_for.for_custom_build();
    496    // When not overridden, then the dependencies to run a build script are:
    497    //
    498    // 1. Compiling the build script itself.
    499    // 2. For each immediate dependency of our package which has a `links`
    500    //    key, the execution of that build script.
    501    //
    502    // We don't have a great way of handling (2) here right now so this is
    503    // deferred until after the graph of all unit dependencies has been
    504    // constructed.
    505    let compile_script_unit = new_unit_dep(
    506        state,
    507        unit,
    508        &unit.pkg,
    509        &unit.target,
    510        script_unit_for,
    511        // Build scripts always compiled for the host.
    512        CompileKind::Host,
    513        CompileMode::Build,
    514        IS_NO_ARTIFACT_DEP,
    515    )?;
    516
    517    let mut result = vec![compile_script_unit];
    518
    519    // Include any artifact dependencies.
    520    //
    521    // This is essentially the same as `calc_artifact_deps`, but there are some
    522    // subtle differences that require this to be implemented differently.
    523    //
    524    // Produce units that build all required artifact kinds (like binaries,
    525    // static libraries, etc) with the correct compile target.
    526    //
    527    // Computing the compile target for artifact units is more involved as it has to handle
    528    // various target configurations specific to artifacts, like `target = "target"` and
    529    // `target = "<triple>"`, which makes knowing the root units compile target
    530    // `root_unit_compile_target` necessary.
    531    let root_unit_compile_target = unit_for.root_compile_kind();
    532    let unit_for = UnitFor::new_host(/*host_features*/ true, root_unit_compile_target);
    533    for (dep_pkg_id, deps) in state.deps(unit, script_unit_for) {
    534        for dep in deps {
    535            if dep.kind() != DepKind::Build || dep.artifact().is_none() {
    536                continue;
    537            }
    538            let artifact_pkg = state.get(dep_pkg_id);
    539            let artifact = dep.artifact().expect("artifact dep");
    540            let resolved_artifact_compile_kind = artifact
    541                .target()
    542                .map(|target| target.to_resolved_compile_kind(root_unit_compile_target));
    543
    544            result.extend(artifact_targets_to_unit_deps(
    545                unit,
    546                unit_for.with_artifact_features_from_resolved_compile_kind(
    547                    resolved_artifact_compile_kind,
    548                ),
    549                state,
    550                resolved_artifact_compile_kind.unwrap_or(CompileKind::Host),
    551                artifact_pkg,
    552                dep,
    553            )?);
    554        }
    555    }
    556
    557    Ok(result)
    558}
    559
    560/// Given a `parent` unit containing a dependency `dep` whose package is `artifact_pkg`,
    561/// find all targets in `artifact_pkg` which refer to the `dep`s artifact declaration
    562/// and turn them into units.
    563/// Due to the nature of artifact dependencies, a single dependency in a manifest can
    564/// cause one or more targets to be build, for instance with
    565/// `artifact = ["bin:a", "bin:b", "staticlib"]`, which is very different from normal
    566/// dependencies which cause only a single unit to be created.
    567///
    568/// `compile_kind` is the computed kind for the future artifact unit
    569/// dependency, only the caller can pick the correct one.
    570fn artifact_targets_to_unit_deps(
    571    parent: &Unit,
    572    parent_unit_for: UnitFor,
    573    state: &State<'_, '_>,
    574    compile_kind: CompileKind,
    575    artifact_pkg: &Package,
    576    dep: &Dependency,
    577) -> CargoResult<Vec<UnitDep>> {
    578    let ret =
    579        match_artifacts_kind_with_targets(dep, artifact_pkg.targets(), parent.pkg.name().as_str())?
    580            .into_iter()
    581            .flat_map(|(artifact_kind, target)| {
    582                // We split target libraries into individual units, even though rustc is able
    583                // to produce multiple kinds in a single invocation for the sole reason that
    584                // each artifact kind has its own output directory, something we can't easily
    585                // teach rustc for now.
    586                match target.kind() {
    587                    TargetKind::Lib(kinds) => Box::new(
    588                        kinds
    589                            .iter()
    590                            .filter(move |tk| match (tk, artifact_kind) {
    591                                (CrateType::Cdylib, ArtifactKind::Cdylib) => true,
    592                                (CrateType::Staticlib, ArtifactKind::Staticlib) => true,
    593                                _ => false,
    594                            })
    595                            .map(|target_kind| {
    596                                new_unit_dep(
    597                                    state,
    598                                    parent,
    599                                    artifact_pkg,
    600                                    target
    601                                        .clone()
    602                                        .set_kind(TargetKind::Lib(vec![target_kind.clone()])),
    603                                    parent_unit_for,
    604                                    compile_kind,
    605                                    CompileMode::Build,
    606                                    dep.artifact(),
    607                                )
    608                            }),
    609                    ) as Box<dyn Iterator<Item = _>>,
    610                    _ => Box::new(std::iter::once(new_unit_dep(
    611                        state,
    612                        parent,
    613                        artifact_pkg,
    614                        target,
    615                        parent_unit_for,
    616                        compile_kind,
    617                        CompileMode::Build,
    618                        dep.artifact(),
    619                    ))),
    620                }
    621            })
    622            .collect::<Result<Vec<_>, _>>()?;
    623    Ok(ret)
    624}
    625
    626/// Returns the dependencies necessary to document a package.
    627fn compute_deps_doc(
    628    unit: &Unit,
    629    state: &mut State<'_, '_>,
    630    unit_for: UnitFor,
    631) -> CargoResult<Vec<UnitDep>> {
    632    // To document a library, we depend on dependencies actually being
    633    // built. If we're documenting *all* libraries, then we also depend on
    634    // the documentation of the library being built.
    635    let mut ret = Vec::new();
    636    for (id, deps) in state.deps(unit, unit_for) {
    637        let Some(dep_lib) = calc_artifact_deps(unit, unit_for, id, &deps, state, &mut ret)? else {
    638            continue;
    639        };
    640        let dep_pkg = state.get(id);
    641        // Rustdoc only needs rmeta files for regular dependencies.
    642        // However, for plugins/proc macros, deps should be built like normal.
    643        let mode = check_or_build_mode(unit.mode, dep_lib);
    644        let dep_unit_for = unit_for.with_dependency(unit, dep_lib, unit_for.root_compile_kind());
    645        let lib_unit_dep = new_unit_dep(
    646            state,
    647            unit,
    648            dep_pkg,
    649            dep_lib,
    650            dep_unit_for,
    651            unit.kind.for_target(dep_lib),
    652            mode,
    653            IS_NO_ARTIFACT_DEP,
    654        )?;
    655        ret.push(lib_unit_dep);
    656        if dep_lib.documented() && state.intent.wants_deps_docs() {
    657            // Document this lib as well.
    658            let doc_unit_dep = new_unit_dep(
    659                state,
    660                unit,
    661                dep_pkg,
    662                dep_lib,
    663                dep_unit_for,
    664                unit.kind.for_target(dep_lib),
    665                unit.mode,
    666                IS_NO_ARTIFACT_DEP,
    667            )?;
    668            ret.push(doc_unit_dep);
    669        }
    670    }
    671
    672    // Be sure to build/run the build script for documented libraries.
    673    ret.extend(
    674        dep_build_script(unit, unit_for, state)?
    675            .into_iter()
    676            .flatten(),
    677    );
    678
    679    // If we document a binary/example, we need the library available.
    680    if unit.target.is_bin() || unit.target.is_example() {
    681        // build the lib
    682        ret.extend(maybe_lib(unit, state, unit_for)?);
    683        // and also the lib docs for intra-doc links
    684        if let Some(lib) = unit
    685            .pkg
    686            .targets()
    687            .iter()
    688            .find(|t| t.is_linkable() && t.documented())
    689        {
    690            let dep_unit_for = unit_for.with_dependency(unit, lib, unit_for.root_compile_kind());
    691            let lib_doc_unit = new_unit_dep(
    692                state,
    693                unit,
    694                &unit.pkg,
    695                lib,
    696                dep_unit_for,
    697                unit.kind.for_target(lib),
    698                unit.mode,
    699                IS_NO_ARTIFACT_DEP,
    700            )?;
    701            ret.push(lib_doc_unit);
    702        }
    703    }
    704
    705    // Add all units being scraped for examples as a dependency of top-level Doc units.
    706    if state.ws.unit_needs_doc_scrape(unit) {
    707        for scrape_unit in state.scrape_units.iter() {
    708            let scrape_unit_for = UnitFor::new_normal(scrape_unit.kind);
    709            deps_of(scrape_unit, state, scrape_unit_for)?;
    710            ret.push(new_unit_dep(
    711                state,
    712                scrape_unit,
    713                &scrape_unit.pkg,
    714                &scrape_unit.target,
    715                scrape_unit_for,
    716                scrape_unit.kind,
    717                scrape_unit.mode,
    718                IS_NO_ARTIFACT_DEP,
    719            )?);
    720        }
    721    }
    722
    723    Ok(ret)
    724}
    725
    726fn maybe_lib(
    727    unit: &Unit,
    728    state: &mut State<'_, '_>,
    729    unit_for: UnitFor,
    730) -> CargoResult<Option<UnitDep>> {
    731    unit.pkg
    732        .targets()
    733        .iter()
    734        .find(|t| t.is_linkable())
    735        .map(|t| {
    736            let mode = check_or_build_mode(unit.mode, t);
    737            let dep_unit_for = unit_for.with_dependency(unit, t, unit_for.root_compile_kind());
    738            new_unit_dep(
    739                state,
    740                unit,
    741                &unit.pkg,
    742                t,
    743                dep_unit_for,
    744                unit.kind.for_target(t),
    745                mode,
    746                IS_NO_ARTIFACT_DEP,
    747            )
    748        })
    749        .transpose()
    750}
    751
    752/// If a build script is scheduled to be run for the package specified by
    753/// `unit`, this function will return the unit to run that build script.
    754///
    755/// Overriding a build script simply means that the running of the build
    756/// script itself doesn't have any dependencies, so even in that case a unit
    757/// of work is still returned. `None` is only returned if the package has no
    758/// build script.
    759fn dep_build_script(
    760    unit: &Unit,
    761    unit_for: UnitFor,
    762    state: &State<'_, '_>,
    763) -> CargoResult<Option<Vec<UnitDep>>> {
    764    Some(
    765        unit.pkg
    766            .targets()
    767            .iter()
    768            .filter(|t| t.is_custom_build())
    769            .map(|t| {
    770                // The profile stored in the Unit is the profile for the thing
    771                // the custom build script is running for.
    772                let profile = state.profiles.get_profile_run_custom_build(&unit.profile);
    773                // UnitFor::for_custom_build is used because we want the `host` flag set
    774                // for all of our build dependencies (so they all get
    775                // build-override profiles), including compiling the build.rs
    776                // script itself.
    777                //
    778                // If `is_for_host_features` here is `false`, that means we are a
    779                // build.rs script for a normal dependency and we want to set the
    780                // CARGO_FEATURE_* environment variables to the features as a
    781                // normal dep.
    782                //
    783                // If `is_for_host_features` here is `true`, that means that this
    784                // package is being used as a build dependency or proc-macro, and
    785                // so we only want to set CARGO_FEATURE_* variables for the host
    786                // side of the graph.
    787                //
    788                // Keep in mind that the RunCustomBuild unit and the Compile
    789                // build.rs unit use the same features. This is because some
    790                // people use `cfg!` and `#[cfg]` expressions to check for enabled
    791                // features instead of just checking `CARGO_FEATURE_*` at runtime.
    792                // In the case with the new feature resolver (decoupled host
    793                // deps), and a shared dependency has different features enabled
    794                // for normal vs. build, then the build.rs script will get
    795                // compiled twice. I believe it is not feasible to only build it
    796                // once because it would break a large number of scripts (they
    797                // would think they have the wrong set of features enabled).
    798                let script_unit_for = unit_for.for_custom_build();
    799                new_unit_dep_with_profile(
    800                    state,
    801                    unit,
    802                    &unit.pkg,
    803                    t,
    804                    script_unit_for,
    805                    unit.kind,
    806                    CompileMode::RunCustomBuild,
    807                    profile,
    808                    IS_NO_ARTIFACT_DEP,
    809                )
    810            })
    811            .collect(),
    812    )
    813    .transpose()
    814}
    815
    816/// Choose the correct mode for dependencies.
    817fn check_or_build_mode(mode: CompileMode, target: &Target) -> CompileMode {
    818    match mode {
    819        CompileMode::Check { .. } | CompileMode::Doc { .. } | CompileMode::Docscrape => {
    820            if target.for_host() {
    821                // Plugin and proc macro targets should be compiled like
    822                // normal.
    823                CompileMode::Build
    824            } else {
    825                // Regular dependencies should not be checked with --test.
    826                // Regular dependencies of doc targets should emit rmeta only.
    827                CompileMode::Check { test: false }
    828            }
    829        }
    830        _ => CompileMode::Build,
    831    }
    832}
    833
    834/// Create a new Unit for a dependency from `parent` to `pkg` and `target`.
    835fn new_unit_dep(
    836    state: &State<'_, '_>,
    837    parent: &Unit,
    838    pkg: &Package,
    839    target: &Target,
    840    unit_for: UnitFor,
    841    kind: CompileKind,
    842    mode: CompileMode,
    843    artifact: Option<&Artifact>,
    844) -> CargoResult<UnitDep> {
    845    let is_local = pkg.package_id().source_id().is_path() && !state.is_std;
    846    let profile = state.profiles.get_profile(
    847        pkg.package_id(),
    848        state.ws.is_member(pkg),
    849        is_local,
    850        unit_for,
    851        kind,
    852    );
    853    new_unit_dep_with_profile(
    854        state, parent, pkg, target, unit_for, kind, mode, profile, artifact,
    855    )
    856}
    857
    858fn new_unit_dep_with_profile(
    859    state: &State<'_, '_>,
    860    parent: &Unit,
    861    pkg: &Package,
    862    target: &Target,
    863    unit_for: UnitFor,
    864    kind: CompileKind,
    865    mode: CompileMode,
    866    profile: Profile,
    867    artifact: Option<&Artifact>,
    868) -> CargoResult<UnitDep> {
    869    let (extern_crate_name, dep_name) = state.resolve().extern_crate_name_and_dep_name(
    870        parent.pkg.package_id(),
    871        pkg.package_id(),
    872        target,
    873    )?;
    874    let public = state
    875        .resolve()
    876        .is_public_dep(parent.pkg.package_id(), pkg.package_id());
    877    let features_for = unit_for.map_to_features_for(artifact);
    878    let artifact_target = match features_for {
    879        FeaturesFor::ArtifactDep(target) => Some(target),
    880        _ => None,
    881    };
    882    let features = state.activated_features(pkg.package_id(), features_for);
    883    let unit = state.interner.intern(
    884        pkg,
    885        target,
    886        profile,
    887        kind,
    888        mode,
    889        features,
    890        state.target_data.info(kind).rustflags.clone(),
    891        state.target_data.info(kind).rustdocflags.clone(),
    892        state
    893            .target_data
    894            .target_config(kind)
    895            .links_overrides
    896            .clone(),
    897        state.is_std,
    898        /*dep_hash*/ 0,
    899        artifact.map_or(IsArtifact::No, |_| IsArtifact::Yes),
    900        artifact_target,
    901        false,
    902    );
    903    Ok(UnitDep {
    904        unit,
    905        unit_for,
    906        extern_crate_name,
    907        dep_name,
    908        public,
    909        noprelude: false,
    910    })
    911}
    912
    913/// Fill in missing dependencies for units of the `RunCustomBuild`
    914///
    915/// As mentioned above in `compute_deps_custom_build` each build script
    916/// execution has two dependencies. The first is compiling the build script
    917/// itself (already added) and the second is that all crates the package of the
    918/// build script depends on with `links` keys, their build script execution. (a
    919/// bit confusing eh?)
    920///
    921/// Here we take the entire `deps` map and add more dependencies from execution
    922/// of one build script to execution of another build script.
    923fn connect_run_custom_build_deps(state: &mut State<'_, '_>) {
    924    let mut new_deps = Vec::new();
    925
    926    {
    927        let state = &*state;
    928        // First up build a reverse dependency map. This is a mapping of all
    929        // `RunCustomBuild` known steps to the unit which depends on them. For
    930        // example a library might depend on a build script, so this map will
    931        // have the build script as the key and the library would be in the
    932        // value's set.
    933        let mut reverse_deps_map = HashMap::new();
    934        for (unit, deps) in state.unit_dependencies.iter() {
    935            for dep in deps {
    936                if dep.unit.mode == CompileMode::RunCustomBuild {
    937                    reverse_deps_map
    938                        .entry(dep.unit.clone())
    939                        .or_insert_with(HashSet::new)
    940                        .insert(unit);
    941                }
    942            }
    943        }
    944
    945        // Next, we take a look at all build scripts executions listed in the
    946        // dependency map. Our job here is to take everything that depends on
    947        // this build script (from our reverse map above) and look at the other
    948        // package dependencies of these parents.
    949        //
    950        // If we depend on a linkable target and the build script mentions
    951        // `links`, then we depend on that package's build script! Here we use
    952        // `dep_build_script` to manufacture an appropriate build script unit to
    953        // depend on.
    954        for unit in state
    955            .unit_dependencies
    956            .keys()
    957            .filter(|k| k.mode == CompileMode::RunCustomBuild)
    958        {
    959            // This list of dependencies all depend on `unit`, an execution of
    960            // the build script.
    961            let Some(reverse_deps) = reverse_deps_map.get(unit) else {
    962                continue;
    963            };
    964
    965            let to_add = reverse_deps
    966                .iter()
    967                // Get all sibling dependencies of `unit`
    968                .flat_map(|reverse_dep| {
    969                    state.unit_dependencies[reverse_dep]
    970                        .iter()
    971                        .map(move |a| (reverse_dep, a))
    972                })
    973                // Exclude ourself
    974                .filter(|(_parent, other)| other.unit.pkg != unit.pkg)
    975                // Only deps with `links`.
    976                .filter(|(_parent, other)| {
    977                    state.gctx.cli_unstable().any_build_script_metadata
    978                        || (other.unit.target.is_linkable()
    979                            && other.unit.pkg.manifest().links().is_some())
    980                })
    981                // Avoid cycles when using the doc --scrape-examples feature:
    982                // Say a workspace has crates A and B where A has a build-dependency on B.
    983                // The Doc units for A and B will have a dependency on the Docscrape for both A and B.
    984                // So this would add a dependency from B-build to A-build, causing a cycle:
    985                //   B (build) -> A (build) -> B(build)
    986                // See the test scrape_examples_avoid_build_script_cycle for a concrete example.
    987                // To avoid this cycle, we filter out the B -> A (docscrape) dependency.
    988                .filter(|(_parent, other)| !other.unit.mode.is_doc_scrape())
    989                // Skip dependencies induced via dev-dependencies since
    990                // connections between `links` and build scripts only happens
    991                // via normal dependencies. Otherwise since dev-dependencies can
    992                // be cyclic we could have cyclic build-script executions.
    993                .filter_map(move |(parent, other)| {
    994                    if state
    995                        .dev_dependency_edges
    996                        .contains(&((*parent).clone(), other.unit.clone()))
    997                    {
    998                        None
    999                    } else {
    1000                        Some(other)
    1001                    }
    1002                })
    1003                // Get the RunCustomBuild for other lib.
    1004                .filter_map(|other| {
    1005                    state.unit_dependencies[&other.unit]
    1006                        .iter()
    1007                        .find(|other_dep| other_dep.unit.mode == CompileMode::RunCustomBuild)
    1008                        .map(|other_dep| {
    1009                            let mut dep = other_dep.clone();
    1010                            let dep_name = other.dep_name.unwrap_or(other.unit.pkg.name());
    1011                            // Propagate the manifest dep name from the sibling edge.
    1012                            // The RunCustomBuild-RustCustomBuild edge is synthetic
    1013                            // and doesn't carry a usable dep name, but build script
    1014                            // metadata needs one for `CARGO_DEP_<dep_name>_*` env var
    1015                            dep.dep_name = Some(dep_name);
    1016                            dep
    1017                        })
    1018                })
    1019                .collect::<HashSet<_>>();
    1020
    1021            if !to_add.is_empty() {
    1022                // (RunCustomBuild, set(other RunCustomBuild))
    1023                new_deps.push((unit.clone(), to_add));
    1024            }
    1025        }
    1026    }
    1027
    1028    // And finally, add in all the missing dependencies!
    1029    for (unit, new_deps) in new_deps {
    1030        state
    1031            .unit_dependencies
    1032            .get_mut(&unit)
    1033            .unwrap()
    1034            .extend(new_deps);
    1035    }
    1036}
    1037
    1038impl<'a, 'gctx> State<'a, 'gctx> {
    1039    /// Gets `std_resolve` during building std, otherwise `usr_resolve`.
    1040    fn resolve(&self) -> &'a Resolve {
    1041        if self.is_std {
    1042            self.std_resolve.unwrap()
    1043        } else {
    1044            self.usr_resolve
    1045        }
    1046    }
    1047
    1048    /// Gets `std_features` during building std, otherwise `usr_features`.
    1049    fn features(&self) -> &'a ResolvedFeatures {
    1050        if self.is_std {
    1051            self.std_features.unwrap()
    1052        } else {
    1053            self.usr_features
    1054        }
    1055    }
    1056
    1057    fn activated_features(
    1058        &self,
    1059        pkg_id: PackageId,
    1060        features_for: FeaturesFor,
    1061    ) -> Vec<InternedString> {
    1062        let features = self.features();
    1063        features.activated_features(pkg_id, features_for)
    1064    }
    1065
    1066    fn is_dep_activated(
    1067        &self,
    1068        pkg_id: PackageId,
    1069        features_for: FeaturesFor,
    1070        dep_name: InternedString,
    1071    ) -> bool {
    1072        self.features()
    1073            .is_dep_activated(pkg_id, features_for, dep_name)
    1074    }
    1075
    1076    fn get(&self, id: PackageId) -> &'a Package {
    1077        self.package_set
    1078            .get_one(id)
    1079            .unwrap_or_else(|_| panic!("expected {} to be downloaded", id))
    1080    }
    1081
    1082    /// Returns a filtered set of dependencies for the given unit.
    1083    fn deps(&self, unit: &Unit, unit_for: UnitFor) -> Vec<(PackageId, Vec<&Dependency>)> {
    1084        let pkg_id = unit.pkg.package_id();
    1085        let kind = unit.kind;
    1086        self.resolve()
    1087            .deps(pkg_id)
    1088            .filter_map(|(id, deps)| {
    1089                assert!(!deps.is_empty());
    1090                let deps: Vec<_> = deps
    1091                    .iter()
    1092                    .filter(|dep| {
    1093                        // If this target is a build command, then we only want build
    1094                        // dependencies, otherwise we want everything *other than* build
    1095                        // dependencies.
    1096                        if unit.target.is_custom_build() != dep.is_build() {
    1097                            return false;
    1098                        }
    1099
    1100                        // If this dependency is **not** a transitive dependency, then it
    1101                        // only applies to test/example targets.
    1102                        if !dep.is_transitive()
    1103                            && !unit.target.is_test()
    1104                            && !unit.target.is_example()
    1105                            && !unit.mode.is_any_test()
    1106                        {
    1107                            return false;
    1108                        }
    1109
    1110                        // If this dependency is only available for certain platforms,
    1111                        // make sure we're only enabling it for that platform.
    1112                        if !self.target_data.dep_platform_activated(dep, kind) {
    1113                            return false;
    1114                        }
    1115
    1116                        // If this is an optional dependency, and the new feature resolver
    1117                        // did not enable it, don't include it.
    1118                        if dep.is_optional() {
    1119                            // This `unit_for` is from parent dep and *SHOULD* contains its own
    1120                            // artifact dep information inside `artifact_target_for_features`.
    1121                            // So, no need to map any artifact info from an incorrect `dep.artifact()`.
    1122                            let features_for = unit_for.map_to_features_for(IS_NO_ARTIFACT_DEP);
    1123                            if !self.is_dep_activated(pkg_id, features_for, dep.name_in_toml()) {
    1124                                return false;
    1125                            }
    1126                        }
    1127
    1128                        // If we've gotten past all that, then this dependency is
    1129                        // actually used!
    1130                        true
    1131                    })
    1132                    .collect();
    1133                if deps.is_empty() {
    1134                    None
    1135                } else {
    1136                    Some((id, deps))
    1137                }
    1138            })
    1139            .collect()
    1140    }
    1141}