Skip to content

Commit 5e1bce9

Browse files
committed
feat(build): build.mcpp 补全 — 环境契约 + cross 下运行 + 依赖包执行 (0.0.95)
设计: .agents/docs/2026-07-17-asm-sources-and-general-build-capabilities-design.md (PR-C) G3 环境契约 + cross: - 注入 MCPP_TARGET/HOST/PROFILE/OUT_DIR/MANIFEST_DIR/MCPP_FEATURE_<NAME>/ MCPP_FEATURES(仅子进程,capture_exec env);契约值无条件折入重跑键 (cache 新增 ctx 行,旧缓存缺行自动失效一次) - cross --target 不再跳过:宿主工具链按同一 spec 词汇独立解析(不注入 target 轴),懒解析且仅当存在 build.mcpp;typed `import mcpp;` 模块补 读取端 target()/host()/profile()/out_dir()/manifest_dir()/has_feature() - feature 闭包收敛为单一 feature_closure 实现(原三处重复);profile 名提升 为 effectiveProfile 供契约使用;--features 解析共享 parse_feature_request G2 依赖包 build.mcpp(Cargo build.rs 模型): - 时机:feature 激活后、modgraph 扫描前;作用域照 Cargo:cfg/flags 只进该包 自身 TU(镜像进 privateBuild,与 MCPP_FEATURE_ 宏同款),link 指令补传终链 (BFS 传播已过,追加新尾部) - 产物全部项目本地化:target/.build-mcpp/deps/<pkg>@<ver>/,registry 包根 绝不写入;相对 generated= 以 OUT_DIR 为基;scanner 支持绝对路径字面源条目 - 顺修潜在盲区:generated= 只推 bc.sources,scanner 走 modules.sources 镜像 ——现在双推(此前靠默认 glob 兜住) 版本 bump 0.0.95(mcpp.toml + fingerprint.cppm 同步);docs/07 中英补契约与 依赖节;e2e 110(契约值/缓存/feature+profile 重跑)/111(dep 作用域/终链/ registry 零写入)/112(cross + wine 全环);单测 35/35,e2e 112 过(3 失败 均既有环境性 22/54/62)
1 parent 7582cd9 commit 5e1bce9

10 files changed

Lines changed: 635 additions & 91 deletions

File tree

‎docs/07-build-mcpp.md‎

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,37 @@ If your `build.mcpp` also needs to *write* a generated file, mix in a textual
9292
stdout protocol above remains the low-level substrate; `import mcpp;` is the typed
9393
layer over it.
9494

