Skip to content

Commit d515306

Browse files
committed
feat: the engine gaps left open after the SDK batch (2026.9.12.2)
Implements .agents/docs/2026-09-12-engine-gaps-after-the-sdk-batch.md (M1-M9). - #618: `[targets.<name>] windows_subsystem` and `windows_entry`, rendered per ABI onto the declaring executable's own link (`/SUBSYSTEM:` with the CRT `/ENTRY:` symbol on MSVC, `-mwindows`/`-municode` on GNU), inert off PE, and refused on library targets. Build-program protocol 10 adds the `windows-subsystem` and `windows-entry` directives for a named target. - T1: the fast path compares the toolchain request (`--toolchain`, `MCPP_TOOLCHAIN`, and `[toolchain] default`); a build asking for another toolchain no longer replays the previous one. - #615: `runtime.deploy = [{ from, to }]` places runtime files in a directory relative to the executable, in mcpp.toml and in descriptors, and `mcpp pack` carries both `deploy_files` and `deploy` at the same relative paths. - `[target.<selector>.abi] threads` as a typed graph-wide switch, with `requires_abi` on a package or feature refused before compilation when the root does not state it. - #613: a dependency's install hook receives MCPP_COMPILER, MCPP_CXX_STDLIB and the target names, computed by the function the build-program environment uses; docs state the `mcpp:c++-abi` recipe for source-built static packages. - #614: one function decides an xlings invocation's environment, the Windows project scope is restored after each invocation, and xlings' own error lines follow a failed install. - #609 and G1: a documented toolchain hazard, and the refusal that names `[target.<selector>.xlings.workspace]`, with examples/13 using it.
1 parent 2995edd commit d515306

51 files changed

Lines changed: 2946 additions & 148 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/docs/2026-09-12-a-verified-web-run-that-asked-the-host-for-node.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ status: landed
55

66
# A verified Web run that asked the host for node
77

8-
**Status:** implemented in mcpp 2026.9.12.1 and openxlings/xim-pkgindex#823.
8+
**Status:** implemented in mcpp 2026.9.12.2 (2026.9.12.1 was not published) and openxlings/xim-pkgindex#823.
99

1010
## What was measured
1111

.agents/docs/2026-09-12-engine-gaps-after-the-sdk-batch.md

Lines changed: 77 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
---
22
subject: triage
3-
status: active
3+
status: landed
44
---
55

66
# The engine gaps left open after the SDK batch
77

