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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! Serialization of [`UnitGraph`] for unstable option [`--unit-graph`].
//!
//! [`--unit-graph`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#unit-graph
use cargo_util_schemas::core::PackageIdSpec;
use crate::GlobalContext;
use crate::compiler::Unit;
use crate::compiler::{CompileKind, CompileMode};
use crate::util::CargoResult;
use crate::util::Unhashed;
use crate::util::data_structures::HashMap;
use crate::util::interning::InternedString;
use crate::workspace::Target;
use crate::workspace::dependency::Dependency;
use crate::workspace::profiles::{Profile, UnitFor};
/// 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,
/// The dependency name as written in the manifest (including a rename).
///
/// `None` means this edge does not carry a manifest dep name. For example,
/// std edges in build-std or synthetic edges for build script executions.
/// When `None`, the package name is typically used by callers as a fallback.
///
/// This is mainly for Cargo-synthesized outputs
/// (artifact env vars and `CARGO_DEP_*` metadata env)
/// and is distinct from `extern_crate_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,
/// If `true`, the dependency will not trigger Rust lint.
pub nounused: bool,
/// The manifest dependency that gave rise to this dependency
///
/// Skip hashing as this is redundant and for book keekping purposes only
pub manifest_deps: Unhashed<Option<Vec<Dependency>>>,
}
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: PackageIdSpec,
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>,
// This is only set on nightly since it is unstable.
#[serde(skip_serializing_if = "Option::is_none")]
nounused: 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, nounused) = if gctx.nightly_features_allowed {
(
Some(unit_dep.public),
Some(unit_dep.noprelude),
Some(unit_dep.nounused),
)
} else {
(None, None, None)
};
SerializedUnitDep {
index: indices[&unit_dep.unit],
extern_crate_name: unit_dep.extern_crate_name,
public,
noprelude,
nounused,
}
})
.collect();
SerializedUnit {
pkg_id: unit.pkg.package_id().to_spec(),
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,
})
}