Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
09bc6b6
refactor(platform): xlings 强相关模块归入 src/platform/xlings/
speak-agent Aug 11, 2026
797b4f5
fix(runtime): SubOS 缺声明降级,不再让构建失效 (openxlings/xlings#543)
speak-agent Aug 11, 2026
1edbc59
feat(runtime): 运行期搜索闭包 —— SubOS 库视图进 DT_RPATH,末位
speak-agent Aug 11, 2026
cf38941
release: 2026.8.11.2 —— 文档、xlings pin、设计与实施记录
speak-agent Aug 11, 2026
81e0795
fix(runtime): 「可证」要真的可证 —— 三处收窄,两处由 CI 抓到
speak-agent Aug 11, 2026
1c58f22
fix(runtime): 闭包模型只看产物真正会看的地方
speak-agent Aug 11, 2026
fd330c2
test(e2e): 220 自带一个 farm,不再靠机器碰巧装了什么
speak-agent Aug 11, 2026
6f51d5e
refactor(runtime_search): 删掉两个只有测试在用的导出函数
speak-agent Aug 11, 2026
d0119fa
fix(plan): farm 的护栏补上 libc 轴,并且「不匹配」必须是被证明的
speak-agent Aug 11, 2026
9a0333e
docs: 记录落地后被 CI 与自查推翻的三处
speak-agent Aug 11, 2026
7dacceb
fix(test): 护栏矩阵不能把「本机是 Linux」当成前提;doctor 呈现降级 note
speak-agent Aug 11, 2026
5919795
docs: 观测那一节记下实际落地位置(declared/note 归 why runtime,不归 doctor)
speak-agent Aug 11, 2026
93ab297
test(e2e): 202 用 here-string,别让 pipefail 把「匹配成功」读成失败
speak-agent Aug 11, 2026
8e00398
refactor(runtime_validation): 删掉那个从来没人调用的汇总谓词
speak-agent Aug 11, 2026
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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions .agents/skills/mcpp-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ unexpected`。那是调用它的 shell 的问题,不是脚本的缺陷 ——
`#!/usr/bin/env bash`,CI 也是用 `bash` 调的。别据此把这条 guard 当成坏的而跳过:
它是唯一能机器化捕捉 pin 漂移的东西。

也不要通过修改文档或 workflow 绕开动态 `MCPP_PIN` 设计。`src/xlings.cppm` 的
也不要通过修改文档或 workflow 绕开动态 `MCPP_PIN` 设计。`src/platform/xlings/xlings.cppm` 的
`pinned::kXlingsVersion` 仍是 xlings 版本的唯一真源。

## 发布步骤
Expand Down Expand Up @@ -259,7 +259,7 @@ gh workflow run bump-formula.yml -R mcpp-community/homebrew-mcpp
| 自查 `--version` 显示旧版本,但源码已改 | `target/<triple>/<指纹>/` 的指纹随版本变,`ls \| head -1` 取到了上一次构建的目录 | 用 `ls -dt … \| head -1` 取最新构建 |
| Smoke test 输出旧版本 | CI 缓存了旧的 sandbox/target | 删除 GitHub Actions cache 后重跑 |
| e2e `01_help_and_version.sh` 挂 | 只改了 `mcpp.toml` 没改 `fingerprint.cppm`(它把两者交叉比对) | 同步两处正在构建的版本;注意这个 e2e 只在部分分片里跑,可能表现为"只有某个平台红" |
| xlings bootstrap 失败 | xlings 版本不兼容 | 改 `src/xlings.cppm::kXlingsVersion`(唯一真源),再核对引用它的 workflow 与脚本;当前 pin-check 脚本修复前不能依赖它完成扫描 |
| xlings bootstrap 失败 | xlings 版本不兼容 | 改 `src/platform/xlings/xlings.cppm::kXlingsVersion`(唯一真源),再核对引用它的 workflow 与脚本;当前 pin-check 脚本修复前不能依赖它完成扫描 |
| macOS/Windows 构建失败 | 需要等 Linux job 先完成 | 检查 Linux job 是否成功 |
| `slim: FAIL: ... still not stripped` | strip 工具没生效/被 pack 覆盖 | 别绕过断言——它就是为了拦住 34.8MB 的 tarball 再次发出去 |
| mirror leg 报 `missing/unverified` | 资产没传上去或还没传播 | 先 GET 核验(**必须 GET,`curl -I` 会骗你**),gitcode 用 `gitcode.com` 直链而非 `api.` 主机;确认缺件后本地补传再 `gh run rerun --failed`(脚本幂等,已验证的资产会跳过) |
Expand Down Expand Up @@ -312,7 +312,7 @@ gh workflow run release.yml --ref "v$NEW_VERSION"
| `src/version.cppm` | `MCPP_VERSION = "X.Y.Z"` — 编译期版本常量 |
| `.xlings.json` | `workspace.mcpp` — CI bootstrap 装哪个 mcpp(发布**后**才 bump) |
| `.github/workflows/ci-fresh-install.yml` | `MCPP_PIN` — 由 `wait-index` 从最新 release 推导,**从不手工 bump** |
| `src/xlings.cppm` | `kXlingsVersion` — xlings pin 的**唯一真源** |
| `src/platform/xlings/xlings.cppm` | `kXlingsVersion` — xlings pin 的**唯一真源** |
| `.github/tools/check_version_pins.sh` | 版本/pin 校验 guard(**用 `bash` 跑,不能用 `sh`**) |
| `.github/tools/slim_linux_payload.sh` | linux 载荷 strip + 断言 |
| `.github/tools/mirror_res.sh` | 双端镜像(并发上传 + leg deadline + 完整性 gate) |
Expand Down
4 changes: 2 additions & 2 deletions .github/actions/bootstrap-mcpp/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ inputs:
xlings-version:
description: xlings release to bootstrap from
required: false
# Must equal `pinned::kXlingsVersion` in src/xlings.cppm — enforced by
# Must equal `pinned::kXlingsVersion` in src/platform/xlings/xlings.cppm — enforced by
# .github/tools/check_version_pins.sh, not by this comment. (The previous
# comment here listed the files to keep in lock-step, and that list was
# already incomplete; that is why the check exists.)
Expand All @@ -25,7 +25,7 @@ inputs:
# `package.name`, so one of the two was simply unreachable — and which one
# depended on the machine, which is why CI failed on `compat:lua` on
# Windows and `mcpplibs.capi:lua` on Linux. Never pin below that.
default: '2026.8.11.1'
default: '2026.8.11.2'
cache-target:
description: also restore/save target/ (build artifacts + BMIs)
required: false
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/setup-macos-llvm/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ inputs:
# Floor imposed by the index, not a routine bump — see
# .github/actions/bootstrap-mcpp/action.yml for why 0.4.69 is required
# (two packages named `lua` in one repo need openxlings/xlings#381).
default: '2026.8.11.1'
default: '2026.8.11.2'

runs:
using: composite
Expand Down
10 changes: 5 additions & 5 deletions .github/tools/check_version_pins.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
# Two invariants that used to live only in a comment:
#
# 1. Every xlings version pinned anywhere in .github/ equals
# `pinned::kXlingsVersion` in src/xlings.cppm — which is the version
# `pinned::kXlingsVersion` in src/platform/xlings/xlings.cppm — which is the version
# `mcpp self env` reports and the one release.yml bundles into the
# tarball as <install>/registry/bin/xlings.
#
# 2. mcpp's own version is identical in all four places that carry it.
#
# Why this exists: src/xlings.cppm used to say "keep in lock-step with the
# Why this exists: src/platform/xlings/xlings.cppm used to say "keep in lock-step with the
# XLINGS_VERSION pins in release.yml / cross-build-test.yml / ci-linux-e2e.yml"
# and that list was ALREADY incomplete — it omitted both composite actions,
# which sat on 0.4.30 while everything else moved to 0.4.69. CI's sandbox
Expand All @@ -38,12 +38,12 @@ strip_comments() { sed 's/#.*//'; }

# ── 1. xlings pins ────────────────────────────────────────────────────────

XLINGS_EXPECTED=$(grep -oE 'kXlingsVersion[[:space:]]*=[[:space:]]*"[^"]+"' src/xlings.cppm \
XLINGS_EXPECTED=$(grep -oE 'kXlingsVersion[[:space:]]*=[[:space:]]*"[^"]+"' src/platform/xlings/xlings.cppm \
| grep -oE '"[^"]+"' | tr -d '"' | head -1)
[ -n "$XLINGS_EXPECTED" ] || {
echo "FAIL: could not read kXlingsVersion from src/xlings.cppm" >&2; exit 1; }
echo "FAIL: could not read kXlingsVersion from src/platform/xlings/xlings.cppm" >&2; exit 1; }

note "expected xlings pin: $XLINGS_EXPECTED (src/xlings.cppm)"
note "expected xlings pin: $XLINGS_EXPECTED (src/platform/xlings/xlings.cppm)"

# Anchored patterns only — a bare "version-looking number on a line mentioning
# xlings" would also match `xlings install llvm@20.1.7`, which pins LLVM, not
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/bootstrap-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
# Dormant (workflow_dispatch only), but kept in step with the rest —
# check_version_pins.sh holds it there. Floor: 0.4.69, below which the
# index cannot resolve two packages that share a short name.
XLINGS_VERSION: '2026.8.11.1'
XLINGS_VERSION: '2026.8.11.2'
steps:
- uses: actions/checkout@v4

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci-fresh-install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ jobs:
env:
XLINGS_NON_INTERACTIVE: '1'
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.11.1
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.11.2
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"

- name: Install mcpp and config mirror
Expand Down Expand Up @@ -293,7 +293,7 @@ jobs:

- name: Install xlings + mcpp
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.11.1
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.11.2
# Deliberately NOT writing to $GITHUB_PATH here. On container
# images that declare no PATH in their config (opensuse/
# tumbleweed), appending a single dir to GITHUB_PATH makes the
Expand Down Expand Up @@ -364,7 +364,7 @@ jobs:
# (older ones carry minos=15 and refuse to start).
# v0.4.51+: in-process sha256 — this image has no sha256sum
# binary, so pinned fetches failed before it.
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.11.1
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.11.2
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"

- name: Install mcpp and config mirror
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-linux-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ jobs:

- name: Bootstrap xlings + released mcpp
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.11.1
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.8.11.2
export PATH="$HOME/.xlings/subos/current/bin:$PATH"
xlings update
xlings install mcpp -y -g
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/cross-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ jobs:
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
# Must equal `pinned::kXlingsVersion` (src/xlings.cppm) and the
# Must equal `pinned::kXlingsVersion` (src/platform/xlings/xlings.cppm) and the
# xlings the release bundles — enforced by
# .github/tools/check_version_pins.sh.
#
Expand All @@ -118,7 +118,7 @@ jobs:
# release assets were uploaded in a broken state (records present,
# blobs missing → 404 on GET); re-uploaded clean. The stale-INDEX
# half is handled by the marker-clear below.
XLINGS_VERSION: '2026.8.11.1'
XLINGS_VERSION: '2026.8.11.2'
run: |
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
curl -fsSL -o "/tmp/${tarball}" \
Expand Down Expand Up @@ -255,7 +255,7 @@ jobs:
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.8.11.1'
XLINGS_VERSION: '2026.8.11.2'
run: |
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
curl -fsSL -o "/tmp/${tarball}" \
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
# Pin xlings to a known-good version. The upstream install
# script always grabs `latest` (no version override), so we
# download + self-install manually to avoid broken releases.
XLINGS_VERSION: '2026.8.11.1'
XLINGS_VERSION: '2026.8.11.2'
run: |
if [ ! -x "$HOME/.xlings/subos/default/bin/xlings" ]; then
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
Expand Down Expand Up @@ -288,7 +288,7 @@ jobs:
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.8.11.1'
XLINGS_VERSION: '2026.8.11.2'
run: |
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
curl -fsSL -o "/tmp/${tarball}" \
Expand Down Expand Up @@ -358,11 +358,11 @@ jobs:
# below are pinned to the same version as XLINGS_VERSION; they are
# NOT interpolated from it, so check_version_pins.sh scans for them
# explicitly (they were absent from the old lock-step comment).
XLA="xlings-2026.8.11.1-linux-aarch64.tar.gz"
XLA="xlings-2026.8.11.2-linux-aarch64.tar.gz"
if curl -fsSL -o "/tmp/$XLA" \
"https://github.com/openxlings/xlings/releases/download/v2026.8.11.1/$XLA"; then
"https://github.com/openxlings/xlings/releases/download/v2026.8.11.2/$XLA"; then
tar -xzf "/tmp/$XLA" -C /tmp
XLBIN=$(find /tmp/xlings-2026.8.11.1-linux-aarch64 -path '*/bin/xlings' -type f | head -1)
XLBIN=$(find /tmp/xlings-2026.8.11.2-linux-aarch64 -path '*/bin/xlings' -type f | head -1)
if [ -n "$XLBIN" ]; then
mkdir -p "$STAGING/$WRAPPER/registry/bin"
cp "$XLBIN" "$STAGING/$WRAPPER/registry/bin/xlings"
Expand Down Expand Up @@ -440,7 +440,7 @@ jobs:
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.8.11.1'
XLINGS_VERSION: '2026.8.11.2'
run: |
if [ ! -x "$HOME/.xlings/subos/default/bin/xlings" ]; then
WORK=$(mktemp -d)
Expand Down Expand Up @@ -622,7 +622,7 @@ jobs:
shell: bash
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.8.11.1'
XLINGS_VERSION: '2026.8.11.2'
run: |
# Captured before the `cd` below, in POSIX form: this step never
# returns to the workspace, and GITHUB_WORKSPACE is a backslash
Expand Down
75 changes: 75 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,81 @@
> 本文件追踪 `mcpp-community/mcpp` 公开仓的版本演进。
> 格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)。

