Skip to content

Commit bba733a

Browse files
committed
2026.9.27.1: tests, specs and docs for #704-#716; xlings version vectors; faster ELF reads
Tests. e2e 802 (#704: a host build applies its host row, under either spelling) and 803 (#716: a recorded payload that is gone is refused offline, naming the address and the record). Unit tests for #713 (a member inherits the root's [xlings.workspace] entries and rows; its own wins), #714 (an unresolved `workspace = true` is named in every dependency table) and #710 (a member tool reads its workspace's toolchain; its own wins), for which prepare exports host_tool_declared_toolchain. Version selection. mcpp.xpkg_version gains select_installed, the one rule `mcpp::xpkg_dir` answers with (a literal name, then the xlings grammar, then the highest), and runs the conformance vectors xlings publishes, vendored as modules/versioning/tests/data/semver-vectors.tsv. ELF inspection reads a file with one sized read; filling the vector through an istreambuf_iterator made the post-link check of `mcpp test` take tens of minutes. Specs: SPEC-001 v1.5 (version answers follow xlings; packaging revision), SPEC-004 v1.8 (host row, workspace clauses 8-10, a dependency's programs), SPEC-007 v0.3 (action env/cwd, planning defers host tools, feature tools, artifacts). Docs 04, 05, 06, 07 and 30 in English and Chinese. CHANGELOG and version 2026.9.27.1. Not built or run in this session; the handover lists the verification that remains. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MajuX4J8ewFeWvZJjzRJt5
1 parent c136000 commit bba733a

25 files changed

Lines changed: 929 additions & 65 deletions

‎CHANGELOG.md‎

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

6+
## [2026.9.27.1] - 2026-09-27
7+
8+
### 缺陷修复(#704、#705、#710、#712 至 #716)
9+
10+
- **宿主构建读取宿主三元组的行(#704)。** 不带 `--target` 的构建此前不读取
11+
`[target.<宿主三元组>]`,其中的 `cxx_runtime` 没有效果。现在宿主构建应用这一行,与
12+
`--target <宿主三元组>` 相同,行的查找与拼写无关;`--toolchain` 仍优先于行的 `toolchain`
13+
(SPEC-004 §4.6)。
14+
- **`xpkg_dir` 回答 xlings 装下的载荷(#712、#716)。** 版本位按 xlings 的版本文法求值,
15+
`libglvnd@1.7` 回答 `1.7.0.1`。xlings 在 `install_targets` 事件中报告每个请求解析到的载荷,
16+
mcpp 按地址记录并优先读取。安装记录仍在而载荷已被删除时,联网构建重新安装,离线构建拒绝并
17+
点名缺失的地址;构建缓存记录读取过的载荷目录,任一目录缺失时快路径不复用缓存。mcpp 以
18+
xlings 发布的版本选择向量测试同一规则(SPEC-001 §10.1)。
19+
- **宿主工具的工具链由请求方决定一次(#710)。** 顺序为 `--toolchain`、工具包自己的声明(工作
20+
空间成员先继承根位置的键)、请求方的宿主工具链;结果传给子构建并写入工具库的键。工具包的源树
21+
摘要跳过带自己 `mcpp.toml` 的子目录,并以 UTF-8 计算路径(#705)。
22+
- **工作空间(#713、#714)。** 成员隐式继承根的 `[xlings.workspace]` 条目与条件行,自己声明的
23+
同一个包优先。未解析的 `workspace = true` 在根包、`-p` 成员与各类依赖处都被点名拒绝;带
24+
`[package]` 的工作空间根解析自己的条目。`[build] sources = []` 不再推断库目标。
25+
- **规则只经其声明的扩展名到达(#715)。** 一个规则只在包含它声明的设备源扩展名时进入包的合成
26+
构建程序;状态行只列出实际生效的规则。
27+
28+
### 规划不构建宿主工具(#707)
29+
30+
`mcpp emit build-database` 不再构建依赖提供的宿主工具。工具库中已有的工具照常使用;没有的工具被
31+
推迟,报告为 note `MCPP_BUILD_DATABASE_HOST_TOOL_DEFERRED`,请求它的构建程序收到该工具将被发布的
32+
路径。它取代 2026.9.26.2 的警告 `MCPP_BUILD_DATABASE_HOST_TOOL_UNBUILT`(SPEC-005 v1.4 R2.5)。
33+
`mcpp build` 不受影响。
34+
35+
### 构建程序与依赖边(#708、#709、#711)
36+
37+
- **action 的 `env` 与 `cwd`(协议 13,#708)。** `mcpp::action::env(name, value)` 与
38+
`cwd(dir)` 由引擎的 action 包装器应用;`cwd` 按包根解析,声明的输入、输出与 stamp 不随它
39+
移动;变量值改变时 action 重新运行。两者都未声明的 action 命令行与协议 12 逐字节相同。
40+
- **特性的 `tools`(#709)。** `[features.<f>] tools = ["<bin>"]` 陈述特性需要本包的程序在
41+
构建机器上运行;启用该特性的消费方得到该工具,与边上写 `tools` 相同。
42+
- **`artifacts` 依赖边(#711)。** `x = { path = "...", artifacts = ["<bin>"] }` 以消费方的
43+
目标与 profile 构建依赖的程序,输出到消费方的 `bin/`,不链接依赖的代码;action 以
44+
`${mcpp.artifact:<x>/<bin>}` 引用它;`mcpp pack` 把它放在程序旁(SPEC-004 §10、
45+
SPEC-007 R6.4)。
46+
47+
### 载荷的打包修订与自包含的 locale(xlings#620、#621)
48+
49+
- 依赖的索引条目的 `revision` 进入依赖完整性判断:修订号不同的已安装依赖按未安装处理。修订号
50+
大于 0 的运行时载荷进入运行时契约(`revision=<n>`),修订号变化使依赖它的产物重新链接;修订号
51+
为 0 时契约文本不变(SPEC-001 §10.2)。
52+
- `mcpp pack` 的 bundle-all 形态随 glibc 载荷复制 `lib/locale` 与 `lib/gconv`,启动脚本设置
53+
`LOCPATH` 与 `GCONV_PATH`(用户已设置时保留用户的值)。
54+
55+
### 其他
56+
57+
- ELF 检查以一次读取载入文件。此前逐字节读入,`mcpp test` 的链接后检查在测试程序较多时耗时
58+
数十分钟。
59+
- 规范:SPEC-001 v1.5、SPEC-004 v1.8、SPEC-005 v1.4、SPEC-007 v0.3。
60+
661
## [2026.9.26.2] - 2026-09-26
762

863
### 编译数据库:一个配置一个数据库(#699 的报告;#397 C-1、#677 B1)

‎docs/04-mcpp-toml.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1780,6 +1780,7 @@ kind = "bin"
17801780
|---|---|---|
17811781
| Source files | `src/**/*.{cppm,cpp,cc,c,S,s,asm}` | Scanned recursively and automatically |
17821782
| Entry point | `src/main.cpp` | If this file exists, a `bin` target is inferred |
1783+
| Library target | a module interface under `src/` | Inferred when no `[targets]` table and no `src/main.cpp` exist; `[build] sources = []` states that the default build compiles nothing and infers no library (2026.9.27.1+) |
17831784
| Library root | `src/<pkg-tail>.cppm` | Override with `[lib].path` |
17841785
| C++ standard | `c++23` | Configure with `[package].standard`; supports `c++20` / `c++26` / `c++2a` / `c++2c` / `gnu++NN` / `c++latest` / `c++fly` (experimental playground) |
17851786
| C standard | `c11` | `.c` files go through the C compiler automatically |

‎docs/05-dependencies.md‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,67 @@ and refused, and the refusal says to restate the source. `tools`, `features`,
448448
effect on the row. A restatement that names another source is refused, naming
449449
both sources (mcpp 2026.9.16.1+); before that release it was ignored.
450450

451+
**Which compiler builds a tool (mcpp 2026.9.27.1+).** The build that requests
452+
a tool decides its toolchain once: `--toolchain` when given; otherwise the tool
453+
package's own declaration, read as its own build reads it (for a workspace
454+
member, after the workspace root's `[toolchain]`, `[target.<triple>]` and
455+
`[indices]`), its host row's `toolchain` before `[toolchain]`; otherwise the
456+
host toolchain the requesting build compiles its build programs with. The
457+
choice is passed to the tool's sub-build and recorded in the tool store key, so
458+
`mcpp build -p <tool>` in the workspace and the same tool built for a consumer
459+
use the same compiler. The source digest of a tool package skips directories
460+
that hold their own `mcpp.toml`, so editing a workspace member does not rebuild
461+
a tool the workspace root provides.
462+
463+
### A feature that provides the package's tools (mcpp 2026.9.27.1+)
464+
465+
A package whose feature needs one of its own programs on the build machine
466+
states it on the feature, and a consumer names only the feature:
467+
468+
```toml
469+
# the tool package
470+
[features.codegen]
471+
tools = ["codegen"]
472+
473+
[targets.codegen]
474+
kind = "bin"
475+
main = "src/codegen.cpp"
476+
```
477+
478+
```toml
479+
# the consumer
480+
[dependencies]
481+
toolpkg = { path = "../toolpkg", features = ["codegen"] }
482+
```
483+
484+
Enabling the feature has the effect of `tools = ["codegen"]` on the edge: the
485+
program is built for the host and `mcpp::dep_bin("toolpkg", "codegen")` names
486+
it. A consumer that does not enable the feature builds nothing. An entry that
487+
names no `bin` target of the package is refused when the manifest loads, and the
488+
message lists the package's `bin` targets.
489+
490+
### A dependency's program shipped with the consumer: `artifacts` (mcpp 2026.9.27.1+)
491+
492+
`tools` builds a program for the machine that runs the build. A program that
493+
ships with the consumer and runs on its target (an updater, a helper process)
494+
is requested with `artifacts`:
495+
496+
```toml
497+
[dependencies]
498+
updater = { path = "../updater", artifacts = ["updater"] }
499+
```
500+
501+
- The dependency's `bin` target is built for the consumer's target and profile,
502+
as a link unit of the consumer's plan, into the consumer's `bin/`. Under
503+
`--target x86_64-linux-musl` it is a musl program.
504+
- None of the dependency's code is linked into the consumer through this edge.
505+
A package also reached through an ordinary edge is linked as usual.
506+
- An action of the consumer's build program names the program with
507+
`${mcpp.artifact:updater/updater}`, in its arguments and its inputs; a name
508+
that matches no `artifacts` entry fails planning and names the placeholder.
509+
- `mcpp run` does not choose it, and `mcpp pack` stages it beside the
510+
consumer's program.
511+
451512
> The section has been parsed since early versions and, until 2026.8.29.1, read
452513
> by nothing that made a decision: writing it produced a manifest that loaded,
453514
> no diagnostic, and no effect.

‎docs/06-features-and-capabilities.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ simd = { sources = ["src/simd/**"], flags = [
9494
```
9595

9696
- **The table form accepts exactly** `implies`, `forward`, `defines`, `sources`,
97-
`flags`, `requires`, `provides`. Anything else is reported as a schema warning
97+
`flags`, `requires`, `provides`, `tools`. Anything else is reported as a schema warning
9898
and ignored (mcpp 2026.9.1.1+); `deps` is reported separately as reserved and
9999
points at `[feature-deps.<name>]`. Before that release `[features]` was
100100
the one structured section with no schema check at all, so a misplaced
@@ -120,6 +120,11 @@ simd = { sources = ["src/simd/**"], flags = [
120120
feature `flags` are **private per-TU build flags** — they never propagate to
121121
consumers (same contract as `[build].flags`), so they stay inside the additive
122122
model: scoped by glob, deterministic order, no cross-package effect.
123+
- `tools` (mcpp 2026.9.27.1+) names `bin` targets of this package that the
124+
feature needs on the build machine. A consumer that enables the feature
125+
receives them as if its dependency edge had written `tools = [...]`
126+
([05, build-time dependencies](05-dependencies.md)); a name that is not a
127+
`bin` target of the package is refused at load.
123128

124129

125130
### A feature that is a build rule (mcpp 2026.9.7.1+)

‎docs/07-workspace.md‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ A member can override an inherited version:
133133
mbedtls = "4.0.0" # override; does not use the workspace version
134134
```
135135

136+
An entry that says `.workspace = true` and that no workspace resolves is
137+
refused wherever the package enters a build (the root, a member selected with
138+
`-p`, a `path`, `git` or index dependency), naming the table and the entry
139+
(mcpp 2026.9.27.1+). It is resolved against the `[workspace.dependencies]` of
140+
the workspace whose `members` list the package; a workspace root that carries
141+
its own `[package]` resolves its own entries the same way.
142+
136143
## 4. Inheriting Toolchain and Build Configuration
137144

138145
The workspace root's `[toolchain]` and `[target.<triple>]` settings are automatically inherited by all members. A member can override them in its own project file.
@@ -161,6 +168,22 @@ linkage = "static"
161168
default = "llvm@20.1.7"
162169
```
163170

171+
`[toolchain]`, `[target.<triple>]` and `[indices]` choose the compiler, the
172+
target rows and the indices for a whole graph, so a member takes them from the
173+
workspace root only where it is the root of a build: built from the workspace,
174+
with `-p`, or as a host tool of another package (mcpp 2026.9.27.1+ for the
175+
last). A member reached as a dependency takes them from that build's root.
176+
177+
A build without `--target` targets the host, and `[target.<host-triple>]`
178+
applies to it as `--target <host-triple>` would (mcpp 2026.9.27.1+).
179+
180+
The root's `[xlings.workspace]` entries, including its
181+
`[target.<selector>.xlings.workspace]` rows, are inherited implicitly as well
182+
(mcpp 2026.9.27.1+): a payload describes the environment a build runs in, like
183+
`[toolchain]`, so no opt-in is needed. A member's own declaration of the same
184+
package wins. `[feature-xlings.<f>]` entries are not inherited, because a
185+
feature belongs to the package that declares it.
186+
164187
### 4.1 `[workspace.package]` and `[workspace.build]`
165188

166189
Package metadata and build flags shared by every member are declared once at the

‎docs/30-build-mcpp.md‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,16 @@ position was compared against a directory name, so a range installed a payload
426426
and then answered that nothing was installed — which is why a rule package
427427
could not state a floor and every project repeated its rule's package list.
428428

429+
**The answer is the payload xlings installed** *(2026.9.27.1+)*. xlings reports
430+
what each address resolved to, and `xpkg_dir` answers from that record first.
431+
Without one, it selects among the installed version directories by the xlings
432+
version grammar: a bare version of one or two segments is a prefix range, three
433+
or more segments must match as written, so `libglvnd@1.7` answers `1.7.0.1`.
434+
Before this release the Cargo reading of `1.7` could not see a four-segment
435+
directory, and the answer was `""` for a payload on disk. A declared payload
436+
that was removed after it was installed is installed again, or refused
437+
offline, instead of answering `""` (SPEC-001 §10.1).
438+
429439
**A package a DEPENDENCY declared is answered too** *(2026.9.6.6+)*, at the
430440
version this build actually installed rather than the one the local manifest
431441
wrote. One package means one version: where a project and a rule both name it,
@@ -685,6 +695,47 @@ scan agrees with what the generator will emit — the same assertion-plus-
685695
verification trade `[modules].scan_overrides` makes, and the compiler's own
686696
P1689 output checks it at build time.
687697

698+
#### Environment and working directory: `env` / `cwd` (protocol 13)
699+
700+
An action's command is an argv, not a shell line, so `NAME=value cmd` and
701+
`cd dir && cmd` are not available to it. A generator configured through
702+
environment variables, or one that must run in a particular directory, states
703+
both on the action:
704+
705+
```cpp
706+
mcpp::action a;
707+
a.id = "gen";
708+
a.role = mcpp::roles::source;
709+
a.env("GEN_MODE", "release")
710+
.cwd("tools") // relative to the package root
711+
.arg("./gen").arg(out.c_str())
712+
.output(out.c_str())
713+
.submit();
714+
```
715+
716+
The engine's action wrapper sets them before it runs the command. Declared
717+
inputs, outputs and the stamp are resolved when the plan is made and do not
718+
move with `cwd`; the command's own arguments are passed unchanged, so a
719+
relative path among them is relative to `cwd`. A variable's value is part of
720+
the edge's command line, and changing it re-runs the action. An action that
721+
declares neither keeps the protocol 12 command line byte for byte.
722+
723+
#### A dependency's program in an action: `${mcpp.artifact:}` (2026.9.27.1+)
724+
725+
A dependency edge with `artifacts = ["<bin>"]` builds that program for the
726+
consumer's target ([05](05-dependencies.md)). An action names it with
727+
`${mcpp.artifact:<dependency>/<bin>}`, in its arguments and its inputs:
728+
729+
```cpp
730+
a.arg("cp").arg("${mcpp.artifact:updater/updater}").arg(out.c_str())
731+
.input("${mcpp.artifact:updater/updater}")
732+
.output(out.c_str())
733+
.submit();
734+
```
735+
736+
A placeholder that names no `artifacts` entry fails planning and is named in the
737+
error.
738+
688739
### Deploying what the program generated: `deploy` (2026.9.12.3+, protocol 11)
689740

690741
`[runtime] deploy` (docs/04 §2.11) places a file that already exists in the

‎docs/specs/build-plugins.md‎

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
|---|---|
55
| 规范编号 | SPEC-007 |
66
| 标题 | 构建插件:配置、施工与校验的分工,运行时与规划期的义务 |
7-
| 状态 | 草案 v0.2 |
8-
| 版本 | 0.2 |
9-
| 最后修改 | 2026-09-26 |
10-
| 对应实现 | 逐条标注。未注明版本的「已实现」条款对应 mcpp >= 2026.9.26.1;注明 mcpp#702 的条款对应 mcpp >= 2026.9.26.2 |
7+
| 状态 | 草案 v0.3 |
8+
| 版本 | 0.3 |
9+
| 最后修改 | 2026-09-27 |
10+
| 对应实现 | 逐条标注。未注明版本的「已实现」条款对应 mcpp >= 2026.9.26.1;注明 mcpp#702 的条款对应 mcpp >= 2026.9.26.2;注明 mcpp#707、#708、#709、#711 的条款对应 mcpp >= 2026.9.27.1 |
1111
| 相关设计文档 | `.agents/docs/2026-09-26-compile-database-and-issue-699-design.md`(§5) |
12-
| 相关 issue | mcpp#699、mcpp#701、mcpp#702、mcpp#703 |
12+
| 相关 issue | mcpp#699、mcpp#701、mcpp#702、mcpp#703、mcpp#707、mcpp#708、mcpp#709、mcpp#711 |
1313
| 使用文档 | [docs/30 - build.mcpp](../30-build-mcpp.md)、[docs/31 - 编写规则包](../31-authoring-a-rule-package.md) |
1414

1515
本规范规定构建插件对引擎和对消费方承担的义务,以及引擎为此提供的机制。docs/31 说明怎样编写
@@ -126,6 +126,12 @@
126126
下载的 action(例如由包管理器取得源码)**必须**在其说明中写明,并在离线构建中
127127
(`--offline` 或 `MCPP_OFFLINE=1`;前者在进程环境中设置后者,action 继承之)不访问网络:
128128
从缓存完成,或以指出缺失内容的消息失败。(作者义务;环境传递 **已实现**)
129+
- **R3.8** action 需要的环境变量与工作目录**必须**用 `env(name, value)` 与 `cwd(dir)` 声明
130+
(协议 13),**禁止**写成命令中的 shell 语法(`NAME=value cmd`、`cd dir &&`),因为 R3.1
131+
不假定 shell。引擎的 action 包装器在运行命令前设置它们:`cwd` 按声明包的根目录解析;声明的
132+
输入、输出与 stamp 在规划时解析为绝对路径,不受 `cwd` 影响;命令参数原样传给命令,其中的
133+
相对路径相对于 `cwd`。变量的值属于这条边的命令行,值改变时该 action 重新运行。两者都未
134+
声明的 action,其命令行与协议 12 逐字节相同。(**已实现**,mcpp#708)
129135

130136
## 4. 运行时:程序依赖的共享库的查找
131137

@@ -149,9 +155,11 @@
149155
的配置与构建相同。(**已实现**)
150156
- **R5.2** 一个包的构建程序在规划中失败时,该包只按其清单描述,并得到一条错误诊断;成员的
151157
其余部分照常描述。插件遵守 R1.2 时,环境不完整不会使构建程序失败。(**已实现**,mcpp#702)
152-
- **R5.3** 插件所需的宿主工具在规划中构建失败时,规划继续,构建程序收到该工具将被发布的路径,
153-
并产生一条警告。插件**应当**在 action 中运行宿主工具,而不是在构建程序中运行,使规划不依赖
154-
工具能否构建。(引擎部分 **已实现**,mcpp#702;「应当」为作者义务)
158+
- **R5.3** 规划不构建宿主工具(SPEC-005 R2.5)。全局工具库中已有的工具照常使用;没有的工具
159+
被推迟,规划产生一条 note `MCPP_BUILD_DATABASE_HOST_TOOL_DEFERRED`,点名工具与其所属包,
160+
请求它的构建程序收到该工具将被发布的路径。插件**应当**在 action 中运行宿主工具,而不是在
161+
构建程序中运行,使规划不依赖工具是否已经构建。(引擎部分 **已实现**,mcpp#707;此前规划
162+
构建宿主工具,构建失败时降级为警告,mcpp#702;「应当」为作者义务)
155163

156164
## 6. 环境与载荷
157165

@@ -160,6 +168,13 @@
160168
的包上:`xpkg_dir` 为正在构建的包回答;`host-module` 的声明对编入它的每个构建程序可见
161169
(docs/31)。(**已实现**)
162170
- **R6.2** 插件**禁止**探测宿主路径来寻找工具或 SDK;未声明的依赖不可复现。(作者义务)
171+
- **R6.3** 插件的某个特性需要本包的程序在构建机器上运行时,**应当**在该特性上声明
172+
`[features.<f>] tools = ["<bin>"]`,而不是要求每个消费方在依赖边上重复写 `tools`。启用该
173+
特性的消费方得到该工具,与边上写了 `tools` 相同(SPEC-004 §10.2)。(**已实现**,mcpp#709)
174+
- **R6.4** 一个需要随消费方发布、在消费方的目标上运行的程序(更新器、辅助进程)**必须**以依赖
175+
边的 `artifacts` 取得(SPEC-004 §10.3),**禁止**以 `tools` 取得:`tools` 为构建机器构建,
176+
交叉构建中得到错误架构的程序。action 以 `${mcpp.artifact:<依赖>/<目标>}` 引用它的路径。
177+
(**已实现**,mcpp#711)
163178

164179
## 7. 版本与兼容
165180

@@ -182,4 +197,5 @@
182197
| 版本 | 日期 | 变更 |
183198
|---|---|---|
184199
| 0.1 | 2026-09-26 | 首版草案(mcpp#699、#701、#702、#703)。 |
200+
| 0.3 | 2026-09-27 | 随 mcpp 2026.9.27.1:新增 R3.8(action 的 `env` 与 `cwd`,协议 13,mcpp#708);R5.3 改为规划不构建宿主工具、缺失的工具以 note 推迟(mcpp#707);新增 R6.3(特性的 `tools`,mcpp#709)与 R6.4(`artifacts` 与 `${mcpp.artifact:}`,mcpp#711)。 |
185201
| 0.2 | 2026-09-26 | 随 mcpp 2026.9.26.2 落地:R1.3 的警告、R2.1 的 `runtime_search_dir`、R2.4、R3.3 的 `prepare`(目录须含文件;链接边等待所有 `prepare`)、R3.5、R3.6、R4.1、R4.3、R5.2、R5.3 标为已实现。 |

0 commit comments

Comments
 (0)