8-
**Status:** reviewed 2026-09-12. The four questions in the first draft were
9-
answered, and the answers are recorded in §9. Three statements in the first
10-
draft were then measured and corrected: two recorded gaps already have an
11-
existing mechanism (§2, §5.2), and a new defect was found (§7). The
12-
implementation is one mcpp PR carrying the next date version. 2026.9.12.1 (#617)
13-
is merged and unreleased, so its change ships with that PR.
8+
**Status:** landed in mcpp 2026.9.12.2. The four questions in the first draft
9+
were answered in review (§9), and three statements were measured and corrected
10+
before implementation (§2, §5.2, §7). The corrections made during
11+
implementation are recorded in §11. The ecosystem changes E1 and E2 follow the
12+
release (§10).
1413

1514
## 0. Scope, and the ledger it starts from
1615

@@ -108,15 +107,15 @@ console program may define `wmain`.
108107

109108
| target | `windows_subsystem = "windows"` renders | decided by |
110109
|---|---|---|
111-
| PE, MSVC style: cl, clang-cl, clang targeting `*-windows-msvc` | `/SUBSYSTEM:WINDOWS` plus the entry's `/ENTRY:` symbol, spelled with `-Wl,` under a GNU-style driver | `plan.rcStyle == "msvc"` |
112-
| PE, GNU style: MinGW gcc, clang targeting `*-windows-gnu` | `-mwindows`, plus `-municode` for a wide entry | `plan.rcStyle == "gnu"` |
110+
| PE, MSVC style: cl, clang-cl, clang targeting `*-windows-msvc` | `/SUBSYSTEM:WINDOWS` plus the entry's `/ENTRY:` symbol, spelled with `-Wl,` under a GNU-style driver | `pe_msvc_abi` (§11.1) |
111+
| PE, GNU style: MinGW gcc, clang targeting `*-windows-gnu` | `-mwindows`, plus `-municode` for a wide entry | `pe_msvc_abi` (§11.1) |
113112
| ELF, Mach-O, Wasm | nothing; no diagnostic; byte-identical artefact | `ObjectFormat` |
114113

115114
`"console"` with `"main"` renders nothing on every target, because both are the
116-
linker's defaults. A non-default entry with the console subsystem renders only
117-
the entry. The dialect is read from `rcStyle`, the field the plan already uses to
118-
choose between rc/llvm-rc and windres (`plan.cppm:262`), so resources and the
119-
subsystem cannot disagree about the linker they address.
115+
linker's defaults. On the MSVC ABI any other combination renders both flags
116+
(§11.2). The ABI is answered by `pe_msvc_abi`, the predicate the import library
117+
flag already uses, and the emitter spells the flag for the linker it invokes
118+
(§11.1).
120119

121120
### 1.4 Scope
122121

@@ -443,7 +442,7 @@ Each angle states what the design does, and what would be wrong with the
443442
alternative.
444443

445444
- **Architecture.** Every change lands on a mechanism that already exists:
446-
`LinkUnit::linkFlags` and `rcStyle` (§1), the layer requirement check (§2), the
445+
`LinkUnit` and the PE link-flag predicate (§1), the layer requirement check (§2), the
447446
`runtime` table's skipping of unknown sub-keys (§4), the xlings workspace
448447
selector (§5.1), the graph-global dialect channel and the dependency cache key
449448
(§5.2), and the fast path's recorded inputs (§7). No new channel carries raw
@@ -462,7 +461,7 @@ alternative.
462461
placed where older parsers skip rather than hang: `runtime.deploy` (§4.2),
463462
`requires_abi` as an unknown feature key (§5.2). `console`/`main` render
464463
nothing, so no existing Windows command line changes.
465-
- **Cross-platform.** Rendering is decided by `ObjectFormat` and `rcStyle`; a key
464+
- **Cross-platform.** Rendering is decided by the object format and the PE link-flag predicate; a key
466465
that means nothing for a format is inert and byte-identical there. The Windows
467466
criteria run on Windows CI, not on Wine.
468467
- **Consistency.** One vocabulary per concept: `mcpp:c++-abi` is the standard
@@ -520,3 +519,66 @@ M1 to M4, M6, M7 and M8 are independent and are implemented in parallel. The
520519
three ecosystem changes follow the release, because each adopts a key only the
521520
new engine reads, and E2's descriptor must be checked against the index's
522521
minimum engine version before it is published.
522+
523+
## 11. Corrections made during implementation
524+
525+
Each item states what the sections above said, what was measured or read in the
526+
code, and what was built instead.
527+
528+
1. **§1.3, the discriminator.** The ABI is not read from `plan.rcStyle`.
529+
`LinkUnit` carries the declared words, and the emitter renders them, because
530+
only the emitter knows whether the link is a separate linker invocation, which
531+
decides between `/SUBSYSTEM:` and `-Wl,/SUBSYSTEM:`. The ABI is answered by
532+
`pe_msvc_abi`, extracted from `pe_link_flag`, so the import library and the
533+
subsystem cannot address two different linkers.
534+
2. **§1.3, the MSVC row.** Both `/SUBSYSTEM:` and `/ENTRY:<entry>CRTStartup` are
535+
written whenever either key differs from its default. Without `/SUBSYSTEM:`,
536+
link.exe infers the subsystem from the entry function the objects define, so
537+
`WinMain` with the console subsystem would link as a GUI program; without
538+
`/ENTRY:`, the GUI subsystem selects `WinMainCRTStartup`, which a portable
539+
`int main()` does not satisfy.
540+
3. **§2.3 item 1, the order.** The layer requirement check runs in target-side
541+
resolution, after the dependency graph is installed, and it is not moved ahead
542+
of provisioning. A package's manifest may live inside its payload, so the
543+
complete set of requirements is known only after installation. The hook
544+
environment is what lets an install hook refuse before it compiles.
545+
4. **§2.3 item 2, the values.** `MCPP_TARGET` in a hook follows the build-program
546+
rule: the requested triple, or the host triple for a native build. The six
547+
values are computed by `install_hook_env`, from which the build-program
548+
environment also takes them, in their existing order, so no build program's
549+
re-run key changes.
550+
5. **§3.1, absent and empty on Windows.** The CRT defines `_putenv_s(key, "")` as
551+
removal, so the Windows branch already produced an absent
552+
`XLINGS_PROJECT_DIR`, and the two platforms did not disagree about global
553+
mode. What was wrong on Windows was the lifetime: the value stayed in mcpp's
554+
environment after the invocation. The asymmetry that did exist was on POSIX,
555+
where the `install_packages` fallback spelled global mode by hand whatever the
556+
project directory was.
557+
6. **§3.2, the scope of the guard.** Only `XLINGS_PROJECT_DIR` is scoped.
558+
`XLINGS_HOME` and the PATH prefix are left process-wide on Windows, as before;
559+
scoping them has not been measured on Windows and is not part of this change.
560+
The hook variables of §2.3 are applied by the dependency installer's own
561+
scope rather than by the xlings environment function.
562+
7. **§4.3, the TOML form.** mcpp's TOML layer refuses an array of tables in any
563+
section not on an allowlist, and `runtime.deploy` had to join it. The unit
564+
test written for the key reported this before an end-to-end test or a user
565+
could.
566+
8. **§5.2, rendering.** Rendering is decided by the object format rather than by
567+
the driver: `-pthread` on every target that is neither PE nor freestanding,
568+
nothing on PE and nothing on a freestanding target. The switch reaches the
569+
root's `dialect_cxxflags`, `cflags` and `ldflags` and every dependency's
570+
`cflags`. The MinGW driver would accept `-pthread`; it is not rendered there,
571+
and threads on that ABI are outside this change's criteria.
572+
9. **§7, the named set.** A recorded build is replayed only for the same target
573+
triple, profile, cache mode, requested features and toolchain request. The
574+
toolchain request is the command-line override (`--toolchain`,
575+
`MCPP_TOOLCHAIN`) together with the machine default (`[toolchain] default`).
576+
`--offline`, `--locked` and `--jobs` change how a resolution is fetched,
577+
checked or executed, not what it chooses, and are not compared. An entry
578+
written before the `toolchain=` line declines once.
579+
10. **§7, the criterion.** A CI runner has one toolchain family installed, so the
580+
A-B-A test requests the platform's own toolchain through `--toolchain` and
581+
asserts that resolution runs, which the fast path skips. The machine-default
582+
leg switches to a second installed version of the same family and asserts
583+
the version string in the artefact; it reports itself as not measured where
584+
no second version is installed.

.agents/docs/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ Records that declare one. Everything else is listed by date below.
5252

5353
### triage
5454

55-
- [The engine gaps left open after the SDK batch](2026-09-12-engine-gaps-after-the-sdk-batch.md)active
55+
- [The engine gaps left open after the SDK batch](2026-09-12-engine-gaps-after-the-sdk-batch.md)landed
5656
- [Six open issues: what each one actually is, and what would answer it](2026-09-11-six-open-issues-analysis.md) — active
5757

5858
## By date
5959

6060
### 2026-09
6161

62-
- [The engine gaps left open after the SDK batch](2026-09-12-engine-gaps-after-the-sdk-batch.md)active
62+
- [The engine gaps left open after the SDK batch](2026-09-12-engine-gaps-after-the-sdk-batch.md)landed
6363
- [A verified Web run that asked the host for node](2026-09-12-a-verified-web-run-that-asked-the-host-for-node.md) — landed
6464
- [Six open issues: what each one actually is, and what would answer it](2026-09-11-six-open-issues-analysis.md) — active
6565
- [SDK toolchains, the payload/engine seam, and openkal across iOS, Android and Web](2026-09-11-sdk-toolchains-and-ios-local-verification.md) — landed

.github/workflows/ci-macos-ios.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -203,11 +203,11 @@ jobs:
203203
[target.aarch64-ios-sim]
204204
runner = ["simctl-run"]
205205
206-
# Declared at the top level here and not in examples/13, because a
207-
# tool declaration is not conditional on a target and this package
208-
# exists for macOS alone. This fixture is macOS-only, so it can say
209-
# it; a portable manifest cannot.
210-
[xlings.workspace]
206+
# Declared on the row that runs it, as examples/13 does. A target
207+
# section's `xlings.workspace` is installed only when that target is
208+
# built, so the step below that runs the simulator artefact through
209+
# `simctl-run` is also the measurement that this declaration works.
210+
[target.aarch64-ios-sim.xlings.workspace]
211211
"xim:apple-simulator-tools" = ""
212212
TOML
213213
cat > /tmp/iostest/src/main.cpp << 'CPP'

CHANGELOG.md

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
66
## [Unreleased]
77

8-
## [2026.9.12.1] - 2026-09-12
8+
## [2026.9.12.2] - 2026-09-12
9+
10+
2026.9.12.1 未单独发布,其条目并入本版本。
911

1012
### Web 产物的运行不再依赖宿主的 `node`
1113

@@ -34,6 +36,76 @@ Emscripten 链接产出的是首行为 `#!/usr/bin/env node` 的 JavaScript 启
3436
忽略它,所以配方可以先发;在此之前安装的 emsdk 载荷没有描述文件,行为与之前相同,重新
3537
安装后获得。
3638

39+
### Windows GUI 可执行文件:`windows_subsystem``windows_entry`(#618)
40+
41+
- `[targets.<name>]` 增加 `windows_subsystem = "console" | "windows"`
42+
`windows_entry = "main" | "wmain" | "WinMain" | "wWinMain"`。它们是字段而不是链接标志,因为正确的
43+
标志取决于 ABI:MSVC ABI 渲染为 `/SUBSYSTEM:` 与 CRT 启动符号 `/ENTRY:<entry>CRTStartup`(经 GNU
44+
风格驱动时带 `-Wl,`),只要任一键偏离默认值两条都写出;GNU ABI 渲染为 `-mwindows``-municode`
45+
在 ELF、Mach-O 与 WebAssembly 上不产生任何标志,产物逐字节不变。
46+
- 只到达声明它们的可执行目标的链接;同包的其他可执行文件、测试二进制与消费者保持控制台子系统。库目标
47+
声明任一键被拒绝,拒绝信息指出目标与键名;取值不在集合内被拒绝并列出可接受的取值。
48+
- 构建程序协议升至 10:`mcpp::windows_subsystem(target, value)``mcpp::windows_entry(target, value)`
49+
为本包的可执行目标设置同一字段。指向未声明的目标、非可执行目标,或与 mcpp.toml 矛盾的取值,在应用任何
50+
指令之前被拒绝;缓存命中的路径施加同一检查。
51+
- `[targets.<name>]` 不支持键的警告所列出的键表改为由解析器接受的键表生成;此前手写的副本漏掉了 `exports`
52+
53+
### 快路径比较工具链请求
54+
55+
- 快路径此前比较目标三元组、profile、缓存模式与 feature,但不比较 `--toolchain`(即 `MCPP_TOOLCHAIN`)
56+
与本机默认工具链(config.toml 的 `[toolchain] default`)。实测:以 gcc 构建后执行
57+
`mcpp build --toolchain llvm@22.1.8`,输出 `Finished dev in 0.00s` 并保留 gcc 产物,解析阶段的检查
58+
全部被跳过。
59+
- 构建缓存记录增加 `toolchain=` 行,`mcpp build``mcpp run` 的快路径都比较它。早于该行的记录被拒绝
60+
一次,随后的构建重新写入。`--offline``--locked``--jobs` 不改变解析的选择,不参与比较。
61+
62+
### `runtime.deploy`:把运行期文件放进相对可执行文件的目录(#615)
63+
64+
- `[runtime] deploy = [{ from = "...", to = "..." }]` 与描述文件的 `runtime.deploy`:`from` 相对声明它的
65+
包,`to` 相对可执行文件所在目录,`"."` 表示该目录本身。`deploy_files` 把每一项放在可执行文件旁,无法
66+
满足从固定子目录读取的加载器,例如 macOS 上的 Vulkan loader 读取 `<可执行文件目录>/vulkan/icd.d`
67+
- mcpp.toml 与描述文件使用同一条路径规则:以 `/` 分隔,不得为绝对路径、不得指定盘符、不得含空分量、`.`
68+
`..` 分量;违反的项按序号被拒绝。同一目标位置的两个来源被拒绝,同名文件放进不同目录不构成冲突。
69+
测试二进制看到同样的布局。
70+
- `mcpp pack``deploy_files``deploy` 的文件放到打包后可执行文件旁的同一相对位置;此前打包过程不读取
71+
这两个列表中的任何一个。
72+
- 它是独立的键,而不是 `deploy_files` 的表形式:早于它的描述文件读取器在 `deploy_files` 中遇到 `{`
73+
不会终止,而对不认识的 `runtime` 键会跳过。
74+
75+
### 产物的 ABI 开关:`[target.<selector>.abi] threads``requires_abi`
76+
77+
- 线程支持是整个产物共享的性质:标准库模块预构建、依赖扫描、每个包的每个翻译单元与链接必须一致。根
78+
manifest 以 `[target.<selector>.abi] threads = true` 声明;在既非 PE 也非 freestanding 的目标上渲染为
79+
`-pthread`,并经方言 flag 进入依赖缓存键。未知成员与非布尔的 `threads` 被拒绝。
80+
- 依赖以 `[package] requires_abi = { threads = true }`
81+
`[features] <name> = { requires_abi = { threads = true } }` 声明需求;根包未满足时在编译之前被拒绝,
82+
拒绝信息指出包与 feature,并给出满足它的表。依赖自己写的 `[target.<selector>.abi]` 被报告
83+
(`abi/dependency-table`)且不生效。
84+
85+
### 安装钩子收到已解析的工具链(#613)
86+
87+
- 依赖包的安装钩子收到 `MCPP_COMPILER``MCPP_CXX_STDLIB``MCPP_TARGET``MCPP_TARGET_OS`
88+
`MCPP_TARGET_ARCH``MCPP_TARGET_ENV`,名称与取值同构建程序一致,由同一个函数计算。钩子可以据此拒绝
89+
或诊断,但不得把某种变体构建进名称未体现该变体的存储目录。
90+
- 从源码构建静态库的包以 `requires = ["mcpp:c++-abi=<stdlib>"]` 声明它所针对的标准库;工具链解析出另一
91+
实现的工程被拒绝,拒绝信息指出两个实现。docs/06、docs/22 与 docs/32 记录这一做法。
92+
93+
### xlings 调用的环境与错误输出(#614)
94+
95+
- 一次 xlings 调用的环境由一个函数决定,全局模式是不存在的 `XLINGS_PROJECT_DIR`。POSIX 把它渲染进
96+
命令前缀;Windows 在调用期间以作用域守卫施加,调用结束后恢复原值,项目目录不再留在 mcpp 之后启动的
97+
进程的环境中。`install_packages` 的回退路径此前在 POSIX 上无视项目目录、一律按全局模式拼写,现与直接
98+
路径一致。
99+
- 安装失败时,xlings 自己的错误级别输出(含 `error``E_` 或以 `[xim]` 开头的行,最多最后 20 行)以
100+
`xlings:` 前缀附在 mcpp 的诊断之后;此前 stderr 被丢弃。
101+
102+
### 其他
103+
104+
- `[target.<selector>.xlings]` 下写包名时,拒绝信息指出正确的位置 `[target.<selector>.xlings.workspace]`;
105+
示例 13 与 iOS 模拟器 CI 夹具改用该写法声明 `xim:apple-simulator-tools`,示例 README 不再要求手动安装。
106+
- docs/20 记录 clang 与 MSVC STL 14.51 组合下 `std::find` 作用于宽平凡可比较类型时的已知工具链缺陷
107+
(microsoft/STL#6294,#609)。
108+
37109
## [2026.9.11.4] - 2026-09-11
38110

39111
### iOS 三行:生态编译器与定位到的 SDK

0 commit comments

Comments
 (0)