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