Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
6742728
design: the ecosystem gap supplement (2026-11-15)
Sunrisepeak Nov 15, 2026
7f00eba
m1: two build-dependency requests no version satisfies are refused by…
Sunrisepeak Nov 15, 2026
d96e7fd
m2: launchers by the system table, one per program, and the program a…
Sunrisepeak Nov 15, 2026
2174213
m3: a stated program name on every row, one linked file, resources fo…
Sunrisepeak Nov 15, 2026
05ca70e
m4: execution relations, the row's exception model and companions (N2…
Sunrisepeak Nov 15, 2026
a70348e
m5: runners enabled on request, and named runners as tables (R1, X1, R2)
Sunrisepeak Nov 15, 2026
b4e8bd3
m6, m7: a runner as one statement in a build program, and the program…
Sunrisepeak Nov 15, 2026
6ec6b89
m9: the guide reads the resolved graph, a group's programs are planne…
Sunrisepeak Nov 15, 2026
60435d6
m8: x86_64-linux-android runs in the Android Emulator on request (G7)
Sunrisepeak Nov 15, 2026
e12c8cb
2026.11.16.1: a named system where no single file is made is refused …
Sunrisepeak Nov 15, 2026
3f6b9ed
#938: a missing source named by its path is refused in an editable tr…
Sunrisepeak Nov 15, 2026
085fbd2
design: X3 located and fixed in the musl recipe
Sunrisepeak Nov 15, 2026
7e2b3d0
A link holds a permit of the build's compiler limit, and a POSIX link…
Sunrisepeak Nov 15, 2026
60c3300
design: N41, mcpp's bundled xlings moves to 2026.11.16.1 (for review)
Sunrisepeak Nov 15, 2026
d12da61
The bundled xlings is 2026.11.16.1
Sunrisepeak Nov 15, 2026
3ff5e73
A package's tests are selected by target and built with the features …
Sunrisepeak Nov 15, 2026
2b21e19
e2e: an inherited home's subos is the case's own copy, its links kept
Sunrisepeak Nov 15, 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
694 changes: 694 additions & 0 deletions .agents/docs/2026-11-15-ecosystem-gap-supplement-design.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
---
```

362 records.
363 records.

## By subject

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

### cross-platform

- [生态缺口补充方案:一个 C 程序走遍全部目标所暴露的通用问题](2026-11-15-ecosystem-gap-supplement-design.md) — active
- [生态方案:跨平台通用基础设施(mcpp + openkal + xim),以一个 C89 工程为验证](2026-11-10-cross-platform-ecosystem-design.md) — active

### design
Expand Down Expand Up @@ -201,6 +202,7 @@ Records that declare one. Everything else is listed by date below.

### 2026-11

- [生态缺口补充方案:一个 C 程序走遍全部目标所暴露的通用问题](2026-11-15-ecosystem-gap-supplement-design.md) — active
- [发布的发布面与 macOS 链接的 SDK 契约(2026-11-14 补充)](2026-11-14-release-publication-and-macos-sdk-design.md) — active
- [CI 与发布的时间成本:按测量调度的测试、分片、并行发布](2026-11-14-ci-and-release-time-cost-design.md) — active
- [The three-plane platform architecture: mcpp × openkal × xim](2026-11-12-three-plane-platform-architecture-design.md) — superseded by [2026-11-12-ecosystem-architecture-optimization-design.md](2026-11-12-ecosystem-architecture-optimization-design.md)
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/bootstrap-mcpp/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,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.10.26.1'
default: '2026.11.16.1'

outputs:
sandbox-key:
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.10.26.1'
default: '2026.11.16.1'
image:
description: >
The runner label the job runs on (macos-15, xcode-27). It is part of the
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.10.26.1'
XLINGS_VERSION: '2026.11.16.1'
steps:
- uses: actions/checkout@v4

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci-bootstrap.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
os: [ubuntu-24.04, macos-15, windows-2025]
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.10.26.1'
XLINGS_VERSION: '2026.11.16.1'
steps:
- uses: actions/checkout@v4

Expand All @@ -50,7 +50,7 @@ jobs:
shell: bash
run: |
set -euo pipefail
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.10.26.1
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.11.16.1
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"
echo "$HOME/.xlings/bin" >> "$GITHUB_PATH"

Expand Down Expand Up @@ -124,7 +124,7 @@ jobs:
shell: bash
run: |
set -euo pipefail
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.10.26.1
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.11.16.1
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"

- name: Install the newest release and build the tree with it (mcpp build --strict)
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 @@ -167,7 +167,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.10.26.1
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.11.16.1
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"

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

- name: Install xlings + mcpp
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.10.26.1
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.11.16.1
# 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 @@ -479,7 +479,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.10.26.1
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.11.16.1
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 @@ -469,7 +469,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.10.26.1
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.11.16.1
export PATH="$HOME/.xlings/subos/current/bin:$PATH"
xlings update
xlings install mcpp -y -g
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/ci-unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,17 @@ jobs:
set -euo pipefail
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
mkdir -p "$RUNNER_TEMP/unit"
# LINKS BOUNDED BY THE BOOTSTRAP'S SCHEDULE. Before 2026.11.16.1 a link
# under the detached schedule (bmi_schedule = "on") took no permit, and
# ninja ran six per compiler: a change every test links relinked the 26
# tests at once, at 1 to 1.8 GB each, and the runner ran out of memory.
# Such a bootstrap builds the archive with the ordinary schedule, whose
# job count bounds links; a later one holds a permit for each link.
v=$("$MCPP" --version 2>/dev/null | awk '{print $2; exit}')
if [ "$(printf '%s\n' 2026.11.16.1 "$v" | sort -V | head -1)" != 2026.11.16.1 ]; then
export MCPP_BMI_SCHEDULE=off
echo "the bootstrap $v holds no permit for a link: the archive is built with bmi_schedule off"
fi
# shellcheck disable=SC2086 -- the flag is one word or none
# The profile `ci` (mcpp.toml): -O0 and no debug information. The
# default profile of this package is release (-O2); the tests built
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/cross-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,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.10.26.1'
XLINGS_VERSION: '2026.11.16.1'
run: |
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \
Expand Down Expand Up @@ -322,7 +322,7 @@ jobs:
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.10.26.1'
XLINGS_VERSION: '2026.11.16.1'
run: |
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,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.10.26.1'
XLINGS_VERSION: '2026.11.16.1'
run: |
# BY VERSION, NOT BY PRESENCE. A restored ~/.xlings holds the
# xlings of an earlier release, and this binary is the one the
Expand Down Expand Up @@ -347,7 +347,7 @@ jobs:
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.10.26.1'
XLINGS_VERSION: '2026.11.16.1'
run: |
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \
Expand Down Expand Up @@ -416,7 +416,7 @@ 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.10.26.1-linux-aarch64.tar.gz"
XLA="xlings-2026.11.16.1-linux-aarch64.tar.gz"
# NOT fetch_release.sh: this asset is OPTIONAL and the `if` is the
# point — an arch with no prebuilt xlings must fall through quietly,
# while the helper retries a 404 five times before giving up. The one
Expand All @@ -425,9 +425,9 @@ jobs:
# cover it.
if curl -fsSL --retry 3 --retry-delay 2 --retry-all-errors \
--connect-timeout 20 --max-time 600 -o "/tmp/$XLA" \
"https://github.com/openxlings/xlings/releases/download/v2026.10.26.1/$XLA"; then
"https://github.com/openxlings/xlings/releases/download/v2026.11.16.1/$XLA"; then
tar -xzf "/tmp/$XLA" -C /tmp
XLBIN=$(find /tmp/xlings-2026.10.26.1-linux-aarch64 -path '*/bin/xlings' -type f | head -1)
XLBIN=$(find /tmp/xlings-2026.11.16.1-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 @@ -506,7 +506,7 @@ jobs:
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.10.26.1'
XLINGS_VERSION: '2026.11.16.1'
run: |
# By version, not by presence (see the Linux job).
have=$("$HOME/.xlings/subos/default/bin/xlings" --version 2>/dev/null | awk '{print $2}')
Expand Down Expand Up @@ -698,7 +698,7 @@ jobs:
shell: bash
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.10.26.1'
XLINGS_VERSION: '2026.11.16.1'
run: |
# Captured before the `cd` below, in POSIX form: this step never
# returns to the workspace, and GITHUB_WORKSPACE is a backslash
Expand Down
142 changes: 142 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,148 @@
> Each `## [<version>]` section is that release's notes. Entries are written in English
> from 2026.9.28.3 on; earlier entries remain as written.

