Skip to content

Commit 9e31f50

Browse files
committed
feat(emit): mcpp emit build-database, the plan as a build database written into nothing (#636)
`mcpp emit build-database` plans as `mcpp build --configure-only` plans, with the same selectors, and prints the plan as an S1 build database (C++ Build Database: IDE Profile 0.2.0, a profile of WG21 P2977R2) without writing into the project. `--spec compile-commands` prints compile_commands.json entries instead; `--format json` wraps the document in the mcpp.build-database envelope; `-o <file>` writes it atomically. docs/specs/build-database.md (SPEC-005) states the rules. The document is S1 level 2: one set per package plus <package>:test and mcpp:std; visible-sets lists every other set, because the engine resolves imports over one module graph; each unit's arguments come from the record the compile database renders; ide.role is the declaration form the scanner read. Five engine changes make the no-write planning exact: - BuildOverrides::work_dir had two writes that ignored it (the multi-version mangling stage, and the root package's generated_files, which are now compared rather than written under plan_only); - the std module is described without being compiled (describe_std_module, the derivation ensure_built builds from); - the std units' commands are recovered from the commands mcpp runs, so the std cache identity does not change; - compile_commands and the build database render one UnitInvocation record; - the scanner records the module declaration form (ModuleDeclaration). mcpp.lock is read from the project and never written back; a difference is the warning MCPP_LOCK_WOULD_CHANGE. Planning narration goes to stderr through a descriptor-level redirect. A failure envelope omits data. Tests: BuildDatabase.* unit tests drive the real gcc and clang std command builders; Scanner.DeclarationFormIsRecordedAsRead; CompileCommandsEmit.UnitInvocationsAreTheCompileDatabaseArguments; WireGolden.NullDataIsOmitted; e2e 688 validates the output against the vendored S1 schema and uses --configure-only as the control leg for the no-write criterion.
1 parent 62bc752 commit 9e31f50

30 files changed

Lines changed: 2675 additions & 89 deletions

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,39 @@
55

66
## [Unreleased]
77

8+
### `mcpp emit build-database`:不写工程目录的构建数据库(#636)
9+
10+
新命令按 `mcpp build --configure-only` 的方式、用相同的选择器规划,把计划打印为
11+
S1「C++ Build Database: IDE Profile」0.2.0(WG21 P2977R2 的一个 profile)文档,不写入
12+
工程目录;`--spec compile-commands` 改为打印 `compile_commands.json` 的条目,
13+
`--format json` 用 `mcpp.build-database` 信封包裹,`-o <file>` 原子写入文件。规则见
14+
SPEC-005(`docs/specs/build-database.md`)。
15+
16+
- 文档满足 S1 等级 2:每个包一个集合,另有 `<包>:test` 与 `mcpp:std`;`visible-sets`
17+
列出其余所有集合,因为引擎在一张模块图上解析 import;每个单元的 `arguments` 与
18+
`compile_commands.json` 取自同一条记录;`ide.role` 取自扫描器读到的声明形式。
19+
- 规划写到 `$MCPP_HOME/cache/build-database/<key>`:`BuildOverrides::work_dir` 此前有
20+
两处写入不跟随它(多版本改名的暂存目录、根包 `generated_files`),现已修正;标准库
21+
模块只描述不编译(`describe_std_module`);`mcpp.lock` 从工程读取、从不写回,不一致时
22+
给出 `MCPP_LOCK_WOULD_CHANGE` 警告。
23+
- 标准库模块单元的命令从 mcpp 实际运行的构建命令中还原,std 缓存目录的身份不变。
24+
- 信封增加约定:失败时省略 `data`。`--protocol-version` 声明该命令的效应,不含
25+
`write-project`。
26+
- 测试:单测 `BuildDatabase.*`、`Scanner.DeclarationFormIsRecordedAsRead`、
27+
`CompileCommandsEmit.UnitInvocationsAreTheCompileDatabaseArguments`、
28+
`WireGolden.NullDataIsOmitted`;e2e 688 以随仓的 S1 schema 校验输出,并以
29+
`--configure-only` 作对照腿证明工程目录未被写入。
30+
31+
### Windows 上不再每条命令都打印 "The system cannot find the path specified."
32+
33+
vendored xlings 的版本探针以命令串 `<xlings> --version 2>/dev/null` 运行。Windows 上
34+
命令串交给 cmd.exe,它打不开 `/dev/null`:除首次外的每条命令都打印这句提示,xlings
35+
没有运行,探针返回空版本,于是 vendored xlings 从不按 pin 更新。`mcpp.platform.process`
36+
增加 `capture_stdout`:直接运行程序、只捕获标准输出、丢弃标准错误、标准输入为空,
37+
Windows 上重定向写 cmd.exe 自己的空设备;xlings 版本探针与另外四个带 POSIX 语法、
38+
Windows 可达的探针改用它。(单测 `CaptureStdout.*`、
39+
`XlingsVersionPin.ProbeReadsStandardOutputThroughTheLauncher`,e2e 687)
40+
841
### 在已激活的 xlings subos 中运行时,registry 不再被重定向(2026.9.14.3)
942

