Skip to content

Commit 0de80d7

Browse files
committed
2026.9.28.3: SPEC-007 section 9, SPEC-008, the chapters and the changelog for #734; the design record
1 parent c49d127 commit 0de80d7

20 files changed

Lines changed: 1699 additions & 18 deletions

‎.agents/docs/2026-09-28-build-cost-foreign-toolsets-and-library-surface-design.md‎

Lines changed: 1221 additions & 0 deletions
Large diffs are not rendered by default.

‎.agents/docs/README.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ superseded_by: 2026-09-07-....md # when status is superseded
1818
---
1919
```
2020

21-
315 records.
21+
316 records.
2222

2323
## By subject
2424

@@ -31,6 +31,7 @@ Records that declare one. Everything else is listed by date below.
3131
### design
3232

3333
- [An ecosystem design for mcpp and xlings: one authority per fact, and the work that follows from it](2026-09-28-ecosystem-design-and-optimisation-plan.md) — landed
34+
- [Build cost, foreign toolsets, the build-plugin architecture and the library surface: engine, plugin and index design (#734)](2026-09-28-build-cost-foreign-toolsets-and-library-surface-design.md) — active
3435
- [The compile database, `emit build-database`, and #701/#702: triage against the specifications, and one design](2026-09-26-compile-database-and-issue-699-design.md) — landed
3536
- [Issues #693 to #696: triage against mcpp's contracts, and one repair plan](2026-09-25-issues-693-696-triage-and-repair-plan.md) — landed
3637
- [Workspace inheritance, flag scoping and the published form: a unified repair plan (#690)](2026-09-25-issue-690-workspace-build-inheritance-consistency.md) — landed
@@ -108,6 +109,7 @@ Records that declare one. Everything else is listed by date below.
108109

109110
- [Two days of mcpp and xlings: a review of what merged, what is known, and what is open](2026-09-28-ecosystem-review-of-two-days-of-mcpp-and-xlings.md) — active
110111
- [An ecosystem design for mcpp and xlings: one authority per fact, and the work that follows from it](2026-09-28-ecosystem-design-and-optimisation-plan.md) — landed
112+
- [Build cost, foreign toolsets, the build-plugin architecture and the library surface: engine, plugin and index design (#734)](2026-09-28-build-cost-foreign-toolsets-and-library-surface-design.md) — active
111113
- [Eight reports after 2026.9.27.1: implementation plan](2026-09-27-eight-reports-implementation-plan.md) — active
112114
- [Eight reports after 2026.9.27.1: what each one is, where it belongs, and one optimisation plan](2026-09-27-eight-reports-by-home-and-one-optimisation-plan.md) — active
113115
- [The compile database, `emit build-database`, and #701/#702: triage against the specifications, and one design](2026-09-26-compile-database-and-issue-699-design.md) — landed

‎CHANGELOG.md‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,56 @@
33
> 本文件追踪 `mcpp-community/mcpp` 公开仓的版本演进。
44
> 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)。
55

6+
## [2026.9.28.3] - 2026-09-28
7+
8+
本版本实施 #734 设计中 mcpp 的部分:构建插件体系的三层(`mcpp.core`、官方通用库、插件)、
9+
构建信息、工作区成员只构建一次、批量放置、`pack -p`、库接口规范的第一阶段与包的版本下限。
10+
设计、测量、任务划分与实施记录见
11+
`.agents/docs/2026-09-28-build-cost-foreign-toolsets-and-library-surface-design.md`,规范见
12+
SPEC-007 §9 与新的 SPEC-008。配套的 mcpp-plugins 0.17.0 以本版本为下限。
13+
14+
### 行为变化
15+
16+
- **被其他成员以 path 依赖使用的工作区成员只构建一次(E1)。** 消费方构建之前,成员在自己的目录中
17+
作为自身构建的根构建一次,由它的 ninja 判断过期(包括成员根目录之外的头文件);消费方经 stage
18+
边取得其对象与 BMI,按内容比较。条件是成员在消费方图中的构建键输入与它作为根时相等
19+
(`package.index` 除外,它只记来源);不相等时照旧在消费方图中编译,`-v` 写出不同的输入。同时
20+
构建的两个消费方以文件锁轮流使用成员目录。一个五成员 Windows 工作区的核心库此前被编译三次。
21+
- **程序旁的文件由一个进程放置(E4)。** 程序的 deploy 条目在两条及以上时成为一条 `stage_list`
22+
边,读取规划写出的 `placements.list`;`mcpp stage --list` 对每个目的地保持单文件语义。在
23+
Windows 首次构建上,1270 条单文件放置耗时 4.5 s,一个进程复制同样的文件耗时 0.5 s。
24+
- **库接口的第一阶段(E6,SPEC-008)。** `mcpp pack` 写出未进入发布闭包的导出模块(W2),"Withheld"
25+
一行列出每个未发布的单元(此前没有接口根时显示 "(nothing)",而两个导出模块既未发布也未列出);
26+
`mcpp build` 在包导入依赖的非公开模块时警告(W3);缺少接口根的警告写明对 `mcpp pack` 的后果
27+
(W1)。全部为警告。
28+
29+
### 特性
30+
31+
- **`mcpp.core`(E8,协议 14)。** 引擎接口以 `mcpp.core` 为名,`mcpp` 是永久等价的写法。
32+
- **构建信息(E2,协议 14)。** `mcpp::tool(role)`、`abi_tool(role)`、`tool_env()`、
33+
`toolset_identity()`、`msvc_instance_dir()`、`ninja_program()`、`cxx_runtime()`、
34+
`msvc_crt_linkage()` 以事实陈述解析出的工具链与程序的 C++ 运行时契约,取自引擎自身命令行所读的
35+
同一来源。
36+
- **结构化诊断(E11,协议 14)。** `mcpp::report({severity, message, impact, hint})` 以引擎的形式
37+
呈现,进入 JSON 输出,缓存命中时重放。
38+
- **缺失的构建程序模块指出 feature(E7)。** 模块只在依赖未启用的 feature 之后提供时,错误写出包名、
39+
feature 名与应加的一行。
40+
- **插件模块的名字(E10)。** `mcpp.<自己的命名空间>.*` 不再被警告;保留的第二段(`core`、
41+
`plugins`、`deps`、`rules`、`dist`、`tools`)只属于命名空间 `mcpp` 的包。
42+
- **`mcpp pack -p <member>`(E3)。** 在工作区根目录打包某个成员,结果与在成员目录中打包相同。
43+
- **包的版本下限(E9)。** `[package] mcpp = ">=<release>"` 与 `[workspace.package] mcpp`;
44+
低于下限的引擎在其他工作之前停止,写出升级命令;只接受 `>=`。
45+
- **`[lib]` 报告未知键(E12)。** 此前拼错的 `path` 被静默接受。
46+
- **快路径说明拒绝原因(E5 的测量部分)。** `-v` 下每个拒绝点写出其条件。
47+
48+
### 兼容性
49+
50+
- 协议升至 14:使用 §9 新接口的构建程序在旧引擎上编译失败并指出缺少的名字;以
51+
`[package] mcpp` 声明下限的包在旧引擎上得到一条"不支持的键"警告。
52+
- 升级后的第一次构建各付一次代价:每个构建程序因上下文新增变量而重新运行一次;被共享的工作区
53+
成员在消费方中改为暂存,其对象在成员目录中编译一次;程序旁的放置边形状改变而运行一次(内容相同
54+
的文件不重写)。
55+
656
## [2026.9.28.2] - 2026-09-28
757

858
本版本实施 2026-09-28 生态设计中 mcpp 的部分(WS1、WS2、WS3、WS7、WS8、WS10 与决定 D7),关闭

‎docs/04-mcpp-toml.md‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,22 @@ mcpp does not read is reported, as in `[build]`: a warning, and an error under
103103
resources = "res"
104104
```
105105

