You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: [build].defines is a BuildInputs member, and [build] stops swallowing unknown keys (2026.7.28.1)
Review follow-up on #297. The original fix routed `[build].defines` to the
P1689 scan correctly — the mechanism was right and the fold sites already
mirrored the #229 conditional-merge funnel. Two things were left open.
1. `defines` lived on BuildConfig, not BuildInputs.
The cfg axis carries `ConditionalConfig::inputs`, a BuildInputs — that is
the whole point of the type (#258): "membership here is the answer, and it
is a type rather than a hand-kept list, so it cannot drift." A BuildConfig-
only field is therefore inexpressible under `[target.'cfg(...)'.build]`,
and since the conditional reader only reads keys it knows, a platform-only
macro vanished without a word — #296's own failure mode, one section over.
The fold's comment claimed conditional defines landed; they could not.
`defines` is moved to BuildInputs, append() carries it, the conditional
reader reads it, and the emptiness gate counts it (a section with only
`defines` was being dropped before it was ever evaluated).
2. The root cause was never "defines wasn't folded" — it was that `[build]`
read its keys with a bare if-chain and silently discarded everything else.
That is #131's footgun, which `[targets.<name>]` already guards against
with exactly the comment that describes #296: "a `[targets.x] cxxflags`
typo on an older mcpp just vanished." `[build]` and
`[target.<pred>.build]` now get the same treatment — a schema warning, an
error under --strict. Verified against all 116 mcpp.toml in the repo and
every heredoc manifest in tests/: zero false positives. (`build.default_*`
in the e2e fixtures is the GLOBAL config.toml, parsed by config.cppm, and
is untouched by this.)
Also: the xpkg descriptor listed `defines` as a did-you-mean redirect to
`flags`. The two manifest surfaces are two spellings of one schema, so a key
accepted in an mcpp.toml must not be an unknown-key error in a descriptor —
`defines` is now a real key there and in `target_cfg`, and only the singular
misspelling still redirects.
Tests — the new call sites had no coverage at all, and two thirds of the
existing fold sites were untested:
- conditional `defines` parse, defines-only section, append() merge,
both unknown-key guards, and a manifest exercising every supported
`[build]` key so the guard can't fire on one (129 -> 136 unit tests)
- e2e 167 rewritten: toolchain-neutral (a LOCAL module, not `import std`,
so it runs on Windows where #296 was reported), #error guards as the
assertion, plus NAME=value, a value containing a space (the -D quoting
path from #234), the cfg axis, a path DEPENDENCY's own defines, and
non-propagation to the consumer
- e2e 167 no longer masks a failing `mcpp run` behind `tail`'s exit status
- e2e 93 asserts `defines` parses as a known descriptor key
Version bumped to 2026.7.28.1 (check_version_pins.sh green; the bootstrap
MCPP_PIN stays at the released 2026.7.27.1).
Copy file name to clipboardExpand all lines: docs/05-mcpp-toml.md
+27-1Lines changed: 27 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -183,7 +183,33 @@ then only guaranteed to run on the build machine's version and above). A lower
183
183
floor (11–13) requires a self-built libc++ archive (already verified to work, a
184
184
data-level switch, available on request).
185
185
186
-
`defines` desugars each entry to `-D<x>` on both the C and C++ compile channels and reaches every TU in the package — including module interface units — so it affects the P1689 module scan. For macros that should only affect a single binary's entry source, use `[targets.<name>].defines` instead.
186
+
`defines` takes **bare** macro names (no `-D`) and desugars each entry to `-D<x>` on
187
+
both the C and C++ compile channels. It reaches every TU in the package — module
188
+
interface units included — so it also reaches the P1689 module scan, which is what
189
+
makes a macro-guarded `import` resolvable. Assembly units pick it up too. It is a
190
+
build input like any other, so `[target.'cfg(...)'.build]` can carry it:
191
+
192
+
```toml
193
+
[build]
194
+
defines = ["APP_NAME=\"demo\""]
195
+
196
+
[target.'cfg(windows)'.build]
197
+
defines = ["USE_WIN32", "WINVER=0x0A00"]
198
+
```
199
+
200
+
Picking the right axis:
201
+
202
+
| You want the macro on… | Use |
203
+
|---|---|
204
+
| every TU of this package |`[build].defines` (here) |
205
+
| one binary's own entry source only |`[targets.<name>].defines`|
206
+
| a specific set of files |`[build].flags` with a `glob` + `defines`|
207
+
| every TU **and** every consumer's TUs |`[features.<name>].defines` (an interface contribution) |
208
+
209
+
`[build].defines` is private to the package: it does not propagate to consumers.
210
+
211
+
Unsupported keys under `[build]` are reported as a warning (an error under
212
+
`--strict`) rather than silently ignored.
187
213
188
214
Do not configure the C++ standard via `build.cxxflags = ["-std=..."]`. Instead use:
0 commit comments