Skip to content

fix: fold [build].defines into cflags/cxxflags before P1689 scan - #297

Merged
Sunrisepeak merged 4 commits into
mcpp-community:mainfrom
ZheFeng7110:fix/build-defines-p1689-scan
Jul 28, 2026
Merged

fix: fold [build].defines into cflags/cxxflags before P1689 scan#297
Sunrisepeak merged 4 commits into
mcpp-community:mainfrom
ZheFeng7110:fix/build-defines-p1689-scan

Conversation

@ZheFeng7110

Copy link
Copy Markdown
Member

Summary

[build].defines was parsed by the TOML loader but never folded into the compile flags used by the P1689 module scanner. When import statements were guarded by a macro declared in [build].defines, the scanner saw no imports, while the planner (via scan_overrides) expected them, causing a plan-vs-scan divergence.

This PR fixes that by:

  1. Adding defines to BuildConfig in src/manifest/types.cppm.
  2. Parsing [build].defines in src/manifest/toml.cppm.
  3. Introducing fold_build_defines_into_flags() in src/build/prepare.cppm to desugar defines into -D<x> on both cflags and cxxflags before the manifest is snapshotted into packages and before fingerprinting.
  4. Adding a unit test and an E2E regression test (tests/e2e/167_build_defines_module_scan.sh) that mirrors the conditional-import + scan_overrides scenario.
  5. Updating docs/05-mcpp-toml.md and docs/zh/05-mcpp-toml.md.

Closes #296

Test plan

  • mcpp build self-hosts successfully.
  • mcpp test unit/test_manifest passes.
  • New E2E test tests/e2e/167_build_defines_module_scan.sh passes.
  • Reproduced the original failure with the unpatched binary and confirmed the patched binary builds the user's example.

ZheFeng7110 and others added 4 commits July 27, 2026 23:32
[build].defines was parsed but never folded into the compile flags used
by the P1689 module scanner. When imports were guarded by a macro from
[build].defines, the scanner saw no imports while the planner (via
scan_overrides) expected them, causing module-graph divergence.

- Add defines to BuildConfig
- Parse [build].defines in TOML loader
- Fold defines into -D<x> on cflags/cxxflags before snapshot/fingerprint
- Add unit test and E2E regression test
- Update English and Chinese docs

Closes mcpp-community#296
[build].defines was parsed but never folded into the compile flags used
by the P1689 module scanner. When imports were guarded by a macro from
[build].defines, the scanner saw no imports while the planner (via
scan_overrides) expected them, causing module-graph divergence.

- Add defines to BuildConfig
- Parse [build].defines in TOML loader
- Fold defines into -D<x> on cflags/cxxflags before snapshot/fingerprint
- Add unit test and E2E regression test
- Update English and Chinese docs

Closes mcpp-community#296
…to fix/build-defines-p1689-scan

# Conflicts:
#	tests/e2e/167_build_defines_module_scan.sh
…owing unknown keys (2026.7.28.1)

Review follow-up on mcpp-community#297. The original fix routed `[build].defines` to the
P1689 scan correctly — the mechanism was right and the fold sites already
mirrored the mcpp-community#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 (mcpp-community#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 — mcpp-community#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 mcpp-community#131's footgun, which `[targets.<name>]` already guards against
   with exactly the comment that describes mcpp-community#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 mcpp-community#296 was reported), #error guards as the
    assertion, plus NAME=value, a value containing a space (the -D quoting
    path from mcpp-community#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).
@Sunrisepeak

Sunrisepeak commented Jul 28, 2026

Copy link
Copy Markdown
Member

Review 跟进 —— 已 push 一个 follow-up commit

先说结论:原修复方向是对的。我把链路实测追了一遍 —— fold 落在 makePackageRoot 快照之前,scan_packages 读的 privateBuild.cxxflags 正是那份快照,ninja_backend 再把它拼进 P1689 扫描规则;三个 fold 点也精确复刻了既有的 #229 conditional-merge 漏斗。机制没有问题,compute_fingerprint 在三处 fold 之后跑,所以指纹参与也成立。

在这个基础上补了两处。

1. defines 该是 BuildInputs 成员,而不是 BuildConfig 成员

cfg 轴承载的是 ConditionalConfig::inputs(一个 BuildInputs),而这正是 #258 造出这个类型的目的 —— types.cppm 里的原话:

membership here is the answer, and it is a type rather than a hand-kept list, so it cannot drift

挂在 BuildConfig 上的字段,在 [target.'cfg(...)'.build]结构性地无法表达;而条件段读取器只读它认识的键,于是:

[target.'cfg(windows)'.build]
defines = ["USE_WIN32"]

会被静默丢弃 —— 正是 #296 本身的失败模式,只是挪到了隔壁一个段落。(原 commit 里 fold 函数的注释写了 "so conditional defines land too",这句当时无法成立。)

现在 defines 移进 BuildInputs:append() 带上它,条件段读取器读它,非空闸也计入它 —— 之前只写 defines 的条件段会在被求值之前就整个丢掉。

2. 根因订正:不是"defines 没被 fold",而是 [build] 会静默吞掉未知键

这点也影响 PR 描述。描述里写 defines "was parsed by the TOML loader but never folded",但 diff 里是新增了解析那一行 —— 这个 PR 之前 [build].defines 根本没被读过,它是一个被静默丢弃的未知键。

这正是 #131 的坑,而 [targets.<name>] 早就加了守卫,注释写的就是 #296 的剧本:

a [targets.x] cxxflags typo on an older mcpp just vanished

现在 [build][target.<pred>.build] 同样处理:schema warning,--strict 下是 error。这才是能从根上避免 #296 的那一半。

误报风险已实测:扫了仓库全部 116 个 mcpp.toml 以及 tests/ 里所有 heredoc 清单,零误报。(e2e fixture 里的 build.default_jobs / default_backend全局 config.toml,由 config.cppm 解析,不经过这条路径。)

3. 顺带:xpkg 描述符里的 defines 不再是 did-you-mean 错误

xpkg.cppm 之前把 defines 列为重定向到 flags 的易混淆别名。两个 manifest 表面是同一套 schema 的两种拼写,mcpp.toml 里合法的键不该在描述符里报 unknown key。现在 defines 在 mcpp 段和 target_cfg 里都是正式键,只剩单数 define 还做重定向。

测试

新增的三个 fold 调用点原本零覆盖,而已有 fold 点有三分之二没测:

版本

bump 到 2026.7.28.1(check_version_pins.sh 绿;bootstrap MCPP_PIN 保持已发布的 2026.7.27.1 不动)。

本地验证

全量单测 37/37 二进制通过(136 个 manifest 用例);e2e 167 / 93 / 85 / 108 / 109 / 116 / 149 / 119 / 80 / 83 全过。

CI

15/15 全绿(01c800c):四平台自举 + e2e、hermetic 容器、aarch64-musl 交叉、mingw→wine、macOS LLVM 端到端、Windows toolchains + regressions。

@Sunrisepeak
Sunrisepeak merged commit a0d3ed1 into mcpp-community:main Jul 28, 2026
15 checks passed
@ZheFeng7110
ZheFeng7110 deleted the fix/build-defines-p1689-scan branch July 28, 2026 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: [build].defines 未被传入 P1689 模块扫描,导致条件 import 与 scan_overrides 冲突

2 participants