106+
`mcpp = ">=<release>"` (mcpp 2026.9.28.3+) states the oldest mcpp release the
107+
package supports. It is a floor, not a pin: the release a project installs is
108+
the one `.xlings.json` names. Only the `>=` form is accepted, because a bare
109+
release means "exactly" elsewhere in mcpp; a bare release and a value that is
110+
not a release are refused with the spelling that is meant. An engine below the
111+
floor stops before any other work, naming the package, the floor, its own
112+
release and the command that installs a newer one. `[workspace.package] mcpp`
113+
states it once for every member. An engine older than 2026.9.28.3 ignores the
114+
key with a warning.
115+
116+
```toml
117+
[package]
118+
name = "myplugin"
119+
mcpp = ">=2026.9.28.3"
120+
```
121+
106122
#### Dialect flags and the `import std` BMI
107123

108124
Some flags change what the standard library's headers declare, so the precompiled `import std`
@@ -1022,6 +1038,10 @@ path = "src/capi/lua.cppm" # Override the default lib-root location
10221038
```
10231039

10241040
Default convention: `src/<last segment of package name>.cppm` (e.g. package name `mcpplibs.cmdline` → `src/cmdline.cppm`).
1041+
`path` is the only key of the table; any other key is reported, as in `[build]`
1042+
(mcpp 2026.9.28.3+). The lib root is the interface root of SPEC-008: the module a
1043+
packed library publishes, with what it re-exports, and the module a build
1044+
program imports from a host-module dependency.
10251045
### 2.5 `[dependencies]`, `[dev-dependencies]`, `[build-dependencies]`
10261046

10271047
Moved to [05 — Dependencies and Resolution](05-dependencies.md).

‎docs/07-workspace.md‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,28 @@ fan-out continues; a timed-out build fails that member; `--workspace-timeout` st
413413
the fan-out and lists what did not run instead of leaving the CI job to kill the
414414
process (which discards everything it had to say).
415415

416+
### 5.4 A member used by other members is built once (mcpp 2026.9.28.3+)
417+
418+
A member that other members use as a path dependency is built once, in its own
419+
directory, and every member that uses it takes its objects and module
420+
interfaces from there. A `--workspace` build and separate `-p` builds of two
421+
programs therefore compile a shared library member once, where each program
422+
used to compile it again in its own directory.
423+
424+
- **Staleness is the member's own.** Before a consumer builds, the member's
425+
own build runs, and its ninja decides what is stale, including an input
426+
outside the member's root (a header under `../3rdParty`).
427+
- **Equal build keys are the condition.** The member's build key in the
428+
consumer's graph must equal its key as the root of its own build; the key
429+
covers the toolchain, the flags, the profile and the features. A member that
430+
a consumer builds differently (another feature set, for example) is compiled
431+
in that consumer's graph, as before; `-v` states the input that differs.
432+
- **One build at a time.** Two consumers built at once take turns on the
433+
member's directory.
434+
- **Scope.** The rule applies in the default cache mode (`--cache off` compiles
435+
everything in the graph that asks for it) and to members only; a path
436+
dependency outside the workspace has one consumer and keeps its behaviour.
437+
416438
## 6. Directory Layout
417439

418440
The recommended directory layout for a workspace:

‎docs/10-pack-and-release.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ mcpp pack --profile dev # build with a different profile (default
147147
mcpp pack --dev # the same, as `build` and `run` spell it; --profile wins over it
148148
mcpp pack --message-format json # one mcpp.pack envelope on stdout (mcpp 2026.9.16.1+)
149149
mcpp pack --no-strip # ship the artifacts as built
150+
mcpp pack -p app --format release # a workspace member, as if run in its directory
150151
mcpp pack --debug-symbols dbg/ # write the separated *.debug files under dbg/
151152
mcpp pack --format msi --features installer # activate root-package features for the pack
152153
```
@@ -158,6 +159,11 @@ one distribution is declared under `[feature-deps.<f>]` with `tools = [...]` and
158159
only by the pack that names `<f>`. `mcpp run --format <name> --features <LIST>` hands
159160
the same features to the pack it performs.
160161

