Skip to content

Commit 2ae6623

Browse files
committed
docs: publishing a workspace member, the index-archive member, CHANGELOG 2026.9.25.1, SPEC-004 criteria 13-14
1 parent c10876c commit 2ae6623

8 files changed

Lines changed: 163 additions & 10 deletions

‎.agents/docs/2026-09-25-issue-690-implementation-plan.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,10 @@ Each angle names the property it requires and the evidence that shows it.
7373

7474
## 5. Release chain
7575

76-
1. PR in `mcpp-community/mcpp` with the version 2026.9.25.1 in `mcpp.toml` and `modules/versioning/src/version.cppm`. All required checks green. Squash merge.
76+
1. PR in `mcpp-community/mcpp` with the version 2026.9.25.1 in `mcpp.toml` and `modules/versioning/src/version.cppm`, and the internal xlings pin at the latest xlings release (2026.9.20.1). All required checks green. Squash merge.
7777
2. `origin/main` HEAD run green.
7878
3. `release.yml` dispatched. Each archive is uploaded to GitCode with the local tools the moment it appears (`tools/mirror_res.sh` from xlings, GitCode leg only). GET 200 and byte comparison on both mirrors.
7979
4. `openxlings/xim-pkgindex` bump pull request merged. The published index artifact is read to confirm `latest`.
80-
5. Bootstrap pin pull request in `mcpp-community/mcpp` (`.xlings.json`). The open #689 is resolved first.
81-
6. `mcpp-community/mcpp-index`: CI run against the release. No package change is expected (the design's search found no package that relies on the root include broadcast). If a package fails, it is fixed in one pull request.
82-
7. Sandbox verification: `xlings subos use <n> --sandbox --cmd ...` with the CN mirror set for both xlings and mcpp inside the sandbox. It covers the #690 fixture, the git-member fixture, the F7 shadow fixture, a publish dry run of a workspace member, and a build of two representative index packages.
80+
5. `.xlings.json` (the mcpp that builds mcpp) is not moved: review of 2026-09-25 asked for no separate bootstrap pull request unless a build needs it.
81+
6. `mcpp-community/mcpp-index`: one pull request that moves its CI pins to 2026.9.25.1, which runs every member on every platform against the release. Before the release, 16 members were run locally with the candidate binary (all passed), and no member declares `include_dirs`, so the W6 change has no consumer-side reliance to break there.
82+
7. Sandbox verification: `.agents/docs/2026-09-25-issue-690-verify.sh` in `xlings subos use <n> --sandbox --cmd ...`, with the CN mirror set for both xlings and mcpp inside the sandbox, and the same script against 2026.9.24.1 as the control.

‎.agents/docs/2026-09-25-issue-690-workspace-build-inheritance-consistency.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ The decisions below are derived from these rules. Each rule names its source in
7575

7676
**F10 (measured during implementation): a member reached as a dependency does not resolve its own `x.workspace = true` entries.** A sibling `lib` whose manifest says `util.workspace = true` builds under `-p lib`. Under `-p app` it fails with `dependency 'util' has SemVer constraint '' but no readable index entry for it`. The dependency load site applied only `inherit_workspace_package`, so the entry reached resolution with neither version nor path. This is the same placement defect as F1, for the third part of what a member inherits.
7777

78+
**F11 (measured during implementation): a member inside an index package's archive does not inherit its archive's workspace.** A descriptor may point at a member manifest (`mcpp = "*/mcpp/cairo/mcpp.toml"`; 22 installed index packages on the measuring machine have a workspace root in their archive). The resolver loaded that manifest as a stand-alone file, so a member that omits `version` was refused and `[workspace.build]` was ignored, while the same commit consumed through `git` inherits (D1). None of the 22 installed archives declares `[workspace.package]`, `[workspace.build]` or `[workspace.dependencies]`, so applying the inheritance changes no existing package. It is applied through the same function as the sibling and git cases, searching no higher than the install root (e2e 774).
79+
7880
**F8 (reasoned): the F1 dependency's cache key records a define its compile does not carry.** `cache_key.cppm:534` reads `pkg.manifest.buildConfig.defines`, which retains the unfolded entries.
7981

8082
Root cause: the build half of inheritance runs inside the snapshot, after the fold.

‎CHANGELOG.md‎

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

6+
## [2026.9.25.1] - 2026-09-25
7+
8+
### 工作空间成员在每种位置上以相同方式编译(#690)
9+
10+
`[workspace.build]` 的继承此前在把清单固定进构建图的那一步执行,晚于 `defines` 的展开。
11+
作为兄弟成员 `path` 依赖被编译的成员因此收不到工作空间的 `defines`(#690 报告的情形),
12+
而被命令选中的根成员收到两份工作空间的 `cflags`、`cxxflags` 与 `ldflags`。现在成员在自己的
13+
加载处继承,顺序与根包相同:先继承,再合并条件节,最后展开 `defines`;固定进构建图的一步只读取
14+
结果,遇到未展开的 `defines` 时报告内部错误。
15+
16+
同一处还补上了两件同形的缺口:
17+
18+
- 作为依赖出现的成员解析自己的 `x.workspace = true` 条目。此前该条目以既无版本也无路径的形式
19+
进入解析,报出的是「no readable index entry」。
20+
- 通过 `git` 引用的、托管在 git 上的工作空间的成员,除 `[workspace.package]` 外,也继承所在仓库
21+
的 `[workspace.build]` 与 `[workspace.dependencies]`,相对路径以仓库根为锚点。同一个提交在它
22+
自己的检出中与在使用方的依赖图中以相同方式编译。
23+
- 索引描述符以 `mcpp = "<子目录>/mcpp.toml"` 指向归档内的成员时,该成员以同样方式取得归档中的
24+
工作空间;在归档内查找工作空间根不越出该版本的安装根。本机已安装的 22 个带工作空间根的索引包
25+
都没有声明可继承的表,这一变化不改变任何现有包。
26+
27+
`[workspace.build] ios_deployment_target` 此前被解析、被继承,却被已知键检查拒绝;可继承键现在
28+
只在一张表里陈述,解析、已知键检查与报错文本都取自这张表。
29+
30+
### `defines` 按宏名构成集合
31+
32+
`defines` 的条目按包接收它们的顺序合并:`[workspace.build]`、包自己的 `[build]`、命中的
33+
`[target.<selector>.build]`。同一宏名的后一个条目在原位替换前一个,条目 `!NAME` 移除该宏名,
34+
每个宏名只以一个 `-D` 词到达编译器。成员因此可以覆盖或移除继承来的宏,而不再产生重定义诊断
35+
(`-Werror` 下是错误)。`defines` 条目同样取代同一个包的 `cflags`、`cxxflags` 中同名的 `-D` 词。
36+
更早的 mcpp 会把 `!NAME` 作为 `-D!NAME` 交给编译器,使用它的包需要 mcpp 2026.9.25.1 或更新版本。
37+
38+
### 使用方的头文件目录不再进入依赖
39+
40+
根包的 `include_dirs` 与 `include_dirs_after`(包括 `private_include_dirs`)此前被写进
41+
`build.ninja` 的文件级编译标志,图中每个编译单元都读到它们:根包目录中与系统头或依赖头同名的
42+
文件会在依赖内部遮蔽它们。依赖缓存键不含这些目录,于是按一个工程的根包头文件编译出的依赖对象
43+
会被另一个无关工程取用(实测:`compat.cjson` 的 `cJSON_Compare(1.0, 1.2)` 在未写任何头文件的
44+
工程中答 1)。现在每个编译单元只收到自己的包的目录,以及它的依赖公开的目录;根包自己的编译单元
45+
中每个目录只出现一次。
46+
47+
**行为变化。** 依赖若曾依靠使用方的头文件目录才能编译,现在报告缺少头文件;mcpp 在编译器报错
48+
之后指出该头文件所在的使用方目录。依赖需要通过自己的 `include_dirs` 或它的某个依赖找到头文件。
49+
依赖缓存的 epoch 由 3 升为 4,升级后首次构建重建一次依赖缓存,不需要任何操作。
50+
51+
### 成员清单只有一种读法
52+
53+
`mcpp publish`、`mcpp pack`、`mcpp emit xpkg`、`mcpp toolchain list`、`mcpp sbom`、`mcpp index list`/`update`、
54+
`mcpp update` 的索引刷新、快路径的身份判定与测试发现,此前直接读取成员目录中的原始清单:省略
55+
`version` 的成员被拒绝,未写 `[toolchain]` 的成员在 `toolchain list` 中显示全局默认工具链,而同一
56+
目录下的 `mcpp build` 用的是工作空间的工具链。现在它们与 `prepare_build` 经同一个函数读取继承后的
57+
清单。
58+
59+
### 工作空间成员的发布形态自包含
60+
61+
在成员目录中执行 `mcpp publish` 或 `mcpp emit xpkg` 时,归档只包含成员自己的目录,此前其中的
62+
`mcpp.toml` 原样照搬:继承的 `version`、`[build]` 标志不在其中,兄弟成员之间的 `path` 依赖原样保留
63+
而使用方无法解析,描述符的 `deps` 静默略去这些依赖。现在发布的清单是归一化后的:继承来的值被写出,
64+
`x.workspace = true` 条目取得解析后的来源,兄弟依赖以版本依赖发布,原清单以 `mcpp.toml.orig` 保留,
65+
归一化后的文件同时写到 `target/dist/<name>-<version>.mcpp.toml`。归档由 git 对象按提交日期构建,
66+
两次运行逐字节相同。不带 `version` 的兄弟 `path` 依赖、包外非成员的 `path` 依赖、位于成员目录之外的
67+
继承头文件目录会被拒绝,报错给出应写的内容。不是工作空间成员的包与此前一样原样归档。
68+
归一化后的清单只使用 2026.9.24.1 已接受的键,实测该版本的客户端可以构建它。
69+
70+
### xlings 2026.9.20.1
71+
72+
内置的 xlings 由 2026.9.16.1 升为 2026.9.20.1(openxlings/xlings#610):项目 subos 中执行的命令
73+
不再从项目的 subos 读取全局工作空间并据此删除全局 shim;下载失败的安装不再报告 `installed`。
74+
75+
### 测试基础设施
76+
77+
e2e 辅助脚本 `_inherit_toolchain.sh` 改为按版本链接开发者的载荷。此前它链接整个包目录,测试
78+
新装的版本穿过链接写进开发者的 `~/.mcpp`,链接脚本指向测试结束后即被删除的临时目录(#293 的
79+
第二种形态;实测 `31_transitive_deps.sh` 写出了这样的 `xim-x-glibc/2.44.3`)。
80+
681
## [2026.9.24.1] - 2026-09-24
782

883
### MSVC ABI 上的 toolset:只选一次,可以指定,记录在案

‎docs/07-workspace.md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,11 @@ member inherits `[workspace.package]` as it does here (mcpp 2026.9.16.1+; see
408408
[05 — Dependencies](05-dependencies.md)). It also inherits its repository's
409409
`[workspace.build]` and resolves its `x.workspace = true` entries against that
410410
repository's `[workspace.dependencies]` (2026.9.25.1+), so the same commit
411-
compiles the same way in its own checkout and in a consumer's graph.
411+
compiles the same way in its own checkout and in a consumer's graph. A member
412+
that an index descriptor points at inside a tag tarball receives the tarball's
413+
workspace in the same way. Publishing a member with `mcpp publish` writes the
414+
inherited values into the published manifest
415+
([11 — Publishing a Library](11-publishing-a-library.md)).
412416

413417
## 7. Relationship to C++ Modules
414418

‎docs/11-publishing-a-library.md‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,38 @@ mcpp's build sandbox is network-isolated, so `file://` and
142142
seeded one is the copy that will still be there when the publish silently
143143
failed.
144144

145+
## Publishing a workspace member *(mcpp 2026.9.25.1+)*
146+
147+
A member's manifest may leave `version`, `[build]` flags and `x.workspace = true`
148+
entries to its workspace ([07](07-workspace.md) §4.1). Both publishing routes
149+
keep that working.
150+
151+
- **The descriptor points into the repository's tag tarball**
152+
(`mcpp = "*/libs/http/mcpp.toml"`). The consumer reads the member's manifest
153+
from the tarball and applies the workspace root the tarball contains, as a
154+
`git` consumer does. The manifest is published as written.
155+
- **`mcpp publish` or `mcpp emit xpkg` inside the member.** The archive contains
156+
only the member's directory, so its `mcpp.toml` is normalised: the values the
157+
member inherits are written out, `x.workspace = true` entries receive their
158+
resolved source, and a dependency on a sibling member is published as a
159+
version dependency. The manifest as written is kept beside it as
160+
`mcpp.toml.orig`, and the normalised file is also written to
161+
`target/dist/<name>-<version>.mcpp.toml` for review. The archive is built from
162+
git objects with the commit's dates, so two runs produce the same bytes. A
163+
package that is not a workspace member is archived exactly as before.
164+
165+
A sibling dependency states the version it is published under:
166+
167+
```toml
168+
[dependencies]
169+
"acme.util" = { path = "../util", version = "0.3.0" } # path for development, version for consumers
170+
```
171+
172+
`mcpp publish` refuses a sibling dependency without `version` and names the
173+
member's version and the line to write. It refuses a `path` dependency outside
174+
the package that is not a workspace member, and an inherited include directory
175+
outside the member's directory, because the archive contains neither.
176+
145177
## Manifest keys that need a version floor
146178

147179
Most `[build]` keys degrade cleanly on an older mcpp: it warns that the key is
@@ -169,4 +201,5 @@ re-refreshing the index looking for it.
169201
- [ ] `publish-artifact.yml` succeeded
170202
- [ ] cold resolve (seeded copy deleted) downloads and compiles it
171203
- [ ] consumers bumped
204+
- [ ] a workspace member: the normalised `target/dist/<name>-<version>.mcpp.toml` reviewed
172205

‎docs/specs/manifest-semantics.md‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,15 @@ feature-deps feature-xlings ← 限定词是门
344344
的编译命令在两个仅 include 设置不同的根包下相同;根包自己的编译单元中每个根包目录
345345
恰好出现一次;依赖因此找不到头文件时,报错之后指出消费者目录
346346
(`tests/e2e/765_a_consumer_include_directory_stays_in_the_consumer.sh`)。
347+
13. §9 第 1 条索引归档一种情况的判据:描述符指向归档内一个省略 `version` 的成员时,该成员
348+
取得归档工作空间的版本与 `defines`(`tests/e2e/774_an_index_member_inherits_its_archive_workspace.sh`)。
349+
第 5 条的判据:成员目录内的 `emit xpkg`、`publish --dry-run`、`toolchain list` 读取继承后的
350+
清单(`tests/e2e/773_commands_outside_the_build_read_the_effective_manifest.sh`)。
351+
14. §9 第 7 条的判据:发布归档中的清单写出继承来的 `version`、`license` 与 `cxxflags`,兄弟边
352+
以版本边出现且描述符的 `deps` 列出它,原清单以 `mcpp.toml.orig` 保留;归档的使用方在新旧两个
353+
客户端上都能构建;两次发布的归档逐字节相同;缺少 `version` 的兄弟 `path` 边被拒绝且报错给出
354+
应写的一行;无需修改的包的归档与此前逐字节相同
355+
(`tests/e2e/772_a_published_member_is_self_contained.sh`)。
347356

348357
## 8. 编译 flag 列表的元素
349358

@@ -385,9 +394,10 @@ feature、`[profile.<n>]`、`[target.<selector>.build]`、xpkg 描述符,以及
385394
## 9. 工作空间继承与构建需求的作用域
386395

387396
1. 工作空间成员**必须**恰好接收一次 `[workspace.package]`、`[workspace.build]` 与
388-
`x.workspace = true` 条目的继承,无论它是命令构建的包、另一个成员的 `path` 依赖,
389-
还是通过 `git` 引用的、托管在 git 上的工作空间的成员。后一种情况按该成员所在仓库的
390-
工作空间根继承,相对路径以该仓库的根为锚点。
397+
`x.workspace = true` 条目的继承,无论它是命令构建的包、另一个成员的 `path` 依赖、
398+
通过 `git` 引用的托管在 git 上的工作空间的成员,还是索引包归档内的成员(描述符的
399+
`mcpp` 字段指向该成员的清单)。后两种情况按该成员所在仓库或归档的工作空间根继承,
400+
相对路径以该根为锚点;在归档内查找工作空间根时**禁止**越出该版本的安装根。
391401
2. 向量按工作空间、成员、命中的 `[target.<selector>.build]` 的顺序追加;`defines` 按
392402
§8 的集合语义合并。标量仅在成员未**声明**该键时取工作空间的值。
393403
3. 继承**必须**在 `defines` 展开之前、在清单被固定进构建图之前完成。实现**必须**拒绝
@@ -414,4 +424,4 @@ feature、`[profile.<n>]`、`[target.<selector>.build]`、xpkg 描述符,以及
414424
| 1.3 | 2026-09-14 | 条件依赖声明替换同一身份的无条件声明,`targets.<name>` 成为可条件化的 section,不读取的 section 必须报出(mcpp 2026.9.14.2):新增 §3.1.1 与 §7 第 8 条判据。 |
415425
| 1.4 | 2026-09-15 | 库目标的默认链接形态 `linkage`(mcpp 2026.9.15.2):§3.1.1 补默认值的语义、优先顺序与拒绝条件;§7 补第 9 条判据。 |
416426
| 1.5 | 2026-09-17 | 编译 flag 列表元素的读法(mcpp 2026.9.17.1,#655):新增 §8 与 §7 第 10 条判据。 |
417-
| 1.6 | 2026-09-25 | 工作空间继承与构建需求的作用域(mcpp 2026.9.25.1,#690):§8 补 `defines` 的集合语义;新增 §9 与 §7 第 11、12 条判据。 |
427+
| 1.6 | 2026-09-25 | 工作空间继承与构建需求的作用域(mcpp 2026.9.25.1,#690):§8 补 `defines` 的集合语义;新增 §9 与 §7 第 11 至 14 条判据。 |

‎docs/zh/07-workspace.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,9 @@ myproject/
391391
`[workspace.package]`(mcpp 2026.9.16.1+;见 [05 —— 依赖](05-dependencies.md))。
392392
它还继承所在仓库的 `[workspace.build]`,并按该仓库的 `[workspace.dependencies]`
393393
解析自己的 `x.workspace = true` 条目(2026.9.25.1+),因此同一个提交在它自己的
394-
检出中与在使用方的依赖图中以相同方式编译。
394+
检出中与在使用方的依赖图中以相同方式编译。索引描述符指向 tag tarball 内的成员时,
395+
该成员以同样方式取得 tarball 中的工作空间。用 `mcpp publish` 发布成员时,继承来的值
396+
被写入发布的清单([11 —— 发布库](11-publishing-a-library.md))。
395397

396398
## 7. 与 C++ 模块的关系
397399

‎docs/zh/11-publishing-a-library.md‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,32 @@ mcpp 的构建沙箱与网络隔离,`file://` 和 `http://127.0.0.1` 形式的
130130
**在相信「真的能用」之前,先删掉播种的那一份。** 播种出来的 0.0.48 与已发布的
131131
0.0.48 对构建而言毫无区别,而当发布实际上已悄悄失败时,留在那里的正是播种的那一份。
132132

133+
## 发布工作空间成员 *(mcpp 2026.9.25.1+)*
134+
135+
成员的清单可以把 `version`、`[build]` 标志与 `x.workspace = true` 条目交给工作空间
136+
提供([07](07-workspace.md) §4.1)。两种发布方式都保留这一点。
137+
138+
- **描述符指向仓库 tag tarball 中的成员**(`mcpp = "*/libs/http/mcpp.toml"`)。使用方
139+
从 tarball 中读取成员的清单,并应用 tarball 所含的工作空间根,与通过 `git` 引用时
140+
相同。清单按原样发布。
141+
- **在成员目录中执行 `mcpp publish` 或 `mcpp emit xpkg`。** 归档只包含成员自己的目录,
142+
因此其中的 `mcpp.toml` 被归一化:成员继承的值被写出,`x.workspace = true` 条目取得
143+
解析后的来源,对兄弟成员的依赖以版本依赖发布。原样的清单以 `mcpp.toml.orig` 保留在
144+
旁边,归一化后的文件同时写到 `target/dist/<name>-<version>.mcpp.toml` 供审阅。归档由
145+
git 对象按提交的日期构建,两次运行产生相同的字节。不是工作空间成员的包与此前一样
146+
原样归档。
147+
148+
兄弟依赖写出它发布时的版本:
149+
150+
```toml
151+
[dependencies]
152+
"acme.util" = { path = "../util", version = "0.3.0" } # path 用于开发,version 用于使用方
153+
```
154+
155+
`mcpp publish` 拒绝不带 `version` 的兄弟依赖,并给出该成员的版本和应写的一行。它同样
156+
拒绝包外、且不是工作空间成员的 `path` 依赖,以及位于成员目录之外的继承头文件目录,因为
157+
归档中二者都不存在。
158+
133159
## 需要版本下限的 manifest 键
134160

135161
多数 `[build]` 键在较旧的 mcpp 上会干净地降级:警告该键不受支持、忽略它,构建要么
@@ -153,4 +179,5 @@ mcpp 的构建沙箱与网络隔离,`file://` 和 `http://127.0.0.1` 形式的
153179
- [ ] `publish-artifact.yml` 已成功
154180
- [ ] 冷解析(已删掉播种拷贝)能下载并编译
155181
- [ ] 消费方已升版本
182+
- [ ] 工作空间成员:已审阅归一化后的 `target/dist/<name>-<version>.mcpp.toml`
156183
</content>

0 commit comments

Comments
 (0)