1043
`xlings subos use <name>` 打开的 shell 导出 `XLINGS_ACTIVE_SUBOS`,xlings 解析 subos

docs/01-getting-started.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,19 @@ Run it only in a trusted workspace. The process exit code and the resulting
152152
`compile_commands.json` are the stable integration contract; stdout remains
153153
human-readable.
154154

155+
An editor that must not write into the project asks for the same plan on stdout
156+
*(mcpp 2026.9.15.1+)*:
157+
158+
```bash
159+
mcpp emit build-database --format json
160+
```
161+
162+
The document is an S1 build database: every translation unit with its compile
163+
command, the modules it provides and requires, the toolchain and the standard
164+
library units. `--spec compile-commands` prints `compile_commands.json` entries
165+
instead. The fields are listed in [50 — Machine-Readable Output](50-machine-output.md),
166+
and the rules in [SPEC-005](specs/build-database.md).
167+
155168
## Incremental Compilation and Testing
156169

157170
```bash

docs/50-machine-output.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ for `mcpp.xpkg`, with no way to tell which actually changed.
5959
`effects` is always present. An empty array means "nothing"; an absent array
6060
would mean "unknown", which is a different claim.
6161

62+
`data` is present whenever the command produced its document. A command that
63+
failed before it had one omits `data` rather than sending an empty object, and
64+
its `diagnostics` state why; `mcpp.build-database` is such a kind (§8).
65+
6266
### Diagnostics
6367

6468
```jsonc
@@ -403,6 +407,42 @@ payload and run a dependency's build program. A client gates on that table
403407
*before* running anything, so an omission would be a safety claim that is not
404408
true.
405409

410+
### `mcpp.build-database` — the build plan as a build database *(mcpp 2026.9.15.1+)*
411+
412+
```
413+
mcpp emit build-database [--spec s1|compile-commands] --format json
414+
```
415+
416+
It plans as `mcpp build --configure-only` plans, with the same selectors, and
417+
writes nothing into the project. `data` is:
418+
419+
| field | |
420+
|---|---|
421+
| `spec` | `{"name": "s1", "version": "0.2.0"}`, or `{"name": "compile-commands"}` with `--spec compile-commands` |
422+
| `database` | the document of that specification: an S1 build database, or the entries `mcpp build --configure-only` writes to `compile_commands.json` |
423+
| `watch` | the inputs whose change can change the document: paths and glob patterns relative to the workspace root, or absolute paths |
424+
| `inputs-fingerprint` | `fnv1a:<16 hex digits>`, a digest of those inputs, the mcpp version and the selectors |
425+
426+
Without `--format`, the command prints the document alone; `-o <file>` writes
427+
whatever it would print to `<file>` instead. The content of the document, the
428+
no-write guarantee and the `watch` rules are
429+
[SPEC-005](specs/build-database.md).
430+
431+
A failure omits `data` and exits 1, with the diagnostic code
432+
`MCPP_BUILD_DATABASE_NO_PROJECT` outside a project or
433+
`MCPP_BUILD_DATABASE_PLAN_FAILED` when planning fails. Warnings leave the
434+
document in place:
435+
436+
| code | |
437+
|---|---|
438+
| `MCPP_LOCK_WOULD_CHANGE` | the resolution differs from the project's `mcpp.lock`, which the command does not write |
439+
| `MCPP_GENERATED_FILE_NOT_MATERIALIZED` | a root `[build] generated_files` entry is missing or stale on disk, and the command does not write it |
440+
| `MCPP_BUILD_DATABASE_STD_UNIT_UNDESCRIBED` | no standard-library build command names its module source, so that unit is not listed |
441+
442+
`--protocol-version` declares `init-mcpp-home`, `read-project`, `network`,
443+
`write-global-cache` and `exec-build-script` for the command, and never
444+
`write-project`.
445+
406446
### `mcpp test --message-format json` — the test stream
407447