## [2026.8.11.2] — 2026-08-11

### 修复

- **⚠️ 回归:SubOS 没有自我描述时,`mcpp build` / `mcpp test` 直接失败
([xlings#543](https://github.com/openxlings/xlings/issues/543))。**

Windows 上 xlings 不写 `subos_info` 块,而 mcpp 把「缺声明」当成了错误,于是
**每一次构建都停在一条讲 GL 驱动的消息上** —— 在一台没有 ELF、没有 `PT_INTERP`、
没有私有 libc 的机器上。`2026.8.10.2` 引入(PR #400),`2026.8.8.4` 正常。

判据改为:**矛盾报错,缺席降级。** 点名的 SubOS 不存在仍是硬错误(该请求无法被
满足);SubOS 存在但没描述自己则记 `declared=false` + 一条必被打印的 note,
runtime 规则报 `inconclusive` 而不是给出判决,构建继续。

同一位置还有第二颗雷:schema 检查是 `!=`,而它的**读取器**明写着「更高的 schema
照读」。xlings 写出 schema 2 的那天,全平台所有构建会同时停摆。已改为上限语义 ——
**发布数据不得使读它的程序失效**。

- **图形/系统库链得上却跑不起来:运行期搜索路径补上 SubOS 库视图。**

mcpp 在编译与链接两条线上都发 `--sysroot=<subos>`,所以 `-lGL` 零 flag 就解析得到;
但运行期的搜索路径是**另一套独立推导**(只有工具链载荷目录)。结果是
`mcpp build` rc=0、`./bin/app` 报 `libGL.so.1: cannot open shared object file`。

```
$ readelf -d bin/app | grep RPATH
before: [<store>/glibc/2.39/lib64 : <store>/gcc/16.1.0/lib64]
after: [<store>/glibc/2.39/lib64 : <store>/gcc/16.1.0/lib64 : <subos>/lib]
```

新增 `mcpp.platform.runtime_search` 契约模块:一条搜索目录有**来源**
(`payload` / `package` / `subos_farm` / `host_default`)、**次序**与**是否机器本地**。
**次序 = 不可变性递减,farm 在最后** —— 载荷目录装一次不再动,`<subos>/lib` 每次
`xlings install` 都重写;载荷在前,`libc`/`libstdc++` 永远从被 pin 的载荷解析。
交叉目标与非 ELF 格式不发 farm。

- **`validation: pass` 曾对一个跑不起来的产物成立。**

闭包解析在搜完 rpath 后**回落到宿主默认目录**,而宿主通常自带 `libGL.so.1` ⇒
模型认为解析到了。但产物跑在**私有加载器**下,它的默认路径里没有宿主目录。
现在宿主默认目录只在**非 hermetic** binding 下参与;hermetic 产物上一个谁都提供
不了的 `DT_NEEDED` 是**可证的**失败(新判决 `unresolvable`),会让构建变红并指名。

实测佐证(`LD_DEBUG=libs`):私有加载器的内建默认路径是 glibc 载荷**自己的构建期
前缀**(`…/fromsource-x-glibc/2.39/lib`),这台机器上根本不存在;`/usr/lib` **从不**
被查。因此 e2e `206` 里那条「安全的宿主 DSO 对照」此前报 `pass` 也是假绿 —— 它
刻意不运行产物,而产物其实 127。已改为断言 `inconclusive` 并说明原因。

**`[build] allow_host_libs` 同时退出两个阶段。** 它本就关掉链接期 hermeticity 检查;
既然用户已声明「我有意伸到沙箱外」,mcpp 就不能再断言产物起不来(他们可能用
`LD_LIBRARY_PATH` 跑,或装在私有加载器会看的地方)。⇒ 该档下未解析的 `NEEDED`
报 `inconclusive` 并指名,而不是变红。一条声明,一个含义。

另两处精度修正(CI 抓到的):`unresolved` 此前混装三种东西 ——「找不到的 SONAME」
「读不了的对象」「512 上限」。只有第一种可证,故拆出 `unresolvedSonames`;
且**产物的格式由产物决定,不由 binding 决定** —— Linux→Windows 交叉构建拿的是宿主
binding(hermetic),产物却是 PE,「不是 ELF」落进 `unresolved` 后被判成「缺库」,
让 `crosswin.exe` 构建失败。

### 变更

- xlings 强相关模块归入 `src/platform/xlings/`:`mcpp.platform.xlings`、
`mcpp.platform.xlings.subos_info`、`mcpp.platform.xlings.runtime_selection`
(命名空间不变)。`RuntimeBinding` 与 `runtime_search` 留在 `src/platform/` ——
它们是 provider 中立的契约类型,不是 xlings 专属。
- `resolution.json` 的 `runtime.search` 增加 `closure` 数组(路径 + origin +
machine_local,**保序**);`mcpp why runtime` 按加载器次序打印它。
- mcpp 为自己启动的每个进程声明 `XLINGS_SUBOS_LD_PATHS=0` —— xlings 链接器包装器
路径注入的退出声明([xlings#540](https://github.com/openxlings/xlings/issues/540))。
今天是无操作;它落地后 mcpp 的 DT_RPATH 仍只含 mcpp 自己决定的内容。
**不读 `$XLINGS_SUBOS_LIB`**:实测它指向当前 shell 的 subos,而 mcpp 有自己的
registry home,两者通常由**不同物理 glibc 载荷**支撑。
- 内带 xlings pin → `2026.8.11.2`。

## [2026.8.11.1] — 2026-08-11

### 新增
Expand Down
10 changes: 10 additions & 0 deletions docs/02-pack-and-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ How to choose:
- Cross-distro / older glibc (legacy CentOS, Kylin) → `self-contained`
- Single portable file, no host deps → `static`

**No mode ships a build-machine path.** A development build addresses this
machine on purpose: its `DT_RPATH` names the toolchain's payload directories and
the SubOS library view (`<subos>/lib`), and its `PT_INTERP` names a private
loader. Every mode rewrites both — `vendored`/`self-contained` to `$ORIGIN`
relative paths, `system` by clearing the search path entirely and restoring the
platform's standard interpreter. `system` is not "keep whatever the build had";
it is "the target provides everything", which is a statement about the target
and cannot be spelled with this machine's absolute paths. e2e 215 sweeps every
ELF in the bundle for anything under `$MCPP_HOME` and fails on a hit.

### A program that needs the HOST to provide something

"Self-contained" has a floor. Some libraries can only come from the target
Expand Down
Loading
Loading