Skip to content

Commit 5d6e408

Browse files
committed
docs(355): 记录真实案例验证结果 —— libprotoc 可构建,风险解除
设计文档 §11 标注的未核实风险(libprotoc 能否被 mcpp 无 CMake 构建)现在有答案: **能**。138 个 TU 全部编过,源码树无 .h.in/.cmake.in,唯一缺口是 upb 运行时, 而那是 compat.protobuf 已有的 feature —— 用 required_features 就能表达,零引擎改动。 ⇒ Phase 2 的 prebuilt provider 确认为纯优化,不是必需路径。 另记三个只有真实案例(Form B 包)才暴露的 bug,与一个 GCC modules 约束 (导出结构体里不要放大的值类型)。
1 parent 1737a17 commit 5d6e408

1 file changed

Lines changed: 60 additions & 0 deletions

File tree

.agents/docs/2026-08-05-issue355-dependency-host-tools-design.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,3 +808,63 @@ ninja 期执行、增量、并行;工具从本设计的 tool store 取。收
808808
- CMake cross:<https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html>
809809
LLVM `LLVM_NATIVE_TOOL_DIR` <https://reviews.llvm.org/D131052>
810810
- Zig build system:<https://ziglang.org/learn/build-system/>
811+
812+
---
813+
814+
## 13. 实施与真实案例验证(2026.8.5.1)
815+
816+
### 13.1 §11 第 4 步的「未核实风险」——已核实,结论是****
817+
818+
设计里写着:`compat.protobuf` 描述符明文「does NOT build libprotoc」,而
819+
**libprotoc 能否被 mcpp 无 CMake 构建出来尚未核实**;若不能,Phase 2 的
820+
prebuilt provider 就从「优化」升级为 protoc 的唯一可行路径。
821+
822+
拿真实的 mcpp-index + protobuf 35.1 源码实测:
823+
824+
- 上游 `src/file_lists.cmake``libprotoc_srcs` = **138 项**,与 libprotobuf 的
825+
源码集**零重叠**`importer.cc` / `parser.cc` 早已在 libprotobuf 里)
826+
- 源码树里**没有** `.h.in` / `.cmake.in` —— 不需要任何 configure 步骤
827+
- 138 个 TU 全部编过;第一次链接失败,缺 `upb_*` 符号 —— libprotoc 的 upb 生成器
828+
需要 upb 运行时,而那正是 compat.protobuf **已有**`upb` feature
829+
- 把 target 写成 `required_features = { "protoc", "upb" }`**链接通过**
830+
—— 这正是成本门机制该起的作用,**零引擎改动**
831+
832+
端到端:`protoc` 从源码建出 → `mcpp::dep_bin("protobuf","protoc")` 拿到路径 →
833+
`action` 调用它生成 `demo.pb.cc` / `demo.pb.h` → 编译链接 → 程序输出 `NAME=mcpp`
834+
store 命中实测:第二次 `rm -rf target` 后构建 **1.41s**,不重建 protoc。
835+
836+
**⇒ Phase 2(prebuilt-asset provider)确认为纯优化,不是必需路径。**
837+
838+
### 13.2 真实案例暴露的三个 bug(合成 e2e 全部漏掉)
839+
840+
四个新 e2e 都用 path 依赖,也就是 **Form A**(包自带 mcpp.toml)。真实索引里绝大
841+
多数是 **Form B**(compat 描述符,manifest 由 `.lua` 合成),protobuf 就是。这个
842+
差异一次性暴露了三个 bug:
843+
844+
| # | 问题 | 后果 |
845+
|---|---|---|
846+
| 1 | 子构建从 `<root>/mcpp.toml` 读 manifest,**Form B 包没有这个文件** | Form B 包**完全不能**当工具提供方 —— gRPC 那条链整个走不通 |
847+
| 2 | `targets.<x>.main` **不展开** `*/` 包装 glob(`sources` 一直会展开) | Form B 包的任何 bin target 都拿不到入口源码 |
848+
| 3 | `role=source`**全部**输出都被当成翻译单元 | protoc 的 `.pb.h``.pb.cc` 撞同一个对象路径 |
849+
850+
修法分别是:`BuildOverrides::preloaded_manifest`(由调用方交出**未经 feature 激活**
851+
的那份 manifest —— `packages[i].manifest` 是被 `apply()` 改过的副本,从它出发会把
852+
同一批 feature 源码折两次)、在 manifest 定稿后解析 `main` 的 glob、
853+
`is_compilable_output()` 按扩展名过滤。
854+
855+
**方法论**:合成测试测的是「我想到的形状」,真实案例测的是「现实的形状」。这三个
856+
bug 没有一个能靠再多写几个 path-依赖 e2e 发现。
857+
858+
### 13.3 一个 GCC modules 约束
859+
860+
`preloaded_manifest` 初版写成 `std::optional<Manifest>`,而 `BuildOverrides`
861+
**导出**结构体 —— GCC 写不出 module cluster:
862+
863+
```
864+
mcpp.build.prepare: error: failed to read compiled module cluster 529: Bad file data
865+
src/build/execute.cppm:52:45: fatal error: failed to load pendings for 'std::pair'
866+
```
867+
868+
`rm -rf target` 无效(不是陈旧 BMI)。换成 `shared_ptr<const Manifest>` 让导出布局
869+
保持 trivial 后即通过,顺带省掉每次工具构建的一次 manifest 拷贝。
870+
**导出结构体里不要放大的值类型。**

0 commit comments

Comments
 (0)