Skip to main content

cabin_build/
graph.rs

1use cabin_core::StandardFlagConflict;
2use camino::Utf8PathBuf;
3
4use cabin_driver::{BuildAction, Dialect};
5
6/// Backend-independent description of everything that needs to happen to
7/// realize a build. A backend (currently `cabin-ninja`) walks this graph,
8/// lowers each semantic [`BuildAction`] to a concrete command via
9/// [`cabin_driver::lower()`] for the graph's [`Dialect`], and emits the
10/// equivalent build-system-specific representation.
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct BuildGraph {
13    /// All actions to execute, in topological order. Earlier actions in the
14    /// vector never depend on later actions. These are *semantic*
15    /// actions: compile / archive / link intent, not pre-lowered argv.
16    pub actions: Vec<BuildAction>,
17    /// Command-line dialect every action in this graph is lowered for.
18    /// The backend reads it to pick compile/archive/link spellings and
19    /// the matching Ninja dependency-tracking mode.
20    pub dialect: Dialect,
21    /// Output paths that should be marked as default targets.
22    pub default_outputs: Vec<Utf8PathBuf>,
23    /// One entry per C/C++ source compile, used to emit
24    /// `compile_commands.json`. Both languages contribute entries
25    /// with their language-appropriate compiler driver and flags
26    /// recorded in `arguments`.
27    pub compile_commands: Vec<CompileCommand>,
28    /// Standards problems recorded against *planned* compiles. The
29    /// planner records these instead of failing eagerly: the
30    /// `cabin check` rewrite prunes dependency compiles after
31    /// planning, and a violation that does not survive into the
32    /// final graph must not gate the command. The CLI surfaces
33    /// survivors through [`crate::validate_planned_standards`]
34    /// before anything is lowered or written.
35    pub standard_violations: Vec<StandardViolation>,
36}
37
38/// One standards problem recorded against a planned compile. Each
39/// variant carries the offending compile's object path so the
40/// `cabin check` rewrite can prune violations with the same path
41/// filter as the compiles they belong to.
42#[derive(Debug, Clone, PartialEq, Eq)]
43pub enum StandardViolation {
44    /// An MSVC-dialect compile whose standard `cl.exe` has no
45    /// stable `/std:` flag — the planner cannot lower it (its
46    /// compile-commands entry is omitted).
47    MsvcSpelling {
48        /// `package:target` of the offending compile.
49        target: String,
50        /// Human label of the source language (`C` / `C++`).
51        language: &'static str,
52        /// Canonical spelling of the offending standard.
53        standard: &'static str,
54        /// Object path of the offending compile.
55        object: Utf8PathBuf,
56    },
57    /// A compile that carries both a first-class standard
58    /// declaration and an explicit `-std=` / `/std:` token in its
59    /// manifest-derived flag list — the documented escape-hatch
60    /// ambiguity, scoped to compiles the declaration covers.
61    FlagConflict {
62        conflict: StandardFlagConflict,
63        /// Object path of the offending compile.
64        object: Utf8PathBuf,
65    },
66    /// A consuming compile whose effective implementation standard
67    /// is below a reachable library-like dependency's interface
68    /// requirement for the same language. Recorded against the
69    /// *consumer's* compile so the `cabin check` rewrite prunes the
70    /// incompatibility together with the compiles it protects — a
71    /// dependency-internal incompatibility never gates a check that
72    /// only compiles the selected packages' own translation units.
73    InterfaceIncompatibility {
74        consumer: String,
75        dependency: String,
76        language: &'static str,
77        consumer_standard: &'static str,
78        required: &'static str,
79        requirement_source: &'static str,
80        /// Object path of one of the consumer's compiles of the
81        /// language (every object of a target shares the same
82        /// per-package prefix the check filter tests).
83        object: Utf8PathBuf,
84    },
85}
86
87impl StandardViolation {
88    /// Object path of the offending compile, for the check
89    /// rewrite's path filter.
90    #[must_use]
91    pub fn object(&self) -> &Utf8PathBuf {
92        match self {
93            Self::MsvcSpelling { object, .. }
94            | Self::FlagConflict { object, .. }
95            | Self::InterfaceIncompatibility { object, .. } => object,
96        }
97    }
98}
99
100/// One entry of a Clang JSON Compilation Database.
101///
102/// `arguments` is kept as a list so each backend / consumer can render it
103/// however the format requires (LLVM accepts both `command` and
104/// `arguments` keys; `cabin-ninja` emits `command`).
105#[derive(Debug, Clone, PartialEq, Eq)]
106pub struct CompileCommand {
107    pub directory: Utf8PathBuf,
108    pub file: Utf8PathBuf,
109    pub arguments: Vec<String>,
110    pub output: Utf8PathBuf,
111}