Skip to main content

cabin_driver/
action.rs

1//! Semantic build-action IR.
2//!
3//! The planner emits these toolchain-independent action specs; the
4//! [`crate::lower()`] layer turns them into concrete command argv for a
5//! specific [`crate::Dialect`]. Nothing here names a compiler flag:
6//! the IR records *intent* (optimization level, debug info, defines,
7//! include directories, the source language) and each dialect spells
8//! it (`-O2` vs `/O2`, `-c` vs `/c`, …). A new dialect is added in
9//! [`crate::lower()`] without this IR changing.
10
11use camino::Utf8PathBuf;
12
13use cabin_core::{OptLevel, SourceLanguage};
14
15/// A single semantic build step: compile a translation unit, archive
16/// objects into a static library, or link an executable.
17///
18/// Backend- and toolchain-independent: the concrete command argv is
19/// produced later by [`crate::lower()`], not stored here.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum BuildAction {
22    /// Compile (or syntax-check) one C/C++ translation unit.
23    Compile(CompileAction),
24    /// Archive object files into a static library.
25    Archive(ArchiveAction),
26    /// Link object files and static archives into an executable.
27    Link(LinkAction),
28}
29
30/// What a compile action should produce.
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub enum CompileMode {
33    /// Normal compile: emit the object file at [`CompileAction::object`].
34    Object,
35    /// Syntax/semantic check only (`cabin check`): emit no object;
36    /// `stamp` is `touch`ed to record a successful check. The
37    /// `object` path is retained on the action so the stamp lives
38    /// beside it and the workspace-scope filter in `cabin check` can
39    /// match on it.
40    SyntaxOnly {
41        /// Stamp file written on a successful check, in place of the
42        /// object.
43        stamp: Utf8PathBuf,
44    },
45}
46
47/// Compile one translation unit.
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub struct CompileAction {
50    /// Source language; selects the standard flag and, at lowering
51    /// time, the rule / lowered action kind.
52    pub language: SourceLanguage,
53    /// Absolute path of the translation unit to compile.
54    pub source: Utf8PathBuf,
55    /// Object file the normal build produces. Retained even in
56    /// [`CompileMode::SyntaxOnly`] so the stamp lives beside it and
57    /// the workspace-scope filter in `cabin check` can match on it.
58    pub object: Utf8PathBuf,
59    /// Object vs. syntax-only.
60    pub mode: CompileMode,
61    /// Inputs the compile depends on but that are not command
62    /// arguments (e.g. a generated source produced upstream). The
63    /// `source` is the sole compiled input and is not repeated here.
64    pub implicit_inputs: Vec<Utf8PathBuf>,
65    /// Header-dependency tracking file. `Some` records that the
66    /// dialect should wire dependency discovery for this compile —
67    /// the GNU/Clang lowering emits a `-MMD -MF <depfile>` Makefile
68    /// depfile here, while the MSVC lowering ignores the path and
69    /// relies on `/showIncludes`.
70    pub depfile: Option<Utf8PathBuf>,
71    /// Compiler driver executable.
72    pub compiler: Utf8PathBuf,
73    /// Optional compiler-cache wrapper (e.g. `ccache`) prepended to
74    /// the *run* command by lowering. Never affects
75    /// `compile_commands.json`, which records the underlying compiler
76    /// so IDE tooling sees the real driver.
77    pub compiler_wrapper: Option<Utf8PathBuf>,
78    /// Semantic compile arguments (optimization, defines, includes).
79    pub arguments: CompileArguments,
80    /// Human-readable description for build output (`CXX foo.o`,
81    /// `CHECK foo.o`).
82    pub description: String,
83}
84
85/// Semantic arguments for a compile, with no flag spelled out.
86///
87/// The language standard is *not* stored: it is fixed per source
88/// language (C → C11, C++ → C++17) and spelled by the dialect from
89/// [`CompileAction::language`]. The optimization / debug / assertion
90/// intent comes from the resolved profile.
91#[derive(Debug, Clone, PartialEq, Eq)]
92pub struct CompileArguments {
93    /// Optimization level the active profile selected (`-O0` / `/Od`,
94    /// …).
95    pub opt_level: OptLevel,
96    /// Emit debug information (`-g` / `/Zi`).
97    pub debug_info: bool,
98    /// Define `NDEBUG` (assertions disabled in the active profile).
99    pub define_ndebug: bool,
100    /// Include search directories. Spelled `-I <dir>` / `/I <dir>`.
101    pub include_dirs: Vec<Utf8PathBuf>,
102    /// Preprocessor defines, without any prefix. Spelled `-D<define>`
103    /// / `/D<define>`.
104    pub defines: Vec<String>,
105    /// Escape-hatch compile flags appended verbatim after the
106    /// include block. The user writes these in the active dialect
107    /// (language-neutral first, then language-specific).
108    pub extra_flags: Vec<String>,
109}
110
111/// Archive object files into a static library.
112#[derive(Debug, Clone, PartialEq, Eq)]
113pub struct ArchiveAction {
114    /// Archiver executable (`ar` / `lib`).
115    pub archiver: Utf8PathBuf,
116    /// Static library to produce.
117    pub output: Utf8PathBuf,
118    /// Object files to archive, in order.
119    pub inputs: Vec<Utf8PathBuf>,
120    /// Human-readable description (`AR libfoo.a`).
121    pub description: String,
122}
123
124/// Link objects and static archives into an executable.
125#[derive(Debug, Clone, PartialEq, Eq)]
126pub struct LinkAction {
127    /// Link-driver executable (the C or C++ compiler, chosen per
128    /// target by the planner).
129    pub linker: Utf8PathBuf,
130    /// Executable to produce.
131    pub output: Utf8PathBuf,
132    /// Link inputs (objects then static archives), in link order.
133    pub inputs: Vec<Utf8PathBuf>,
134    /// Inputs the link depends on but that are not command arguments.
135    pub implicit_inputs: Vec<Utf8PathBuf>,
136    /// Extra linker flags (`ldflags`), inserted after the inputs and
137    /// before the output spelling.
138    pub arguments: Vec<String>,
139    /// System libraries to link, as bare names (e.g. `pthread`, `m`).
140    /// Lowered per-dialect — `-l<name>` for GNU-like, `<name>.lib` for
141    /// MSVC — and placed after the archive inputs so a static library's
142    /// required system libraries resolve left-to-right on the GNU link
143    /// line. Kept separate from `arguments` (raw `ldflags`) precisely so
144    /// the dialect layer owns the spelling rather than the planner.
145    pub link_libs: Vec<String>,
146    /// Human-readable description (`LINK app`).
147    pub description: String,
148}