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::{LanguageStandard, OptLevel};
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 /// Effective language standard for this translation unit. Also
51 /// determines the source language (`standard.language()`), which
52 /// selects the rule / lowered action kind, `/EHsc`, and the
53 /// `/Tp` / `/Tc` source-language flag on MSVC.
54 pub standard: LanguageStandard,
55 /// Absolute path of the translation unit to compile.
56 pub source: Utf8PathBuf,
57 /// Object file the normal build produces. Retained even in
58 /// [`CompileMode::SyntaxOnly`] so the stamp lives beside it and
59 /// the workspace-scope filter in `cabin check` can match on it.
60 pub object: Utf8PathBuf,
61 /// Object vs. syntax-only.
62 pub mode: CompileMode,
63 /// Inputs the compile depends on but that are not command
64 /// arguments (e.g. a generated source produced upstream). The
65 /// `source` is the sole compiled input and is not repeated here.
66 pub implicit_inputs: Vec<Utf8PathBuf>,
67 /// Header-dependency tracking file. `Some` records that the
68 /// dialect should wire dependency discovery for this compile —
69 /// the GNU/Clang lowering emits a `-MD -MF <depfile>` Makefile
70 /// depfile here (`-MD`, not `-MMD`, so headers found through a
71 /// system include dir still land in the depfile and keep
72 /// invalidating rebuilds), while the MSVC lowering ignores the
73 /// path and relies on `/showIncludes`.
74 pub depfile: Option<Utf8PathBuf>,
75 /// Compiler driver executable.
76 pub compiler: Utf8PathBuf,
77 /// Optional compiler-cache wrapper (e.g. `ccache`) prepended to
78 /// the *run* command by lowering. Never affects
79 /// `compile_commands.json`, which records the underlying compiler
80 /// so IDE tooling sees the real driver.
81 pub compiler_wrapper: Option<Utf8PathBuf>,
82 /// Semantic compile arguments (optimization, defines, includes).
83 pub arguments: CompileArguments,
84 /// Human-readable description for build output (`CXX foo.o`,
85 /// `CHECK foo.o`).
86 pub description: String,
87}
88
89/// Semantic arguments for a compile, with no flag spelled out.
90///
91/// The language standard lives on [`CompileAction::standard`]; each
92/// dialect spells it (`-std=c++20` vs `/std:c++20`). The
93/// optimization / debug / assertion intent comes from the resolved
94/// profile.
95#[derive(Debug, Clone, PartialEq, Eq)]
96pub struct CompileArguments {
97 /// Optimization level the active profile selected (`-O0` / `/Od`,
98 /// …).
99 pub opt_level: OptLevel,
100 /// Emit debug information (`-g` / `/Zi`).
101 pub debug_info: bool,
102 /// Define `NDEBUG` (assertions disabled in the active profile).
103 pub define_ndebug: bool,
104 /// Include search directories. Spelled `-I <dir>` / `/I <dir>`.
105 pub include_dirs: Vec<Utf8PathBuf>,
106 /// Include search directories marked as *system* search paths,
107 /// so diagnostics inside their headers are suppressed. Searched
108 /// after [`Self::include_dirs`]. The planner routes third-party
109 /// contributions here (registry packages, foundation ports,
110 /// pkg-config system dependencies). Spelled `-isystem <dir>` for
111 /// GNU/Clang; `/external:W0 /external:I <dir>` for MSVC (the
112 /// planner only populates this on MSVC-dialect builds when the
113 /// detected compiler supports the `/external:` block).
114 pub system_include_dirs: Vec<Utf8PathBuf>,
115 /// Preprocessor defines, without any prefix. Spelled `-D<define>`
116 /// / `/D<define>`.
117 pub defines: Vec<String>,
118 /// Escape-hatch compile flags appended verbatim after the
119 /// include block. The user writes these in the active dialect
120 /// (language-neutral first, then language-specific).
121 pub extra_flags: Vec<String>,
122}
123
124/// Archive object files into a static library.
125#[derive(Debug, Clone, PartialEq, Eq)]
126pub struct ArchiveAction {
127 /// Archiver executable (`ar` / `lib`).
128 pub archiver: Utf8PathBuf,
129 /// Static library to produce.
130 pub output: Utf8PathBuf,
131 /// Object files to archive, in order.
132 pub inputs: Vec<Utf8PathBuf>,
133 /// Human-readable description (`AR libfoo.a`).
134 pub description: String,
135}
136
137/// Link objects and static archives into an executable.
138#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct LinkAction {
140 /// Link-driver executable (the C or C++ compiler, chosen per
141 /// target by the planner).
142 pub linker: Utf8PathBuf,
143 /// Executable to produce.
144 pub output: Utf8PathBuf,
145 /// Link inputs (objects then static archives), in link order.
146 pub inputs: Vec<Utf8PathBuf>,
147 /// Inputs the link depends on but that are not command arguments.
148 pub implicit_inputs: Vec<Utf8PathBuf>,
149 /// Extra linker flags (`ldflags`), inserted after the inputs and
150 /// before the output spelling.
151 pub arguments: Vec<String>,
152 /// System libraries to link, as bare names (e.g. `pthread`, `m`).
153 /// Lowered per-dialect — `-l<name>` for GNU-like, `<name>.lib` for
154 /// MSVC — and placed after the archive inputs so a static library's
155 /// required system libraries resolve left-to-right on the GNU link
156 /// line. Kept separate from `arguments` (raw `ldflags`) precisely so
157 /// the dialect layer owns the spelling rather than the planner.
158 pub link_libs: Vec<String>,
159 /// Human-readable description (`LINK app`).
160 pub description: String,
161}