408448
```

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,4 @@ downstream tooling.
160160
- [SPEC-002 — The target side: reserved namespace, five layers, three rules](specs/target-side.md)
161161
- [SPEC-003 — The exit-code contract](specs/exit-codes.md)
162162
- [SPEC-004 — `mcpp.toml` planes, conditioning shape, resolution axes and naming](specs/manifest-semantics.md)
163+
- [SPEC-005 — The build database `mcpp emit build-database` prints](specs/build-database.md)

docs/specs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
| [SPEC-002](target-side.md) | 目标侧模型与能力声明(`mcpp:` 保留命名空间、五层、三条规则) | 评审中 v1.0 | 2026-08-24 | mcpp >= 2026.8.24.2 |
3535
| [SPEC-003](exit-codes.md) | 退出码契约(分类、语义、稳定性承诺) | 评审中 v1.0 | 2026-09-01 | mcpp >= 2026.9.1.1 |
3636
| [SPEC-004](manifest-semantics.md) | `mcpp.toml` 的平面划分、条件化形状、解析轴与命名规约 | 草案 v1.0 | 2026-09-07 | 条件化形状 mcpp >= 2026.8.29.1;目标轴未实现 |
37+
| [SPEC-005](build-database.md) | 构建数据库:`mcpp emit build-database` 的内容、取值规则与不写工程目录的保证 | 评审中 v1.0 | 2026-09-14 | mcpp >= 2026.9.15.1 |
3738

3839
## 文档约定
3940

docs/specs/build-database.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# SPEC-005:构建数据库(`mcpp emit build-database`)
2+
3+
|||
4+
|---|---|
5+
| 规范编号 | SPEC-005 |
6+
| 标题 | mcpp 输出的构建数据库:内容、取值规则与不写工程目录的保证 |
7+
| 状态 | 评审中 v1.0 |
8+
| 版本 | 1.0 |
9+
| 最后修改 | 2026-09-14 |
10+
| 对应实现 | mcpp >= 2026.9.15.1 |
11+
| 相关设计文档 | `.agents/docs/2026-09-14-636-build-database-and-the-latest-xlings.md` |
12+
| 相关 issue | #636 |
13+
| 依据的外部规范 | S1「C++ Build Database: IDE Profile」profile 0.2.0 与 S2 0.2.0 §3.4,取自 https://github.com/Sunrisepeak/lsp-mcpp-private 提交 `b82859d`(schema 自提交 `28ecd6e` 起未变);JSON Compilation Database |
14+
15+
## 0. 适用范围
16+
17+
本规范规定 `mcpp emit build-database` 输出的文档、文档中每个字段取自构建计划的
18+
哪一部分,以及这条命令对工程目录的保证。文档格式由 S1 与 JSON Compilation
19+
Database 定义,本规范不重复它们的字段定义,只规定 mcpp 作为生产方的义务。消费方
20+
的行为(监视、防抖、超时、把文档补全到 S1 等级 3)不属于本规范。
21+
22+
规范用语与实现状态标记见 [规范索引](README.md)
23+
24+
## 1. 命令与文档
25+
26+
| 调用 | 标准输出 |
27+
|---|---|
28+
| `mcpp emit build-database` | S1 文档 |
29+
| `mcpp emit build-database --spec compile-commands` | JSON Compilation Database |
30+
| 以上任一加 `--format json` | [docs/50](../50-machine-output.md) 的信封,文档在 `data.database` |
31+
| 以上任一加 `-o <file>` | 无;原本写到标准输出的内容原子地写入 `<file>` |
32+
33+
- **R1.1** `--spec` 的取值为 `s1`(默认)与 `compile-commands`。其他取值是用法错误:
34+
标准输出为空,退出码为 2。**已实现**
35+
- **R1.2** 选择器与 `mcpp build` 相同:`--target``--toolchain``--profile`
36+
`--release``--dev``--features``--cap``--accel``--no-accel``--static`
37+
`--strict``-p`/`--package``--workspace`。同一组选择器下,文档描述的构建计划
38+
`mcpp build --configure-only` 计算的计划相同;包有测试时,计划包含测试目标与
39+
dev-dependency。**已实现**
40+
- **R1.3** 规划过程的叙述写到标准错误,标准输出只有文档或信封。**已实现**
41+
42+
## 2. 不写工程目录
43+
44+
- **R2.1** 命令**禁止**写入工程目录,即根包、工作区成员与 path 依赖的源码树。规划
45+
写入 `$MCPP_HOME/cache/build-database/<key>`,`<key>` 由工程根与成员决定。该目录
46+
是缓存,可以随时删除。**已实现**
47+
- **R2.2** 标准库模块被描述而不被编译。对没有构建程序的工程,命令不启动任何编译器。
48+
**已实现**
49+
- **R2.3** `mcpp.lock` 从工程根读取,从不写回。规划得出的解析与工程中的锁不一致,
50+
或工程中没有锁而规划会写出一份时,输出警告 `MCPP_LOCK_WOULD_CHANGE`**已实现**
51+
- **R2.4** 根包 `[build] generated_files` 中缺失或内容与声明不一致的文件不被写入,
52+
每个输出一条警告 `MCPP_GENERATED_FILE_NOT_MATERIALIZED`**已实现**
53+
- **R2.5** 构建程序照常运行,工作目录为包根,与 `mcpp build` 相同;构建程序在
54+
`MCPP_OUT_DIR` 之外写入的内容不在本保证之内。依赖提供的宿主工具照常构建到全局
55+
工具库。**已实现**
56+
- **R2.6** `mcpp --protocol-version` 为这条命令声明 `init-mcpp-home``read-project`
57+
`network``write-global-cache``exec-build-script`,不声明 `write-project`
58+
**已实现**
59+
60+
## 3. S1 文档
61+
62+
mcpp 输出的 S1 文档满足 S1 等级 2,不输出 `ide.options`。等级 3 所需的结构化选项由
63+
缺少 `options` 的一方按 S1 §9 规则 1 从 `arguments` 推导。
64+
65+
### 3.1 工具链
66+
67+
- **R3.1** `ide.toolchains` 的键为 `<family>-<version>-<triple>`,其中 `family`
68+
mcpp 的族名(`gcc``llvm``msvc`),`triple` 是编译器自身的拼写。键对消费方不
69+
透明,在一份文档内稳定。**已实现**
70+
- **R3.2** `family``gcc``clang``msvc``driver` 为构建调用的驱动的绝对路径;
71+
`target` 为编译器自身拼写的目标三元组;构建使用 sysroot 时给出 `sysroot`;`stdlib`
72+
给出 `name`(`libstdc++``libc++``msvc-stl``other`)与 `version`,不给出
73+
`module-metadata`,标准库模块经 §3.4 的单元解析。**已实现**
74+
75+
### 3.2 集合
76+
77+
- **R3.3** 每个包一个集合,名为包的限定名(`<namespace>.<name>``<name>`)。根包
78+
测试目标的源文件归入集合 `<包>:test`,标准库模块的单元归入集合 `mcpp:std`。工作区
79+
文档中,每个集合名带前缀 `<成员>/`**已实现**
80+
- **R3.4** `visible-sets` 列出同一成员的其余所有集合。引擎在一次调用的一张模块图上
81+
解析 import,更窄的闭包会描述一条构建并不执行的规则。**已实现**
82+
- **R3.5** `family-name` 为包名,`mcpp:std` 集合的为 `mcpp:std`;`ide.configuration`
83+
为 profile 名;`ide.kind` 在测试集合为 `test`,在根包集合按其目标为 `library`
84+
`executable``other`,在依赖包集合与 `mcpp:std``library`**已实现**
85+
- **R3.6** 不输出 `baseline-arguments``local-arguments`**已实现**
86+
87+
### 3.3 翻译单元
88+
89+
- **R3.7** 除 NASM 单元外,构建计划中的每个编译单元是一个翻译单元。`source`
90+
`work-directory``arguments``object``compile_commands.json` 中对应条目的
91+
`file``directory``arguments``output` 取自同一条记录,因而逐字相同。
92+
**已实现**
93+
- **R3.8** `provides` 把单元提供的模块名映射到空字符串,命令不执行构建(S1-8-6);
94+
`requires` 为单元导入的模块名,分区写全名 `M:P`。不输出 `private`,即 `false`
95+
**已实现**
96+
- **R3.9** `ide.role` 取自扫描器读到的模块声明形式:
97+
98+
| 声明 | `ide.role` |
99+
|---|---|
100+
| 无模块声明 | `non-module` |
101+
| `export module M;` | `module-interface` |
102+
| `export module M:P;` | `module-partition-interface` |
103+
| `module M:P;` | `module-partition-implementation` |
104+
| `module M;` | `module-implementation` |
105+
| `scan_overrides` 声明的单元;P1689 扫描中无法区分实现单元与导入者的单元 | `unknown` |
106+
107+
**已实现**
108+
109+
### 3.4 标准库模块
110+
111+
- **R3.10** 构建导入 `std` 时,`mcpp:std` 集合包含 `std` 的单元;工具链有 `std.compat`
112+
的构建命令时,还包含 `std.compat` 的单元。`provides` 分别为 `std``std.compat`,
113+
`std.compat``requires``std`,角色均为 `module-interface`。该规则对工具链
114+
自带的标准库(GCC 的 `bits/std.cc`、libc++ 的 `std.cppm`、MSVC STL 的 `std.ixx`)与
115+
依赖包提供的 `std.cppm` 相同。**已实现**
116+
- **R3.11** 这些单元的 `arguments``work-directory` 来自 mcpp 构建该模块时运行的
117+
命令:mcpp 为宿主 shell 渲染的命令去掉 `cd`、环境变量赋值与重定向,再撤销引号。
118+
命令中找不到该源文件时,不列出该单元,并输出警告
119+
`MCPP_BUILD_DATABASE_STD_UNIT_UNDESCRIBED`**已实现**
120+
121+
## 4. `--spec compile-commands`
122+
123+
- **R4.1** 文档为 `mcpp build --configure-only` 在同一组选择器下写入
124+
`compile_commands.json` 的条目,差别只在输出路径位于 §2 的工作目录之下。标准库模块
125+
的单元不在其中。**已实现**
126+
127+
## 5. 信封
128+
129+
- **R5.1** `kind``mcpp.build-database`,`kindVersion` 为 1。`data``spec`
130+
(`{"name": "s1", "version": "0.2.0"}``{"name": "compile-commands"}`)、
131+
`database``watch``inputs-fingerprint`**已实现**
132+
- **R5.2** 失败时信封不含 `data`,`diagnostics` 至少含一条 `error`,退出码为 1:不在
133+
工程中为 `MCPP_BUILD_DATABASE_NO_PROJECT`,规划失败为
134+
`MCPP_BUILD_DATABASE_PLAN_FAILED`,工作区中其消息指出成员。工作区中任一成员规划
135+
失败,整次命令失败。**已实现**
136+
- **R5.3** 信封的 `effects``read-project``write-global-cache`,运行了构建程序时
137+
另有 `exec-build-script`**已实现**
138+
139+
## 6. `watch``inputs-fingerprint`
140+
141+
- **R6.1** `watch` 列出:工作区根与每个源码包的 `mcpp.toml`;`mcpp.lock`;存在时的
142+
`build.mcpp`;每个源码包的源文件 glob;测试发现的 glob(`[test] discover`,默认
143+
`tests/**/*.cpp`);构建程序声明的输入文件与 glob;`$MCPP_HOME/config.toml`。位于
144+
工作区根之下的条目写成相对工作区根、以 `/` 分隔的路径或 glob;之外的条目写成绝对
145+
路径,其 glob 展开为运行时匹配到的文件。**已实现**
146+
- **R6.2** 不监视:环境变量,包括 `MCPP_TOOLCHAIN``MCPP_HOME` 与构建程序声明的
147+
环境变量;存储中的包与 git 依赖的检出,它们的版本或提交写在已监视的清单与锁中。
148+
**已实现**
149+
- **R6.3** `inputs-fingerprint` 形如 `fnv1a:<16 位十六进制>`,是 mcpp 版本、选择器与
150+
`watch` 在运行时匹配到的每个文件的路径与内容的摘要;这些输入不变时它不变。它与
151+
构建指纹无关。**已实现**
152+
- **R6.4** 命令不写入 `watch` 列出的任何文件,这由 §2 保证。**已实现**
153+
154+
## 7. 变更记录
155+
156+
| 版本 | 日期 | 变更 |
157+
|---|---|---|
158+
| 1.0 | 2026-09-14 | 首版(#636)。 |

docs/zh/01-getting-started.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ target 和 toolchain 解析结果。生成的 `compile_commands.json` 同时覆
136136
workspace 中运行。插件稳定依赖进程退出码和生成的 `compile_commands.json`,标准输出仍是
137137
面向人的文本,不作为机器协议。
138138

139+
不允许写入工程目录的编辑器在标准输出上取得同一份计划 *(mcpp 2026.9.15.1+)*:
140+
141+
```bash
142+
mcpp emit build-database --format json
143+
```
144+
145+
文档是 S1 构建数据库:每个翻译单元及其编译命令、它提供与导入的模块、工具链以及标准库
146+
模块单元。`--spec compile-commands` 改为输出 `compile_commands.json` 的条目。字段见
147+
[50 —— 机器可读输出](50-machine-output.md),规则见 [SPEC-005](../specs/build-database.md)
148+
139149
## 增量编译与测试
140150

141151
[08 —— 测试](08-testing.md) 是拥有这个主题的章节;下面只是本教程需要的那一步。

docs/zh/50-machine-output.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ mcpp 不支持所请求的内容。
4444

4545
`effects` 永远存在。空数组表示「没有」;字段缺失会表示「未知」,那是另一个断言。
4646

47+
命令产出了它的文档时 `data` 存在。命令在得到文档之前就失败时省略 `data`,而不是
48+
给一个空对象,原因写在 `diagnostics` 里;`mcpp.build-database` 就是这样的 kind(§8)。
49+
4750
### 诊断
4851

4952
```jsonc
@@ -355,6 +358,37 @@ mcpp why toolchain [--target <triple>] [--toolchain <spec>] --format json
355358
解析,而那可能拉取包、安装载荷、并运行某个依赖的构建程序。客户端是在**运行之前**
356359
读这张表来决定放不放行的,漏报一项就是一句不成立的安全承诺。
357360

