1use super::TreeOptions;
4use crate::core::compiler::{CompileKind, RustcTargetData};
5use crate::core::dependency::DepKind;
6use crate::core::resolver::features::{CliFeatures, FeaturesFor, ResolvedFeatures};
7use crate::core::resolver::Resolve;
8use crate::core::{FeatureMap, FeatureValue, Package, PackageId, PackageIdSpec, Workspace};
9use crate::util::interning::{InternedString, INTERNED_DEFAULT};
10use crate::util::CargoResult;
11use std::collections::{HashMap, HashSet};
12
13#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
14pub enum Node {
15 Package {
16 package_id: PackageId,
17 features: Vec<InternedString>,
19 kind: CompileKind,
20 },
21 Feature {
22 node_index: usize,
24 name: InternedString,
26 },
27}
28
29#[derive(Debug, Copy, Hash, Eq, Clone, PartialEq)]
31pub enum EdgeKind {
32 Dep(DepKind),
33 Feature,
34}
35
36#[derive(Clone)]
45struct Edges(HashMap<EdgeKind, Vec<usize>>);
46
47impl Edges {
48 fn new() -> Edges {
49 Edges(HashMap::new())
50 }
51
52 fn add_edge(&mut self, kind: EdgeKind, index: usize) {
54 let indexes = self.0.entry(kind).or_default();
55 if !indexes.contains(&index) {
56 indexes.push(index)
57 }
58 }
59}
60
61pub struct Graph<'a> {
63 nodes: Vec<Node>,
64 edges: Vec<Edges>,
68 index: HashMap<Node, usize>,
70 package_map: HashMap<PackageId, &'a Package>,
72 cli_features: HashSet<usize>,
76 dep_name_map: HashMap<usize, HashMap<InternedString, HashSet<(usize, bool)>>>,
82}
83
84impl<'a> Graph<'a> {
85 fn new(package_map: HashMap<PackageId, &'a Package>) -> Graph<'a> {
86 Graph {
87 nodes: Vec::new(),
88 edges: Vec::new(),
89 index: HashMap::new(),
90 package_map,
91 cli_features: HashSet::new(),
92 dep_name_map: HashMap::new(),
93 }
94 }
95
96 fn add_node(&mut self, node: Node) -> usize {
98 let from_index = self.nodes.len();
99 self.nodes.push(node);
100 self.edges.push(Edges::new());
101 self.index
102 .insert(self.nodes[from_index].clone(), from_index);
103 from_index
104 }
105
106 pub fn connected_nodes(&self, from: usize, kind: &EdgeKind) -> Vec<usize> {
108 match self.edges[from].0.get(kind) {
109 Some(indexes) => {
110 let mut indexes = indexes.clone();
112 indexes.sort_unstable_by(|a, b| self.nodes[*a].cmp(&self.nodes[*b]));
113 indexes
114 }
115 None => Vec::new(),
116 }
117 }
118
119 pub fn has_outgoing_edges(&self, index: usize) -> bool {
121 !self.edges[index].0.is_empty()
122 }
123
124 pub fn node(&self, index: usize) -> &Node {
126 &self.nodes[index]
127 }
128
129 pub fn indexes_from_ids(&self, package_ids: &[PackageId]) -> Vec<usize> {
131 let mut result: Vec<(&Node, usize)> = self
132 .nodes
133 .iter()
134 .enumerate()
135 .filter(|(_i, node)| match node {
136 Node::Package { package_id, .. } => package_ids.contains(package_id),
137 _ => false,
138 })
139 .map(|(i, node)| (node, i))
140 .collect();
141 result.sort_unstable();
144 result.into_iter().map(|(_node, i)| i).collect()
145 }
146
147 pub fn package_for_id(&self, id: PackageId) -> &Package {
148 self.package_map[&id]
149 }
150
151 fn package_id_for_index(&self, index: usize) -> PackageId {
152 match self.nodes[index] {
153 Node::Package { package_id, .. } => package_id,
154 Node::Feature { .. } => panic!("unexpected feature node"),
155 }
156 }
157
158 pub fn is_cli_feature(&self, index: usize) -> bool {
161 self.cli_features.contains(&index)
162 }
163
164 pub fn from_reachable(&self, roots: &[usize]) -> Graph<'a> {
167 assert!(self.dep_name_map.is_empty());
169 let mut new_graph = Graph::new(self.package_map.clone());
170 let mut remap: Vec<Option<usize>> = vec![None; self.nodes.len()];
172
173 fn visit(
174 graph: &Graph<'_>,
175 new_graph: &mut Graph<'_>,
176 remap: &mut Vec<Option<usize>>,
177 index: usize,
178 ) -> usize {
179 if let Some(new_index) = remap[index] {
180 return new_index;
182 }
183 let node = graph.node(index).clone();
184 let new_from = new_graph.add_node(node);
185 remap[index] = Some(new_from);
186 for (edge_kind, edge_indexes) in &graph.edges[index].0 {
188 for edge_index in edge_indexes {
189 let new_to_index = visit(graph, new_graph, remap, *edge_index);
190 new_graph.edges[new_from].add_edge(*edge_kind, new_to_index);
191 }
192 }
193 new_from
194 }
195
196 for root in roots {
198 visit(self, &mut new_graph, &mut remap, *root);
199 }
200
201 new_graph
202 }
203
204 pub fn invert(&mut self) {
206 let mut new_edges = vec![Edges::new(); self.edges.len()];
207 for (from_idx, node_edges) in self.edges.iter().enumerate() {
208 for (kind, edges) in &node_edges.0 {
209 for edge_idx in edges {
210 new_edges[*edge_idx].add_edge(*kind, from_idx);
211 }
212 }
213 }
214 self.edges = new_edges;
215 }
216
217 pub fn find_duplicates(&self) -> Vec<usize> {
220 assert!(self.dep_name_map.is_empty());
222
223 let mut packages = HashMap::new();
225 for (i, node) in self.nodes.iter().enumerate() {
226 if let Node::Package { package_id, .. } = node {
227 packages
228 .entry(package_id.name())
229 .or_insert_with(Vec::new)
230 .push((node, i));
231 }
232 }
233
234 let mut dupes: Vec<(&Node, usize)> = packages
235 .into_iter()
236 .filter(|(_name, indexes)| {
237 indexes
238 .into_iter()
239 .map(|(node, _)| {
240 match node {
241 Node::Package {
242 package_id,
243 features,
244 ..
245 } => {
246 Node::Package {
248 package_id: package_id.clone(),
249 features: features.clone(),
250 kind: CompileKind::Host,
251 }
252 }
253 _ => unreachable!(),
254 }
255 })
256 .collect::<HashSet<_>>()
257 .len()
258 > 1
259 })
260 .flat_map(|(_name, indexes)| indexes)
261 .collect();
262
263 dupes.sort_unstable();
265 dupes.into_iter().map(|(_node, i)| i).collect()
266 }
267}
268
269pub fn build<'a>(
271 ws: &Workspace<'_>,
272 resolve: &Resolve,
273 resolved_features: &ResolvedFeatures,
274 specs: &[PackageIdSpec],
275 cli_features: &CliFeatures,
276 target_data: &RustcTargetData<'_>,
277 requested_kinds: &[CompileKind],
278 package_map: HashMap<PackageId, &'a Package>,
279 opts: &TreeOptions,
280) -> CargoResult<Graph<'a>> {
281 let mut graph = Graph::new(package_map);
282 let mut members_with_features = ws.members_with_features(specs, cli_features)?;
283 members_with_features.sort_unstable_by_key(|e| e.0.package_id());
284 for (member, cli_features) in members_with_features {
285 let member_id = member.package_id();
286 let features_for = FeaturesFor::from_for_host(member.proc_macro());
287 for kind in requested_kinds {
288 let member_index = add_pkg(
289 &mut graph,
290 resolve,
291 resolved_features,
292 member_id,
293 features_for,
294 target_data,
295 *kind,
296 opts,
297 );
298 if opts.graph_features {
299 let fmap = resolve.summary(member_id).features();
300 add_cli_features(&mut graph, member_index, &cli_features, fmap);
301 }
302 }
303 }
304 if opts.graph_features {
305 add_internal_features(&mut graph, resolve);
306 }
307 Ok(graph)
308}
309
310fn add_pkg(
316 graph: &mut Graph<'_>,
317 resolve: &Resolve,
318 resolved_features: &ResolvedFeatures,
319 package_id: PackageId,
320 features_for: FeaturesFor,
321 target_data: &RustcTargetData<'_>,
322 requested_kind: CompileKind,
323 opts: &TreeOptions,
324) -> usize {
325 let node_features = resolved_features.activated_features(package_id, features_for);
326 let node_kind = match features_for {
327 FeaturesFor::HostDep => CompileKind::Host,
328 FeaturesFor::ArtifactDep(target) => CompileKind::Target(target),
329 FeaturesFor::NormalOrDev => requested_kind,
330 };
331 let node = Node::Package {
332 package_id,
333 features: node_features,
334 kind: node_kind,
335 };
336 if let Some(idx) = graph.index.get(&node) {
337 return *idx;
338 }
339 let from_index = graph.add_node(node);
340 let mut dep_name_map: HashMap<InternedString, HashSet<(usize, bool)>> = HashMap::new();
342 let mut deps: Vec<_> = resolve.deps(package_id).collect();
343 deps.sort_unstable_by_key(|(dep_id, _)| *dep_id);
344 let show_all_targets = opts.target == super::Target::All;
345 for (dep_id, deps) in deps {
346 let mut deps: Vec<_> = deps
347 .iter()
348 .filter(|dep| {
351 let kind = match (node_kind, dep.kind()) {
352 (CompileKind::Host, _) => CompileKind::Host,
353 (_, DepKind::Build) => CompileKind::Host,
354 (_, DepKind::Normal) => node_kind,
355 (_, DepKind::Development) => node_kind,
356 };
357 if !show_all_targets && !target_data.dep_platform_activated(dep, kind) {
359 return false;
360 }
361 if !opts.edge_kinds.contains(&EdgeKind::Dep(dep.kind())) {
363 return false;
364 }
365 if opts.no_proc_macro && graph.package_for_id(dep_id).proc_macro() {
367 return false;
368 }
369 if dep.is_optional() {
370 if !resolved_features.is_dep_activated(
373 package_id,
374 features_for,
375 dep.name_in_toml(),
376 ) {
377 return false;
378 }
379 }
380 true
381 })
382 .collect();
383
384 if deps.is_empty() {
387 continue;
388 }
389
390 deps.sort_unstable_by_key(|dep| dep.name_in_toml());
391 let dep_pkg = graph.package_map[&dep_id];
392
393 for dep in deps {
394 let dep_features_for = match dep
395 .artifact()
396 .and_then(|artifact| artifact.target())
397 .and_then(|target| target.to_resolved_compile_target(requested_kind))
398 {
399 Some(target) => FeaturesFor::ArtifactDep(target),
401 None if features_for != FeaturesFor::default() => features_for,
409 None => {
414 if dep.is_build() || dep_pkg.proc_macro() {
415 FeaturesFor::HostDep
416 } else {
417 features_for
418 }
419 }
420 };
421 let dep_index = add_pkg(
422 graph,
423 resolve,
424 resolved_features,
425 dep_id,
426 dep_features_for,
427 target_data,
428 requested_kind,
429 opts,
430 );
431 if opts.graph_features {
432 dep_name_map
434 .entry(dep.name_in_toml())
435 .or_default()
436 .insert((dep_index, dep.is_optional()));
437 if dep.uses_default_features() {
438 add_feature(
439 graph,
440 INTERNED_DEFAULT,
441 Some(from_index),
442 dep_index,
443 EdgeKind::Dep(dep.kind()),
444 );
445 }
446 for feature in dep.features().iter() {
447 add_feature(
448 graph,
449 *feature,
450 Some(from_index),
451 dep_index,
452 EdgeKind::Dep(dep.kind()),
453 );
454 }
455 if !dep.uses_default_features() && dep.features().is_empty() {
456 graph.edges[from_index].add_edge(EdgeKind::Dep(dep.kind()), dep_index);
458 }
459 } else {
460 graph.edges[from_index].add_edge(EdgeKind::Dep(dep.kind()), dep_index);
461 }
462 }
463 }
464 if opts.graph_features {
465 assert!(graph
466 .dep_name_map
467 .insert(from_index, dep_name_map)
468 .is_none());
469 }
470
471 from_index
472}
473
474fn add_feature(
486 graph: &mut Graph<'_>,
487 name: InternedString,
488 from: Option<usize>,
489 to: usize,
490 kind: EdgeKind,
491) -> (bool, usize) {
492 assert!(matches! {graph.nodes[to], Node::Package{..}});
494 let node = Node::Feature {
495 node_index: to,
496 name,
497 };
498 let (missing, node_index) = match graph.index.get(&node) {
499 Some(idx) => (false, *idx),
500 None => (true, graph.add_node(node)),
501 };
502 if let Some(from) = from {
503 graph.edges[from].add_edge(kind, node_index);
504 }
505 graph.edges[node_index].add_edge(EdgeKind::Feature, to);
506 (missing, node_index)
507}
508
509fn add_cli_features(
515 graph: &mut Graph<'_>,
516 package_index: usize,
517 cli_features: &CliFeatures,
518 feature_map: &FeatureMap,
519) {
520 let mut to_add: HashSet<FeatureValue> = HashSet::new();
525 if cli_features.all_features {
526 to_add.extend(feature_map.keys().map(|feat| FeatureValue::Feature(*feat)));
527 }
528
529 if cli_features.uses_default_features {
530 to_add.insert(FeatureValue::Feature(INTERNED_DEFAULT));
531 }
532 to_add.extend(cli_features.features.iter().cloned());
533
534 for fv in to_add {
536 match fv {
537 FeatureValue::Feature(feature) => {
538 let index = add_feature(graph, feature, None, package_index, EdgeKind::Feature).1;
539 graph.cli_features.insert(index);
540 }
541 FeatureValue::Dep { .. } => panic!("unexpected cli dep feature {}", fv),
543 FeatureValue::DepFeature {
544 dep_name,
545 dep_feature,
546 weak,
547 } => {
548 let dep_connections = match graph.dep_name_map[&package_index].get(&dep_name) {
549 Some(dep_connections) => dep_connections.clone(),
551 None => {
552 if weak {
555 continue;
556 }
557 panic!(
558 "missing dep graph connection for CLI feature `{}` for member {:?}\n\
559 Please file a bug report at https://github.com/rust-lang/cargo/issues",
560 fv,
561 graph.nodes.get(package_index)
562 );
563 }
564 };
565 for (dep_index, is_optional) in dep_connections {
566 if is_optional {
567 let index =
569 add_feature(graph, dep_name, None, package_index, EdgeKind::Feature).1;
570 graph.cli_features.insert(index);
571 }
572 let index =
573 add_feature(graph, dep_feature, None, dep_index, EdgeKind::Feature).1;
574 graph.cli_features.insert(index);
575 }
576 }
577 }
578 }
579}
580
581fn add_internal_features(graph: &mut Graph<'_>, resolve: &Resolve) {
584 let feature_nodes: Vec<(PackageId, usize, usize, InternedString)> = graph
586 .nodes
587 .iter()
588 .enumerate()
589 .filter_map(|(i, node)| match node {
590 Node::Package { .. } => None,
591 Node::Feature { node_index, name } => {
592 let package_id = graph.package_id_for_index(*node_index);
593 Some((package_id, *node_index, i, *name))
594 }
595 })
596 .collect();
597
598 for (package_id, package_index, feature_index, feature_name) in feature_nodes {
599 add_feature_rec(
600 graph,
601 resolve,
602 feature_name,
603 package_id,
604 feature_index,
605 package_index,
606 );
607 }
608}
609
610fn add_feature_rec(
615 graph: &mut Graph<'_>,
616 resolve: &Resolve,
617 feature_name: InternedString,
618 package_id: PackageId,
619 from: usize,
620 package_index: usize,
621) {
622 let feature_map = resolve.summary(package_id).features();
623 let Some(fvs) = feature_map.get(&feature_name) else {
624 return;
625 };
626 for fv in fvs {
627 match fv {
628 FeatureValue::Feature(dep_name) => {
629 let (missing, feat_index) = add_feature(
630 graph,
631 *dep_name,
632 Some(from),
633 package_index,
634 EdgeKind::Feature,
635 );
636 if missing {
638 add_feature_rec(
639 graph,
640 resolve,
641 *dep_name,
642 package_id,
643 feat_index,
644 package_index,
645 );
646 }
647 }
648 FeatureValue::Dep { .. } => {}
653 FeatureValue::DepFeature {
654 dep_name,
655 dep_feature,
656 weak,
662 } => {
663 let dep_indexes = match graph.dep_name_map[&package_index].get(dep_name) {
664 Some(indexes) => indexes.clone(),
665 None => {
666 tracing::debug!(
667 "enabling feature {} on {}, found {}/{}, \
668 dep appears to not be enabled",
669 feature_name,
670 package_id,
671 dep_name,
672 dep_feature
673 );
674 continue;
675 }
676 };
677 for (dep_index, is_optional) in dep_indexes {
678 let dep_pkg_id = graph.package_id_for_index(dep_index);
679 if is_optional && !weak {
680 add_feature(
682 graph,
683 *dep_name,
684 Some(from),
685 package_index,
686 EdgeKind::Feature,
687 );
688 }
689 let (missing, feat_index) = add_feature(
690 graph,
691 *dep_feature,
692 Some(from),
693 dep_index,
694 EdgeKind::Feature,
695 );
696 if missing {
697 add_feature_rec(
698 graph,
699 resolve,
700 *dep_feature,
701 dep_pkg_id,
702 feat_index,
703 dep_index,
704 );
705 }
706 }
707 }
708 }
709 }
710}