## [Unreleased]

## [2026.11.16.1] - 2026-11-16

### Changed

- The bundled xlings is 2026.11.16.1. On Windows it replaces a SubOS
description while another process reads it, where a concurrent install
failed with `Failed to write file: ...\.xlings.json` (xlings#715), and a shim
passes an argument holding `"`, `&`, `%` or `^` whole.

### Added

- `[target.'<sel>'.test] discover` selects a package's test programs by
target: its globs join `[test] discover` for the targets the predicate
selects, and a `!` glob removes tests there. A package on the Web holds a
test that needs a native-only dev-dependency without a second package (#942).
- `[test] features` names the features a package's own test build turns on.
The tests are a consumer of the package and this is their request: `mcpp
build`, the programs the tests run and every other consumer keep the
package's defaults, and in a workspace each member's request stays on its own
edge (#941).
- `x86_64-linux-android` runs in the Android Emulator on an x86_64 Linux
machine, once enabled: dirun (>= 0.4.0) boots the API 34 system image
through the image package's profile, and the target's runs do not overlap.
A provider's runner states `exclusive` (G7).
- `mcpp::runner_spec` states a runner in a build program as the table of
data: `.arg()`, `.require()`, `.hosts()`, and `host`, `longlived`,
`exclusive`, `enabled` (protocol 19). `{pkg:<name>}` names a program outside
a package's `bin/`, installed by the first run. A name stated by
`runner_spec` and by the token calls is refused (R2).
- A runner states `enabled = false` when its first use fetches a whole machine
image or an emulator, or leaves state outside the build tree and the package
store. `mcpp run` refuses it with status 2 and `mcpp test` leaves the tests
built and not run, naming `[runner-not-enabled]`, the packages its first use
installs and the ways of enabling it; nothing is installed first. A table
without `cmd` in `config.toml` or the project enables it (`runner = { enabled
= true }`), `MCPP_TARGET_<TRIPLE>_RUNNER_ENABLED=true` enables it once, and
`mcpp run --runner <name>` enables the runner it names. A runner whose `cmd`
a nearer tier replaces is enabled unless stated (R1).
- The Windows rows on an x86_64 Linux machine state Wine as their runner
(`xim:wine@11.0`, `host = "same-arch"`), not enabled by default (X1).
- A named runner takes the table of the default runner (`runners.<name> = {
cmd = [...], longlived = true, enabled = false }`) and merges by the same
rule; `longlived` states in data what `runner_longlived` states in a build
program. A provider's runner states `host` and `enabled` (R2).
- The execution table (`[[platform.executes]]`, SPEC-016 §2.4): a machine runs
the programs of another architecture where it is stated, `linux-x86_64`
executing `i686`. There a `same-arch` runner is built for the artifact's
architecture and started on this machine, and a launcher whose package lacks
this machine's architecture takes one the machine executes: an i386 image
runs on x86_64 Linux through the i686 runner (design 2026-11-15 N23).
- A row's `companions` (`.wasm` on wasm32-emscripten): removed before each
link, staged when the link wrote one, not an error when absent. A clean pack
with `-sSINGLE_FILE=1` failed, naming the missing module, and an earlier
link's module was packed beside a launcher that embeds its own (N33).

- `mcpp::pack_program("<program>")` (build-program protocol 19): a pack-format
provider states the program of the package being packed that it assembles
from, and `mcpp pack --pkg-format <format>` with no program named packs that
program. A program named on the command line outranks it; providers that
state different programs, or a program the build does not have, are refused
by name (design 2026-11-15 N30).
- A pack whose format provider submitted nothing lists, in the refusal, the
warnings the provider stated in that pass (`mcpp::warning`, `mcpp::report`)
as its reasons (N30).

### Changed

- A wasm32-emscripten build whose project states no `[abi] exceptions` uses
WebAssembly exception handling, the row's `exceptions = "wasm"`: a C++
exception is caught, and `setjmp`/`longjmp` follow the same model. The SDK's
default left catching off. `exceptions = "js"`, `true` or `false` states
another model or none (N26).
- A package that carries its runner (`--mode self-contained`) starts only the
runner it carries for this machine, and a machine it holds none for exits
with status 126, naming the machine and the systems the package holds. The
POSIX and the Windows launcher fell back to a runner on `PATH`, which ran
another release's runner (design 2026-11-15 N20).
- The POSIX launcher names the system by the system table's `uname` column, so
a FreeBSD machine finds `libexec/<runner>/freebsd-<arch>/`; it looked for
`FreeBSD-<arch>` (N20).

### Fixed

- A single file named for a system where the platform's runner does not exist
(`--systems macos` for an x86_64 image whose platform names no
`macos-x86_64` runner host) is refused before the build, by the reading
`--systems all` applies to leave it out; it was refused after the build.
- `mcpp test --guide` reads the frameworks from the resolved graph and plans,
scans and builds nothing; at a workspace root it names the frameworks of
every member. It planned and built the whole workspace first (#932).
- `mcpp test` over several members plans a configuration group's programs
together, as `mcpp build --workspace` does. Each member's programs were
planned alone, with that member's features for the packages it shares, and
rebuilt a shared module into the group's directory: three compiles of one
unchanged module in a run, and on Windows a failed rewrite of a module
another process had mapped (#936).
- Under `bmi_schedule = "on"` with GCC a link holds a permit of the build's
compiler limit. Ninja runs six jobs per compiler there and only compilers
were bounded, so links that became ready together all ran at once: mcpp's
26 test programs relinked together at 1 to 1.8 GB each and a 16 GB machine
ran out of memory. A POSIX link is published through a temporary name by
`mcpp link-output --temporary`, one command, so the permit is held until the
artifact is in place.
- A `sources` entry without a pattern that names no existing file is an error
naming its table, and a warning in a package fetched into a store. It was
skipped, and the build failed at an importer of its module (#938).
- On Windows a runner named with a directory and no suffix (`../tools/x`)
takes the system's suffixes as a bare name does; it could not be started.
A `.bat` or `.cmd` program, which the system starts through its command
interpreter (the system table's `command-scripts`), is refused an argument
holding `%`, `^`, `&`, `|`, `<`, `>`, `"` or a line end, which the
interpreter rewrote or ran as a command (R2).
- A name a build program, this machine or the project states for a program
(`mcpp::artifact_name("exe", "{name}")`) is followed on a built-in row as on
a platform's: a program named `cmd.exe` was `cmd.exe.exe` on
x86_64-windows-gnu and `cmd.exe` on x86_64-windows-musl (design 2026-11-15
N9).
- A linked program is written under a temporary name that keeps its extension
(`<dir>/.<file>`, then renamed). DJGPP's driver names a second file after the
output's extension, so `<out>.tmp` left two programs in `bin/` on
i586-dos-djgpp (N9).
- The carrier of an image whose row the built-in table keeps planned and the
project's platform lists with its toolchain is built (an i686 image's
i686-linux-musl runner); it was refused as a row this mcpp builds no program
for (N23).
- `[resources]` and the application manifest are compiled only for a PE row
whose execution system reads them, the system table's `resources = true`
(the built-in `windows` entry); the UEFI row, a PE image the firmware
loads, failed the build with them (N16).
- Two `[build-dependencies]` requests of one package that no version
satisfies are refused as such, naming both requesters, the merge's reason and
the `override` line. The engine tried to rename the second copy's modules,
which does not separate a build program's modules, and failed on the
requester's sources with a message about staging (a project asking for
`mcpp:plugins` 0.21.0 over a platform asking for 0.20.0: `stage: no source
files found under '<platform>'`) (design 2026-11-15 N29).
- `mcpp pack --all-programs` of an ok image gives every program its own pair of
launchers, `bin/<name>` and `bin/<name>.exe`; only the chosen program had them
(N11).

## [2026.11.15.1] - 2026-11-15

### Added
Expand Down
Loading
Loading