361+
### `mcpp.build-database` —— 以构建数据库表达的构建计划 *(mcpp 2026.9.15.1+)*
362+
363+
```
364+
mcpp emit build-database [--spec s1|compile-commands] --format json
365+
```
366+
367+
它按 `mcpp build --configure-only` 的方式、用相同的选择器规划,不写入工程目录。
368+
`data` 为:
369+
370+
| 字段 | |
371+
|---|---|
372+
| `spec` | `{"name": "s1", "version": "0.2.0"}`;使用 `--spec compile-commands` 时为 `{"name": "compile-commands"}` |
373+
| `database` | 该规范的文档:S1 构建数据库,或 `mcpp build --configure-only` 写入 `compile_commands.json` 的条目 |
374+
| `watch` | 变化后可能改变文档的输入:相对工作区根的路径与 glob,或绝对路径 |
375+
| `inputs-fingerprint` | `fnv1a:<16 位十六进制>`,上述输入、mcpp 版本与选择器的摘要 |
376+
377+
不带 `--format` 时命令只输出文档;`-o <file>` 把原本输出的内容写入 `<file>`。文档的
378+
内容、不写工程目录的保证与 `watch` 的规则见 [SPEC-005](../specs/build-database.md)
379+
380+
失败时省略 `data` 并以 1 退出:不在工程中时诊断码为 `MCPP_BUILD_DATABASE_NO_PROJECT`,
381+
规划失败时为 `MCPP_BUILD_DATABASE_PLAN_FAILED`。警告不影响文档:
382+
383+
| 诊断码 | |
384+
|---|---|
385+
| `MCPP_LOCK_WOULD_CHANGE` | 解析结果与工程的 `mcpp.lock` 不一致,命令不写这个文件 |
386+
| `MCPP_GENERATED_FILE_NOT_MATERIALIZED` | 根包 `[build] generated_files` 中的某个文件缺失或内容过期,命令不写这个文件 |
387+
| `MCPP_BUILD_DATABASE_STD_UNIT_UNDESCRIBED` | 没有标准库构建命令点名其模块源文件,该单元不被列出 |
388+
389+
`--protocol-version` 为这条命令声明 `init-mcpp-home``read-project``network`
390+
`write-global-cache``exec-build-script`,从不声明 `write-project`
391+
358392
### `mcpp test --message-format json` —— 测试流
359393

360394
```

docs/zh/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,3 +155,4 @@
155155
- [SPEC-002 —— 目标侧模型:保留命名空间、五层、三条规则](../specs/target-side.md)
156156
- [SPEC-003 —— 退出码契约](../specs/exit-codes.md)
157157
- [SPEC-004 —— `mcpp.toml` 的平面划分、条件化形状、解析轴与命名规约](../specs/manifest-semantics.md)
158+
- [SPEC-005 —— `mcpp emit build-database` 输出的构建数据库](../specs/build-database.md)

0 commit comments

Comments
 (0)