#
cargo/core/compiler/
unit_graph.rs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129

    //! Serialization of [`UnitGraph`] for unstable option [`--unit-graph`].
    //!
    //! [`--unit-graph`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#unit-graph

    use crate::core::compiler::Unit;
    use crate::core::compiler::{CompileKind, CompileMode};
    use crate::core::profiles::{Profile, UnitFor};
    use crate::core::{PackageId, Target};
    use crate::util::interning::InternedString;
    use crate::util::CargoResult;
    use crate::GlobalContext;
    use std::collections::HashMap;

    /// The dependency graph of Units.
    pub type UnitGraph = HashMap<Unit, Vec<UnitDep>>;

    /// A unit dependency.
    #[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
    pub struct UnitDep {
        /// The dependency unit.
        pub unit: Unit,
        /// The purpose of this dependency (a dependency for a test, or a build
        /// script, etc.). Do not use this after the unit graph has been built.
        pub unit_for: UnitFor,
        /// The name the parent uses to refer to this dependency.
        pub extern_crate_name: InternedString,
        /// If `Some`, the name of the dependency if renamed in toml.
        /// It's particularly interesting to artifact dependencies which rely on it
        /// for naming their environment variables. Note that the `extern_crate_name`
        /// cannot be used for this as it also may be the build target itself,
        /// which isn't always the renamed dependency name.
        pub dep_name: Option<InternedString>,
        /// Whether or not this is a public dependency.
        pub public: bool,
        /// If `true`, the dependency should not be added to Rust's prelude.
        pub noprelude: bool,
    }

    const VERSION: u32 = 1;

    #[derive(serde::Serialize)]
    struct SerializedUnitGraph<'a> {
        version: u32,
        units: Vec<SerializedUnit<'a>>,
        roots: Vec<usize>,
    }

    #[derive(serde::Serialize)]
    struct SerializedUnit<'a> {
        pkg_id: PackageId,
        target: &'a Target,
        profile: &'a Profile,
        platform: CompileKind,
        mode: CompileMode,
        features: &'a Vec<InternedString>,
        #[serde(skip_serializing_if = "std::ops::Not::not")] // hide for unstable build-std
        is_std: bool,
        dependencies: Vec<SerializedUnitDep>,
    }

    #[derive(serde::Serialize)]
    struct SerializedUnitDep {
        index: usize,
        extern_crate_name: InternedString,
        // This is only set on nightly since it is unstable.
        #[serde(skip_serializing_if = "Option::is_none")]
        public: Option<bool>,
        // This is only set on nightly since it is unstable.
        #[serde(skip_serializing_if = "Option::is_none")]
        noprelude: Option<bool>,
        // Intentionally not including `unit_for` because it is a low-level
        // internal detail that is mostly used for building the graph.
    }

    /// Outputs a JSON serialization of [`UnitGraph`] for given `root_units`
    /// to the standard output.
    pub fn emit_serialized_unit_graph(
        root_units: &[Unit],
        unit_graph: &UnitGraph,
        gctx: &GlobalContext,
    ) -> CargoResult<()> {
        let mut units: Vec<(&Unit, &Vec<UnitDep>)> = unit_graph.iter().collect();
        units.sort_unstable();
        // Create a map for quick lookup for dependencies.
        let indices: HashMap<&Unit, usize> = units
            .iter()
            .enumerate()
            .map(|(i, val)| (val.0, i))
            .collect();
        let roots = root_units.iter().map(|root| indices[root]).collect();
        let ser_units = units
            .iter()
            .map(|(unit, unit_deps)| {
                let dependencies = unit_deps
                    .iter()
                    .map(|unit_dep| {
                        // https://github.com/rust-lang/rust/issues/64260 when stabilized.
                        let (public, noprelude) = if gctx.nightly_features_allowed {
                            (Some(unit_dep.public), Some(unit_dep.noprelude))
                        } else {
                            (None, None)
                        };
                        SerializedUnitDep {
                            index: indices[&unit_dep.unit],
                            extern_crate_name: unit_dep.extern_crate_name,
                            public,
                            noprelude,
                        }
                    })
                    .collect();
                SerializedUnit {
                    pkg_id: unit.pkg.package_id(),
                    target: &unit.target,
                    profile: &unit.profile,
                    platform: unit.kind,
                    mode: unit.mode,
                    features: &unit.features,
                    is_std: unit.is_std,
                    dependencies,
                }
            })
            .collect();

        gctx.shell().print_json(&SerializedUnitGraph {
            version: VERSION,
            units: ser_units,
            roots,
        })
    }