95+
## Environment contract (mcpp 0.0.95+)
96+
97+
The running program receives the build context as `MCPP_*` variables
98+
(Cargo's env-family equivalent), also exposed through typed readers:
99+
100+
| Variable | Typed reader | Value |
101+
|---|---|---|
102+
| `MCPP_TARGET` | `mcpp::target()` | resolved canonical triple (the `--target` triple under cross; the host triple natively) |
103+
| `MCPP_HOST` | `mcpp::host()` | the host triple |
104+
| `MCPP_PROFILE` | `mcpp::profile()` | effective profile name (`dev`/`release`/…) |
105+
| `MCPP_OUT_DIR` | `mcpp::out_dir()` | a writable scratch/output dir owned by mcpp |
106+
| `MCPP_MANIFEST_DIR` | `mcpp::manifest_dir()` | the package root (= CWD) |
107+
| `MCPP_FEATURE_<NAME>` | `mcpp::has_feature("name")` | set to `1` per active feature (same `<NAME>` sanitization as the `MCPP_FEATURE_` compile macro) |
108+
| `MCPP_FEATURES` | — | comma-separated active feature list |
109+
110+
These values are folded into the re-run key **unconditionally** — changing the
111+
target, profile, or feature set re-runs the program without any
112+
`rerun-if-env-changed` declaration.
113+
114+
## Dependencies' build.mcpp (mcpp 0.0.95+)
115+
116+
A dependency that ships a `build.mcpp` gets it compiled and run too (the
117+
Cargo `build.rs` model — building a package means trusting its build program),
118+
after its features are resolved and before the source scan. Scope follows
119+
Cargo: `cxxflag`/`cflag`/`cfg` directives color **only that package's own
120+
TUs**; `link-lib`/`link-search` reach the final link. Its artifacts (binary,
121+
cache, `MCPP_OUT_DIR`) live in the **consuming project's**
122+
`target/.build-mcpp/deps/<pkg>@<ver>/` — a registry package root is shared
123+
across projects (and may be read-only), so it is never written to; relative
124+
`generated=` paths resolve against `MCPP_OUT_DIR`, not the package root.
125+
95126
## Incremental: declared inputs (no needless re-runs)
96127

97128
mcpp does **not** re-run `build.mcpp` on every build. It caches the program's
@@ -113,11 +144,11 @@ When nothing changed you'll see `build.mcpp up to date (cached)`; otherwise
113144

114145
## Notes & limits
115146

116-
- **Runs on the host.** `build.mcpp` compiles and runs with the host toolchain.
117-
Under a cross build (`mcpp build --target <triple>`) it is **skipped with a
118-
warning** for now (host-toolchain-for-cross is a planned follow-up). Gate
119-
*dependencies* on the target with `[target.'cfg(...)']` tables instead — those
120-
evaluate on the resolved target. See [05 - mcpp.toml Manifest Guide](05-mcpp-toml.md).
147+
- **Runs on the host — including under cross** (mcpp 0.0.95+). Under
148+
`mcpp build --target <triple>` the program is compiled with a host-resolved
149+
toolchain, runs on the host, and sees `MCPP_TARGET` = the cross triple.
150+
For purely declarative target gating, `[target.'cfg(...)']` tables remain
151+
the first choice — see [05 - mcpp.toml Manifest Guide](05-mcpp-toml.md).
121152
- **CWD is the project root**, so relative paths (`src/generated.cpp`) land where
122153
you expect.
123154
- A non-zero exit from `build.mcpp` aborts the build and prints its output.

‎docs/zh/07-build-mcpp.md‎

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,33 @@ int main() {
8686
只有 `import std;` 是不必要的。上面的裸 stdout 协议仍是底层基底;`import mcpp;` 是其上的
8787
类型化层。
8888

89+
## 环境契约(mcpp 0.0.95+)
90+
91+
运行中的程序以 `MCPP_*` 环境变量得到构建上下文(对应 Cargo 的环境变量族),
92+
也有类型化读取端:
93+
94+
| 变量 | 类型化读取 | 值 |
95+
|---|---|---|
96+
| `MCPP_TARGET` | `mcpp::target()` | 解析后的 canonical 三元组(交叉构建下是 `--target` 三元组,原生构建是宿主) |
97+
| `MCPP_HOST` | `mcpp::host()` | 宿主三元组 |
98+
| `MCPP_PROFILE` | `mcpp::profile()` | 生效 profile 名(`dev`/`release`/…) |
99+
| `MCPP_OUT_DIR` | `mcpp::out_dir()` | mcpp 提供的可写输出/暂存目录 |
100+
| `MCPP_MANIFEST_DIR` | `mcpp::manifest_dir()` | 包根(= CWD) |
101+
| `MCPP_FEATURE_<NAME>` | `mcpp::has_feature("name")` | 每个活跃 feature 置 `1`(`<NAME>` 消毒规则与 `MCPP_FEATURE_` 编译宏一致) |
102+
| `MCPP_FEATURES` | — | 活跃 feature 逗号列表 |
103+
104+
这些契约值**无条件**折入重跑键——换 target、换 profile、开关 feature 都会触发重跑,
105+
不需要任何 `rerun-if-env-changed` 声明。
106+
107+
## 依赖包的 build.mcpp(mcpp 0.0.95+)
108+
109+
带 `build.mcpp` 的依赖包也会被编译并运行(Cargo `build.rs` 模型——构建一个包
110+
即信任其构建程序),时机在其 feature 解析之后、源扫描之前。作用域照 Cargo:
111+
`cxxflag`/`cflag`/`cfg` 指令只染色**该包自身的 TU**;`link-lib`/`link-search`
112+
到达终链。其产物(二进制、缓存、`MCPP_OUT_DIR`)放在**消费方工程**的
113+
`target/.build-mcpp/deps/<pkg>@<ver>/` 下——registry 包根跨工程共享(且可能只读),
114+
绝不写入;相对 `generated=` 路径按 `MCPP_OUT_DIR` 解析,而非包根。
115+
89116
## 增量:声明输入(避免无谓重跑)
90117

91118
mcpp **不会**每次构建都重跑 `build.mcpp`。它会缓存程序产出的指令,只有当它依赖的东西
@@ -106,9 +133,9 @@ mcpp **不会**每次构建都重跑 `build.mcpp`。它会缓存程序产出的
106133

107134
## 说明与限制
108135

109-
- **在主机上运行。** `build.mcpp` 用主机工具链编译并运行。在交叉构建
110-
(`mcpp build --target <triple>`)下目前会**跳过并给出警告**(主机工具链交叉是计划中的
111-
后续项)。要按目标平台门控*依赖*,请改用 `[target.'cfg(...)']` 表——它们按解析后的目标
112-
求值。参见 [05 - mcpp.toml 工程文件指南](05-mcpp-toml.md)。
136+
- **在主机上运行——交叉构建下也是**(mcpp 0.0.95+)。`mcpp build --target <triple>`
137+
下,程序用宿主解析的工具链编译、在宿主运行,并看到 `MCPP_TARGET` = 交叉三元组。
138+
纯声明式的目标门控仍首选 `[target.'cfg(...)']` 表——参见
139+
[05 - mcpp.toml 工程文件指南](05-mcpp-toml.md)。
113140
- **当前工作目录是工程根目录**,因此相对路径(`src/generated.cpp`)会落在你预期的位置。
114141
- `build.mcpp` 非零退出会中止构建并打印其输出。

‎mcpp.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mcpp"
3-
version = "0.0.94"
3+
version = "0.0.95"
44
description = "Modern C++ build & package management tool"
55
license = "Apache-2.0"
66
authors = ["mcpp-community"]

0 commit comments

Comments
 (0)