Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ status: landed

# A verified Web run that asked the host for node

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

## What was measured

Expand Down
605 changes: 605 additions & 0 deletions .agents/docs/2026-09-12-engine-gaps-after-the-sdk-batch.md

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion .agents/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ superseded_by: 2026-09-07-....md # when status is superseded
---
```

279 records.
280 records.

## By subject

Expand Down Expand Up @@ -52,12 +52,14 @@ Records that declare one. Everything else is listed by date below.

### triage

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

## By date

### 2026-09

- [The engine gaps left open after the SDK batch](2026-09-12-engine-gaps-after-the-sdk-batch.md) — landed
- [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
- [Six open issues: what each one actually is, and what would answer it](2026-09-11-six-open-issues-analysis.md) — active
- [SDK toolchains, the payload/engine seam, and openkal across iOS, Android and Web](2026-09-11-sdk-toolchains-and-ios-local-verification.md) — landed
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/ci-macos-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,11 @@ jobs:
[target.aarch64-ios-sim]
runner = ["simctl-run"]

# Declared at the top level here and not in examples/13, because a
# tool declaration is not conditional on a target and this package
# exists for macOS alone. This fixture is macOS-only, so it can say
# it; a portable manifest cannot.
[xlings.workspace]
# Declared on the row that runs it, as examples/13 does. A target
# section's `xlings.workspace` is installed only when that target is
# built, so the step below that runs the simulator artefact through
# `simctl-run` is also the measurement that this declaration works.
[target.aarch64-ios-sim.xlings.workspace]
"xim:apple-simulator-tools" = ""
TOML
cat > /tmp/iostest/src/main.cpp << 'CPP'
Expand Down
75 changes: 74 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

## [Unreleased]

## [2026.9.12.1] - 2026-09-12
## [2026.9.12.2] - 2026-09-12

2026.9.12.1 未单独发布,其条目并入本版本。

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

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

### Windows GUI 可执行文件:`windows_subsystem` 与 `windows_entry`(#618)

- `[targets.<name>]` 增加 `windows_subsystem = "console" | "windows"` 与
`windows_entry = "main" | "wmain" | "WinMain" | "wWinMain"`。它们是字段而不是链接标志,因为正确的
标志取决于 ABI:MSVC ABI 渲染为 `/SUBSYSTEM:` 与 CRT 启动符号 `/ENTRY:<entry>CRTStartup`(经 GNU
风格驱动时带 `-Wl,`),只要任一键偏离默认值两条都写出;GNU ABI 渲染为 `-mwindows` 与 `-municode`。
在 ELF、Mach-O 与 WebAssembly 上不产生任何标志,产物逐字节不变。
- 只到达声明它们的可执行目标的链接;同包的其他可执行文件、测试二进制与消费者保持控制台子系统。库目标
声明任一键被拒绝,拒绝信息指出目标与键名;取值不在集合内被拒绝并列出可接受的取值。
- 构建程序协议升至 10:`mcpp::windows_subsystem(target, value)` 与 `mcpp::windows_entry(target, value)`
为本包的可执行目标设置同一字段。指向未声明的目标、非可执行目标,或与 mcpp.toml 矛盾的取值,在应用任何
指令之前被拒绝;缓存命中的路径施加同一检查。
- `[targets.<name>]` 不支持键的警告所列出的键表改为由解析器接受的键表生成;此前手写的副本漏掉了 `exports`。

### 快路径比较工具链请求

- 快路径此前比较目标三元组、profile、缓存模式与 feature,但不比较 `--toolchain`(即 `MCPP_TOOLCHAIN`)
与本机默认工具链(config.toml 的 `[toolchain] default`)。实测:以 gcc 构建后执行
`mcpp build --toolchain llvm@22.1.8`,输出 `Finished dev in 0.00s` 并保留 gcc 产物,解析阶段的检查
全部被跳过。
- 构建缓存记录增加 `toolchain=` 行,`mcpp build` 与 `mcpp run` 的快路径都比较它。早于该行的记录被拒绝
一次,随后的构建重新写入。`--offline`、`--locked` 与 `--jobs` 不改变解析的选择,不参与比较。

### `runtime.deploy`:把运行期文件放进相对可执行文件的目录(#615)

- `[runtime] deploy = [{ from = "...", to = "..." }]` 与描述文件的 `runtime.deploy`:`from` 相对声明它的
包,`to` 相对可执行文件所在目录,`"."` 表示该目录本身。`deploy_files` 把每一项放在可执行文件旁,无法
满足从固定子目录读取的加载器,例如 macOS 上的 Vulkan loader 读取 `<可执行文件目录>/vulkan/icd.d`。
- mcpp.toml 与描述文件使用同一条路径规则:以 `/` 分隔,不得为绝对路径、不得指定盘符、不得含空分量、`.`
或 `..` 分量;违反的项按序号被拒绝。同一目标位置的两个来源被拒绝,同名文件放进不同目录不构成冲突。
测试二进制看到同样的布局。
- `mcpp pack` 把 `deploy_files` 与 `deploy` 的文件放到打包后可执行文件旁的同一相对位置;此前打包过程不读取
这两个列表中的任何一个。
- 它是独立的键,而不是 `deploy_files` 的表形式:早于它的描述文件读取器在 `deploy_files` 中遇到 `{` 时
不会终止,而对不认识的 `runtime` 键会跳过。

### 产物的 ABI 开关:`[target.<selector>.abi] threads` 与 `requires_abi`

- 线程支持是整个产物共享的性质:标准库模块预构建、依赖扫描、每个包的每个翻译单元与链接必须一致。根
manifest 以 `[target.<selector>.abi] threads = true` 声明;在既非 PE 也非 freestanding 的目标上渲染为
`-pthread`,并经方言 flag 进入依赖缓存键。未知成员与非布尔的 `threads` 被拒绝。
- 依赖以 `[package] requires_abi = { threads = true }` 或
`[features] <name> = { requires_abi = { threads = true } }` 声明需求;根包未满足时在编译之前被拒绝,
拒绝信息指出包与 feature,并给出满足它的表。依赖自己写的 `[target.<selector>.abi]` 被报告
(`abi/dependency-table`)且不生效。

### 安装钩子的环境与 `c++-abi` 的做法(#613)

- 依赖包的安装钩子收到 `MCPP_TARGET`、`MCPP_TARGET_OS`、`MCPP_TARGET_ARCH` 与 `MCPP_TARGET_ENV`,名称
与规则同构建程序一致,由同一个函数计算。`MCPP_COMPILER` 与 `MCPP_CXX_STDLIB` 同样总是写出,但在依赖
安装时为空:工具链在依赖图之后才解析,此时没有可陈述的编译器与标准库。每个变量都显式写出,钩子不会读到
从父进程继承的值;钩子不得把某种变体构建进名称未体现该变体的存储目录。
- 从源码构建静态库的包以 `requires = ["mcpp:c++-abi=<stdlib>"]` 声明它所针对的标准库;工具链解析出另一
实现的工程被拒绝,拒绝信息指出两个实现。docs/06、docs/22 与 docs/32 记录这一做法。

### xlings 调用的环境与错误输出(#614)

- 一次 xlings 调用的环境由一个函数决定,全局模式是不存在的 `XLINGS_PROJECT_DIR`。POSIX 把它渲染进
命令前缀;Windows 在调用期间以作用域守卫施加,调用结束后恢复原值,项目目录不再留在 mcpp 之后启动的
进程的环境中。`install_packages` 的回退路径此前在 POSIX 上无视项目目录、一律按全局模式拼写,现与直接
路径一致。
- 安装失败时,xlings 自己的错误级别输出(含 `error`、`E_` 或以 `[xim]` 开头的行,最多最后 20 行)以
`xlings:` 前缀附在 mcpp 的诊断之后;此前 stderr 被丢弃。

### 其他

- `[target.<selector>.xlings]` 下写包名时,拒绝信息指出正确的位置 `[target.<selector>.xlings.workspace]`;
示例 13 与 iOS 模拟器 CI 夹具改用该写法声明 `xim:apple-simulator-tools`,示例 README 不再要求手动安装。
- docs/20 记录 clang 与 MSVC STL 14.51 组合下 `std::find` 作用于宽平凡可比较类型时的已知工具链缺陷
(microsoft/STL#6294,#609)。

## [2026.9.11.4] - 2026-09-11

### iOS 三行:生态编译器与定位到的 SDK
Expand Down
69 changes: 69 additions & 0 deletions docs/04-mcpp-toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,55 @@ A `soname` is meaningful on `kind = "lib"` too — see
[`dependency_linkage`](#dependency_linkage--static-or-shared-is-the-consumers-decision)
below, where the form a library takes becomes the consumer's decision.

#### `windows_subsystem` and `windows_entry` — a Windows GUI executable (mcpp 2026.9.12.2+)

```toml
[targets.myapp]
kind = "bin"
main = "src/main.cpp"
windows_subsystem = "windows" # "console" (default) | "windows"
windows_entry = "main" # "main" (default) | "wmain" | "WinMain" | "wWinMain"
```

A PE executable records a subsystem. `"console"` attaches a console, and
`"windows"` produces a GUI program that starts without one. `windows_entry`
names the function the program defines, not the startup symbol that calls it,
and it is independent of the subsystem: a console program may define `wmain`,
and a GUI program may keep a portable `int main()`.

The keys are fields rather than link flags because the correct flags depend on
the ABI, and a flag cannot state which ABI it addresses:

| `windows_subsystem` / `windows_entry` | MSVC ABI (cl, clang-cl, clang targeting `*-windows-msvc`) | GNU ABI (MinGW gcc, clang targeting `*-windows-gnu`) |
|---|---|---|
| `"console"` / `"main"` | nothing | nothing |
| `"windows"` / `"main"` | `/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup` | `-mwindows` |
| `"windows"` / `"WinMain"` | `/SUBSYSTEM:WINDOWS /ENTRY:WinMainCRTStartup` | `-mwindows` |
| `"windows"` / `"wWinMain"` | `/SUBSYSTEM:WINDOWS /ENTRY:wWinMainCRTStartup` | `-mwindows -municode` |
| `"console"` / `"wmain"` | `/SUBSYSTEM:CONSOLE /ENTRY:wmainCRTStartup` | `-municode` |

On the MSVC ABI both flags are written whenever either key differs from its
default, because the linker infers each from the other when one is absent: the
GUI subsystem alone selects `WinMainCRTStartup`, which a portable `int main()`
does not satisfy, and `/ENTRY:main` skips CRT initialisation, static
constructors included. A GNU-style driver receives the MSVC-ABI flags as
`-Wl,/SUBSYSTEM:...`.

The keys reach the link of the declaring target only. A second executable, the
`mcpp test` binaries and the consumers of the package keep the console
subsystem, which is why `[build] ldflags` is not the place for these flags: that
channel reaches every link in the graph. On ELF, Mach-O and WebAssembly the keys
render nothing and the artefact is byte-identical to one built without them, so
a cross-platform manifest needs no `cfg` block. A library target that declares
either key is refused, and the refusal names the target and the key.

A build program sets the same fields for an executable of its own package with
`mcpp::windows_subsystem("<target>", "windows")` and
`mcpp::windows_entry("<target>", "wmain")` ([build.mcpp](30-build-mcpp.md)).

Application bundles, application manifests and DPI awareness are not part of
these keys; they belong to packaging formats and to `[resources]`.

#### Per-target keys

```toml
Expand All @@ -223,6 +272,8 @@ required_features = ["gui"] # only built when feature `gui` is
| `defines` | Preprocessor macros (`name` or `name=value`); desugar to `-D<x>` on both the C and C++ entry compile. |
| `cxxflags` / `cflags` | Extra compile flags for this target. Do **not** put `-std=...` here — use `[package].standard`. |
| `required_features` | The target is emitted only when **every** listed feature is active in the build; otherwise it is silently skipped. A gate only — it does not activate features (use `--features` / `[features].default`). **One exception, and it is not a second rule:** when this target is requested as a host tool (`tools = [...]`, §2.14), the target is what was *asked for*, so its `required_features` become the sub-build's *inputs*. Same field, one meaning — the resolution just runs in the opposite direction. |
| `windows_subsystem` *(2026.9.12.2+)* | The PE subsystem of an executable: `"console"` (the default) or `"windows"`, a GUI program that starts without a console. Reaches this target's link and no other, and renders nothing on a target that is not PE. See the section above. |
| `windows_entry` *(2026.9.12.2+)* | The entry function the program defines: `"main"` (the default), `"wmain"`, `"WinMain"` or `"wWinMain"`. See the section above. |

> **Scope (important):** `defines` / `cxxflags` / `cflags` on a target apply **only to that
> target's exclusive entry source** (its `main`) — never to shared module/impl objects, which
Expand Down Expand Up @@ -1055,6 +1106,7 @@ transitive_needed_dirs = ["runtime/closure"]
runtime_search_dirs = ["runtime"]
frameworks = ["WindowKit"]
deploy_files = ["bin/widget.dll"]
deploy = [ { from = "share/vulkan/icd.d/widget_icd.json", to = "vulkan/icd.d" } ]

# Use an exact canonical identity when multiple providers exist.
[runtime."display.present"]
Expand Down Expand Up @@ -1109,6 +1161,23 @@ Link intent keeps discovery stages separate:
| `runtime_search_dirs` | RUNPATH/rpath only, never `-L` | rpath only | no flag |
| `frameworks` | no flag | `-framework` | no flag |
| `deploy_files` | copy edge | copy edge | copy beside the output; never a linker flag |
| `deploy` *(2026.9.12.2+)* | copy edge into `bin/<to>/` | copy edge into `bin/<to>/` | copy edge into `bin/<to>/`; never a linker flag |

`deploy` places a file in a directory relative to the executable, which
`deploy_files` cannot express because it places every entry beside the
executable. A loader that reads a fixed subdirectory needs it: the Vulkan loader
on macOS reads driver manifests from `<executable dir>/vulkan/icd.d`. Each entry
is a table of exactly two strings. `from` is relative to the declaring package's
root, and `to` is relative to the executable's directory, where `"."` means that
directory itself. Both are separated by `/` on every host, and neither may be
absolute, name a drive, or contain an empty, `.` or `..` component; an entry
that does is refused, and the refusal names its index. Two sources for one
destination are refused naming the destination, while one file name in two
directories is not a collision. `deploy` is a key of its own rather than a table
form of `deploy_files`, because a descriptor reader that predates it meets `{`
inside `deploy_files` and does not terminate, whereas it skips a `runtime` key it
does not know. `mcpp pack` stages the files of both keys at the same relative
path beside the packed executable.

For one compatibility train, `library_dirs` maps only to runtime search,
`dlopen_libs` maps to required run-phase soname requirements, and
Expand Down
18 changes: 18 additions & 0 deletions docs/06-features-and-capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,24 @@ provides = ["mcpp:compiler-runtime=compiler-rt", "mcpp:c++-abi=libc++"]
requires = ["mcpp:compiler=llvm"]
```

A requirement on the artefact's ABI switch is stated with `requires_abi`, on the
package or on one feature, rather than as a layer:

```toml
[package]
requires_abi = { threads = true }

[features]
mt = { requires_abi = { threads = true } }
```

Only the root manifest sets the switch (`[target.<selector>.abi]`, [22 — The
Target Side](22-target-side.md)); a requirement it does not satisfy is refused
before compilation, naming the package and the feature. A package whose install
hook compiles a static library against one C++ standard library states that
implementation as a layer requirement, `requires = ["mcpp:c++-abi=libstdc++"]`,
for the reason given in the same chapter.

A package that is a standard library states its `std` module source under
`[build]`, where the flags it needs become conditional like any other build
input.
Expand Down
31 changes: 31 additions & 0 deletions docs/20-toolchains.md
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,37 @@ Tracked as [mcpp#256](https://github.com/mcpp-community/mcpp/issues/256).
bundled LLVM toolchains, so a future Clang bump that fixes — or re-breaks —
this becomes visible instead of silently changing what packages can express.

## Known Toolchain Hazard: `std::find` Over a Wide Trivially Comparable Type (clang + MSVC STL 14.51)

A translation unit that calls `std::find` over a trivially copyable type wider
than eight bytes fails to compile inside the standard library when the compiler
is clang and the standard library is the MSVC STL at 14.51 (Visual Studio 18):

```text
xutility:320:23: error: static assertion failed: unexpected size
xutility:6542:49: note: in instantiation of function template specialization
'std::_Find_vectorized<const T, T>' requested here
```

This is the shape of mcpp's default Windows toolchain, clang targeting
`x86_64-pc-windows-msvc`, so the failure surfaces through `mcpp build` although
nothing in mcpp or in the program is wrong. The MSVC STL admits the type to its
vectorized path through a clang-only trait that has no upper size bound, and
the function it dispatches to implements 1-, 2-, 4- and 8-byte elements only.
MSVC's own front end never takes that path. The same source compiles against the
MSVC STL 14.3x that `windows-2022` ships.

The defect is upstream, tracked as
[microsoft/STL#6294](https://github.com/microsoft/STL/issues/6294). Two
workarounds were measured downstream:

- Give the element type a user-written `operator==` instead of a defaulted one.
The type is then not trivially equality-comparable, and the STL keeps its
scalar path.
- Build on an image whose MSVC STL predates 14.51, such as `windows-2022`.

Tracked as [mcpp#609](https://github.com/mcpp-community/mcpp/issues/609).

## The C++ runtime contract (`cxx_runtime`)

`cxx_runtime` states what the produced artifact promises about the machine that
Expand Down
Loading
Loading