162+
`-p <member>` (mcpp 2026.9.28.3+) packs a workspace member from the workspace
163+
root: the member is resolved as every other `-p` resolves it, and the pack runs in
164+
its directory, so the result is the one `mcpp pack` in that directory produces. A
165+
relative `-o` keeps meaning the directory the command was typed in.
166+
161167
`--release` and `--dev` (mcpp 2026.9.16.1+) are the shorthands `build` and `run`
162168
take, with the same precedence: `--profile` wins over either, on all three
163169
commands.

‎docs/12-binary-distribution.md‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,23 @@ error: the published interface imports mathkit:secret , which no unit in this
137137
Restructure so the interface does not reach it, or make it an `export module`
138138
partition and accept that its source is published.
139139

140+
### Public modules, and what `mcpp pack` and `mcpp build` report (mcpp 2026.9.28.3+)
141+
142+
A package's public modules are the lib root's module and what it re-exports
143+
with `export import`, transitively (SPEC-008). They are what a consumer may
144+
import; the published closure also carries what they import without
145+
re-exporting, because a consumer needs it to build their interfaces. The
146+
"Withheld" row lists every unit that is not published, including when the
147+
package has no lib root. The three conditions below are warnings: a library may
148+
implement itself in modules and publish only headers, and only its author can
149+
state which it means.
150+
151+
| Condition | Reported by | Consequence stated |
152+
|---|---|---|
153+
| a `lib` target exports modules and has no lib root | `mcpp build`, for the package being built | `mcpp pack` publishes the library without a module interface |
154+
| exported modules that the packed form does not ship | `mcpp pack`, naming each module | a consumer of the packed form cannot import them |
155+
| the package being built imports a module of a dependency that has a lib root, outside its public modules | `mcpp build`, naming the module and the public ones | the build succeeds from source and fails against the packed form |
156+
140157
## The compatibility tag
141158

