Skip to main content

cargo/core/compiler/
unit_graph.rs

1use crate::core::compiler::Unit;
2use crate::core::compiler::{CompileKind, CompileMode};
3use crate::core::profiles::{Profile, UnitFor};
4use crate::core::{nightly_features_allowed, InternedString, PackageId, Target};
5use crate::util::CargoResult;
6use std::collections::HashMap;
7use std::io::Write;
8
9/// The dependency graph of Units.
10pub type UnitGraph<'a> = HashMap<Unit<'a>, Vec<UnitDep<'a>>>;
11
12/// A unit dependency.
13#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
14pub struct UnitDep<'a> {
15    /// The dependency unit.
16    pub unit: Unit<'a>,
17    /// The purpose of this dependency (a dependency for a test, or a build
18    /// script, etc.).
19    pub unit_for: UnitFor,
20    /// The name the parent uses to refer to this dependency.
21    pub extern_crate_name: InternedString,
22    /// Whether or not this is a public dependency.
23    pub public: bool,
24    /// If `true`, the dependency should not be added to Rust's prelude.
25    pub noprelude: bool,
26}
27
28const VERSION: u32 = 1;
29
30#[derive(serde::Serialize)]
31struct SerializedUnitGraph<'a> {
32    version: u32,
33    units: Vec<SerializedUnit<'a>>,
34    roots: Vec<usize>,
35}
36
37#[derive(serde::Serialize)]
38struct SerializedUnit<'a> {
39    pkg_id: PackageId,
40    target: &'a Target,
41    profile: &'a Profile,
42    platform: CompileKind,
43    mode: CompileMode,
44    features: &'a Vec<InternedString>,
45    #[serde(skip_serializing_if = "std::ops::Not::not")] // hide for unstable build-std
46    is_std: bool,
47    dependencies: Vec<SerializedUnitDep>,
48}
49
50#[derive(serde::Serialize)]
51struct SerializedUnitDep {
52    index: usize,
53    extern_crate_name: InternedString,
54    // This is only set on nightly since it is unstable.
55    #[serde(skip_serializing_if = "Option::is_none")]
56    public: Option<bool>,
57    // This is only set on nightly since it is unstable.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    noprelude: Option<bool>,
60    // Intentionally not including `unit_for` because it is a low-level
61    // internal detail that is mostly used for building the graph.
62}
63
64pub fn emit_serialized_unit_graph(
65    root_units: &[Unit<'_>],
66    unit_graph: &UnitGraph<'_>,
67) -> CargoResult<()> {
68    let is_nightly = nightly_features_allowed();
69    let mut units: Vec<(&Unit<'_>, &Vec<UnitDep<'_>>)> = unit_graph.iter().collect();
70    units.sort_unstable();
71    // Create a map for quick lookup for dependencies.
72    let indices: HashMap<&Unit<'_>, usize> = units
73        .iter()
74        .enumerate()
75        .map(|(i, val)| (val.0, i))
76        .collect();
77    let roots = root_units.iter().map(|root| indices[root]).collect();
78    let ser_units = units
79        .iter()
80        .map(|(unit, unit_deps)| {
81            let dependencies = unit_deps
82                .iter()
83                .map(|unit_dep| {
84                    // https://github.com/rust-lang/rust/issues/64260 when stabilized.
85                    let (public, noprelude) = if is_nightly {
86                        (Some(unit_dep.public), Some(unit_dep.noprelude))
87                    } else {
88                        (None, None)
89                    };
90                    SerializedUnitDep {
91                        index: indices[&unit_dep.unit],
92                        extern_crate_name: unit_dep.extern_crate_name,
93                        public,
94                        noprelude,
95                    }
96                })
97                .collect();
98            SerializedUnit {
99                pkg_id: unit.pkg.package_id(),
100                target: unit.target,
101                profile: &unit.profile,
102                platform: unit.kind,
103                mode: unit.mode,
104                features: &unit.features,
105                is_std: unit.is_std,
106                dependencies,
107            }
108        })
109        .collect();
110    let s = SerializedUnitGraph {
111        version: VERSION,
112        units: ser_units,
113        roots,
114    };
115
116    let stdout = std::io::stdout();
117    let mut lock = stdout.lock();
118    serde_json::to_writer(&mut lock, &s)?;
119    write!(lock, "\n")?;
120    Ok(())
121}