Skip to main content

cabin_build/
graph.rs

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