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}