142159
Every artifact records the toolchain it was built for:

‎docs/30-build-mcpp.md‎

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,91 @@ one. `mcpp::graph_file()` names a JSON document that states the resolved graph:
10561056
- The entries are the `graph` section of `resolution.json` with four additions
10571057
(`manifest_dir`, `features`, `targets`, `metadata`), from one derivation.
10581058

1059+
### The interface's name: `mcpp.core` (protocol 14)
1060+
1061+
The engine's build-program interface is named `mcpp.core`, which is the name the
1062+
specification (SPEC-007) gives to the layer. `mcpp` is its permanent equivalent:
1063+
the engine embeds both units, and the second consists of `export import mcpp;`.
1064+
A program may use either spelling, or both.
1065+
1066+
```cpp
1067+
import mcpp.core; // the same symbols as `import mcpp;`
1068+
```
1069+
1070+
### Build information: the resolved toolchain (protocol 14)
1071+
1072+
A build program reads the resolved toolchain as a set of facts. mcpp does not
1073+
translate them for any foreign build system; a plugin that drives CMake, vcpkg,
1074+
Meson or make does. Every value is empty when it does not apply, and a role is
1075+
one of `cc`, `cxx`, `ld`, `ar`, `rc`, `as`, `mt`.
1076+
1077+
| Accessor | Value |
1078+
|---|---|
1079+
| `mcpp::tool(role)` | the row's tool for the role: the driver on a GNU-style row, the toolset's tools on the cl.exe row |
1080+
| `mcpp::abi_tool(role)` | the target ABI's native tool: on the MSVC ABI `cl`, `link`, `lib`, `ml64` and the SDK's `rc` and `mt`, whichever driver the row uses; elsewhere the same as `tool(role)` |
1081+
| `mcpp::tool_env()` | the environment the engine runs the ABI's tools with, one `KEY=value` per line (`INCLUDE`, `LIB`, `PATH` on the MSVC ABI) |
1082+
| `mcpp::toolset_identity()` | a path-free identity such as `msvc 14.44.35207; sdk 10.0.26100.0` or `clang 22.1.8` |
1083+
| `mcpp::msvc_instance_dir()` | the Visual Studio instance the MSVC toolset belongs to; empty for a managed toolset |
1084+
| `mcpp::ninja_program()` | the ninja mcpp itself runs |
1085+
| `mcpp::cxx_runtime()` | the program's C++ runtime contract: `self-contained`, `toolchain-coupled` or `host-coupled` |
1086+
| `mcpp::msvc_crt_linkage()` | on the MSVC ABI `static` (`/MT`) or `dynamic` (`/MD`), the value `place-dlls` reads |
1087+
1088+
The values enter the build program's context, so every build program runs once
1089+
more after an upgrade to the release that introduced them.
1090+
1091+
### Structured diagnostics: `mcpp::report` (protocol 14)
1092+
1093+
A diagnostic stated with `mcpp::report` is rendered in the engine's form: the
1094+
message, then an `impact:` line and a `hint:` line. It reaches
1095+
`--message-format json` with the same fields, a `degraded` one fails the build
1096+
under `--strict`, and a cached run reports it again. `mcpp::warning(text)` stays,
1097+
and equals a diagnostic with a message only.
1098+
1099+
```cpp
1100+
mcpp::report({.severity = "warning",
1101+
.message = "the generator found no schema",
1102+
.impact = "no bindings are generated",
1103+
.hint = "add schema/*.proto"});
1104+
```
1105+
1106+
### Placing many files at once: `mcpp stage --list`
1107+
1108+
`mcpp stage --list <file>` places every `<source>\t<destination>` pair of the
1109+
file in one process. Each destination keeps the single-file semantics: an equal
1110+
destination is not written, a write goes out of place, and several sources for
1111+
one destination must agree. The engine places the deploy entries of a program
1112+
with one such edge when there are two or more; an action may call
1113+
`${mcpp.self} stage --list` as well.
1114+
1115+
```text
1116+
data/a.txt bin/data/a.txt
1117+
data/b.txt bin/data/b.txt
1118+
```
1119+
1120+
### The names of a plugin's modules
1121+
1122+
A module a build program imports may use the `mcpp.` prefix to state that it is
1123+
an mcpp plugin, under its package's own namespace. The engine warns when a
1124+
module outside namespace `mcpp` uses a reserved second segment or another
1125+
namespace; mcpp-index applies the same rule when it admits a package.
1126+
1127+
| Module name | Provided by |
1128+
|---|---|
1129+
| `mcpp`, `mcpp.core` | the engine |
1130+
| `mcpp.plugins.*`, `mcpp.deps.*`, `mcpp.rules.*`, `mcpp.dist.*`, `mcpp.tools.*` | packages in namespace `mcpp` |
1131+
| `mcpp.<namespace>.*` | packages in that namespace |
1132+
1133+
### A module behind a feature that is not enabled
1134+
1135+
When a build program imports a module that a dependency offers only behind a
1136+
feature, the error names the package and the feature:
1137+
1138+
```text
1139+
error: build.mcpp imports 'mcpp.rules.qt'
1140+
provided by: mcpp.plugins, feature "rules-qt" (not enabled)
1141+
hint: enable it on the dependency edge: mcpp.plugins = { ..., features = ["rules-qt"] }
1142+
```
1143+
10591144
### `import mcpp;` is the surface that evolves (mcpp 2026.8.5.1+)
10601145

10611146
Two ways to talk to mcpp, and they carry **different compatibility promises**:
@@ -1107,10 +1192,12 @@ if constexpr (requires { mcpp::runner("qemu"); }) // hard error when absent
11071192
```
11081193
11091194
A `requires`-expression over a **qualified name that does not exist** is
1110-
ill-formed, not `false`. So there is no in-language feature probe, and a
1111-
package that adopts a new directive states its floor in prose (its README) and
1112-
relies on the diagnostic above. Such a package should name the mcpp version it
1113-
requires.
1195+
ill-formed, not `false`. So there is no in-language feature probe. A package
1196+
that adopts a new directive states its floor in its manifest,
1197+
`[package] mcpp = ">=<release>"` (mcpp 2026.9.28.3+, docs/04): an engine below
1198+
the floor stops before compiling anything and names the release to install. An
1199+
older engine ignores the key with a warning, and the diagnostic above remains
1200+
what it reports.
11141201
11151202
### `import std;` (mcpp 2026.8.2.1+)
11161203

‎docs/README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,4 @@ downstream tooling.
163163
- [SPEC-005 — The build database `mcpp emit build-database` prints](specs/build-database.md)
164164
- [SPEC-006 — Toolchain management: identity, origin, selection and the payload contract](specs/toolchain-management.md)
165165
- [SPEC-007 — Build plugins: configuration, construction and verification, and the runtime and planning obligations](specs/build-plugins.md)
166+
- [SPEC-008 — A library's interface: public modules, the published closure, and one interface in both forms](specs/library-interface.md)

‎docs/specs/README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
| [SPEC-004](manifest-semantics.md) | `mcpp.toml` 的平面划分、条件化形状、解析轴与命名规约 | 草案 v1.10 | 2026-09-28 | 条件化形状 mcpp >= 2026.8.29.1;目标轴 mcpp >= 2026.9.6.4;`linkage` 默认值 mcpp >= 2026.9.15.2;链接 flag 的词读法 mcpp >= 2026.9.26.2;条件化的 `dialect_cxxflags` 与 `-p` 的包身份 mcpp >= 2026.9.28.1;条件表按具体程度生效 mcpp >= 2026.9.28.2 |
3737
| [SPEC-005](build-database.md) | 构建数据库:`mcpp emit build-database` 的内容、取值规则与不写工程目录的保证 | 评审中 v1.5 | 2026-09-28 | mcpp >= 2026.9.15.1;v1.3 条款 mcpp >= 2026.9.26.2;v1.4 条款 mcpp >= 2026.9.27.1;v1.5 条款 mcpp >= 2026.9.28.1 |
3838
| [SPEC-006](toolchain-management.md) | 工具链管理:身份、来源、选择与载荷契约 | 草案 v0.4 | 2026-09-28 | 逐条标注;已实现条款 mcpp >= 2026.9.24.1;§3.7 mcpp >= 2026.9.28.1;§3.7.1 mcpp >= 2026.9.28.2 |
39-
| [SPEC-007](build-plugins.md) | 构建插件:配置、施工与校验的分工,运行时与规划期的义务 | 草案 v0.5 | 2026-09-28 | 逐条标注;mcpp >= 2026.9.26.2;v0.3 条款 mcpp >= 2026.9.27.1;v0.4 条款 mcpp >= 2026.9.28.1;v0.5 条款 mcpp >= 2026.9.28.2 |
39+
| [SPEC-007](build-plugins.md) | 构建插件:配置、施工与校验的分工,运行时与规划期的义务 | 草案 v0.6 | 2026-09-28 | 逐条标注;mcpp >= 2026.9.26.2;v0.3 条款 mcpp >= 2026.9.27.1;v0.4 条款 mcpp >= 2026.9.28.1;v0.5 条款 mcpp >= 2026.9.28.2;v0.6(§9)mcpp >= 2026.9.28.3 |
40+
| [SPEC-008](library-interface.md) | 库的接口:公开模块、发布闭包与两种形态的一致 | 草案 v0.1 | 2026-09-28 | 第一阶段(只警告)mcpp >= 2026.9.28.3 |
4041

4142
## 文档约定
4243

0 commit comments

Comments
 (0)