Skip to content

Commit 4d9e037

Browse files
authored
2026.11.10.1: base packages, Windows GNU-ABI from every host, FreeBSD rows, foreign packing, test records for any framework; mcpp#911 N1–N8, #913, #902, #917 (#916)
* E2, E13, E14: an entry per program's flags; the kernel-abi provider's interfaces for build programs; layer suppliers may not require one another in a circle * E1: rows a platform defines are read as the built-in ones are; nothing of the payload's host side reaches a row whose C library a platform describes * E3: a GNU-ABI Windows row finds its resource compiler in the paired payload or uses llvm-rc; a quoted toolchain header is the toolchain's * E4: FreeBSD's identities are built-in data with their compiler triple; the rows' systems are words of the language; a platform-served row names the platform as its remedy * E5: a base package states the C++ run-time and compiler run-time it holds beside its C library; its headers, libraries and std module stand where the payload's would * E6: a patched member of a git repository is patched in a copy of the repository, so its edges to sibling members hold * E7: a foreign artifact's closure is read from its DT_NEEDED; --mode static links and checks a static program A program for another system was handed to the host's ldd (exit 127). Its closure is now read from the file: a library this build produced travels beside it, every other name is the target system's. `--mode static` sets force_static and checks the file, so a dynamic program is never packed under the `-static` name; a row whose C library a platform describes supports a full static link. * E8: [platform.link] flags that a compiler link does not use are named; docs/04 states per-target object variants The words are given to ld.lld only; a platform with driver = "compiler" now receives a warning that names [platform.build] ldflags. docs/04 states the per-target object variants and per-program entry objects instead of the retired compile-once sentence. * E9: a MinGW-w64 base package serves the GNU-ABI Windows rows beside llvm on every host; the unserved-target remedy names a spelling the parser accepts The mingw-llvm provider names xim:mingw-w64-sysroot (the target side of llvm-mingw: MinGW-w64 on UCRT, libc++, libunwind, compiler-rt) for x86_64-windows-gnu and the new aarch64-windows-gnu row, below the gcc payload where that exists. A base package on a MinGW row is the driver's sysroot with the run-times its layers state; its compiler runtime is read from the directory the base names (compiler-runtime-dir), and a static link takes its archives. A provider's sysroot package is the base statement of last resort. The unserved-target diagnosis names [toolchain] <host> = { path, prefix } instead of [target.X] toolchain = "<path>" (mcpp#913). * E10: a scan override of a file this build excludes is kept for the builds that compile it (mcpp#902) A [scan_overrides] glob whose files exist and take no part in this build -- a feature that is off, a ! rule of a [target.<selector>.build] -- is no longer refused; a glob that matches no file of the package still is. * E11: the 32-bit hosted identities (i686-linux-musl, i686-linux-gnu, i686-openkal) are registered intent Planned rows: a request is refused as planned rather than as an unknown target, and an explicit [target.<row>] toolchain opts in early. No payload of the index targets them, and openkal's 32-bit class is a design discussion. * docs: SPEC-002 v1.6 (base packages, layer-cycle), SPEC-006 v0.11, SPEC-013 v1.7, SPEC-014 v2.2, SPEC-016 v1.1; MCPP_KERNEL_ABI_INTERFACES and layer-cycle in docs/30 and docs/50 * docs: base packages (docs/22), the targets every host reaches (docs/21), foreign ELF closure and the static check (docs/10), defined rows, served FreeBSD rows and link.flags (docs/35); en and zh * 2026.11.10.1: version, CHANGELOG; CI bootstraps from 2026.11.9.1 * AGENTS.md: the repository's rules in their shortest form, linked to the documents that state them; design record 2026-11-10 (cross-platform ecosystem, fourth version) * E5: a base package is an ordinary package -- provides answers its layers, [build] states them, the package root is the sysroot; a provider's sysroot is its identity's base The [base] table (an architecture-keyed roots map, include-dirs, libs by link form, compiler-runtime-dir) is replaced by the manifest vocabulary every layer supplier uses: include_dirs, ldflags, std-module*, and one new [build] key, compiler_runtime_dir (-resource-dir for clang, -B for gcc). One base package is the sysroot of one identity; a platform's provider takes sysroot as a package or { path }, ahead of the platform's own. The mingw-llvm provider names xim:mingw-w64-sysroot@20261104-1. * tests: the rows E4, E9 and E11 add -- capability pins, the windows set, the rows snapshot; freebsd is a platform name * README: the rows this release adds; graph.cpp stays within its length limit * A provider's base yields to a graph-supplied system; a carrier that names no hosts exists where the platform's runner does CI on #916: a carrier for windows-aarch64 was built now that aarch64-windows-gnu is a row, over the mingw-llvm base beneath openkal-windows (an x86_64 implementation). The provider's sysroot, an engine default, is no longer a statement when the graph supplies the system, as the row's toolchain convention already is not; and a carrier that names no hosts is built only where the platform's runner exists (runner.hosts), so --systems all leaves the others out with the reason. * mcpp test states what its programs report as they report it: parts, case records, metrics and bounds; SPEC-017 (mcpp#917) The runner's side of the test protocol, for any framework that implements it: - test-parts: --cases names the parts [test] split runs a program as (parts), and each part's record names its program (part_of); - test-case-stream: the report is read while the program runs (P5.1), and a case record states each case's beginning and end before the program's record; - test-metrics: the cases' kind, tags, metrics and bounds and the program's usage reach the records, and the run kept under target/mtest carries them with each case's start and its failures' expected and actual values (P6, P10.2, P12), so a Bench case's measurements reach mtest analyze trend. The --list main keeps its meaning. SPEC-017 states the runner, the protocol it reads, the records and the store, framework-neutral. * Windows resources: the subjects of the plan are collected by their own function step13_windows_resources stays within the 400-line function limit. * A provider's base is kept only once the graph is known; a paired sysroot is stated wherever no cfg is trusted The base statement was memoised when first asked, before the dependency graph was loaded, so a provider's base did not yield to a graph that supplies the C library (x86_64-windows-gnu over openkal on hosts the mingw-llvm provider serves). The compile side stated a paired provider's sysroot only when a cfg was bypassed; the Windows llvm payload has no cfg, so aarch64-windows-gnu found no libc++ headers there. The link side already stated it unconditionally. * Target matrix: the cells of the mingw-llvm provider and the planned rows; e2e 1063 runs in the wine job * Two mcpp processes of one home install one package once; e2e 182 states the MSVC ABI it asks for A dependency is installed under the home's install turn (registry/.install.lock, re-entered for the package's own dependencies); a process that waited for the turn looks for the package again before installing it. A second process was told the install succeeded while the first was still placing the package, and stopped with "install path missing after fetch" (two e2e workers fetching one package into one home). e2e 182: llvm alone is not a request for the MSVC ABI now that clang pairs with the MinGW-w64 payload and compiles against it on a host without a cfg; the project writes x86_64-windows-msvc as its target. * docs/25: a home's install turn * A base package's C library is reported by the name its manifest states; the mingw-llvm provider names mingw-w64-sysroot 20261104-2 (mcpp:c-abi=ucrt) The c-abi layer of a base package was reported by the package's name (mingw-w64-sysroot); it is the C library its provides states. Revision 2 of the MinGW-w64 base states ucrt, the name mcpp's vocabulary gives the Windows C library and the one the MinGW-w64 payload answers, so that one requirement (compat.glfw's Win32 backend) is met by either. The design records I1 in that form, and the defects CI exposed. * The base statement decided before the graph is kept as provisional, not dropped base_statement_text points into the memo; an answer that was not kept left it pointing at another target's statement or at none. The engine tier's answer is kept and marked provisional, and asked again once the dependency graph is loaded. * A paired system's C++ library is stated on C++ commands only -stdlib= rode the toolchain words every C and assembly command shares, so a C unit of a paired target drew clang's unused-argument warning, an error under -Werror. paired_stdlib_flag() is appended to the C++ flags and to the module scan; the std module build asks for it as before. * A payload not found after its install names the directories it was looked for in The error "install path missing after fetch" now lists each version directory the lookup tried, in its order, so that a provider that placed the payload elsewhere is seen at once. e2e 15 prints the output of a failing mcpp test. * A version a merge replaces withdraws the requests it made A resolved record keeps its constraints by requester, and a merge that replaces <ns>.<name>@<old> records that version as superseded: the items it queued are not walked, and its constraints no longer bound a merge. The graph os 0.4.4 -> 0.4.1 (pinned) was refused with "irreconcilable versions" between openkal 0.24.0 and a request of openkal-linux 0.26.0, a version no longer in it. e2e 1066 reproduces the order. * mcpp test: the cases counted beside the programs, and the failures as an index The summary states the cases that check (a case that declared cases is told by them): cases: N passed, N failed, N skipped (in N programs). The failures list each failed program and under it the failed leaf cases at the place of their first failure; the per-program repetition of the case failures, which the framework's own output already shows under the program's line, is gone. The program count keeps its words. * cenv: FreeBSD and NetBSD present POSIX as Linux does The BSDs' ELF triples predefine __unix__ and are LP64 with a 32-bit wchar_t, so a C library's posix/arch-default declaration is realised with no token (<arch>-freebsd-musl: a C library above openkal-freebsd). docs/22 states the row. * The missing-payload diagnostic names the configuration its stores come from * Design: tests and dependency resolution, a supplement (mcpp, mcpp test, mtest, mcpp-ide) * Design: tests and dependency resolution, second revision (layers, the test session, case output and checks, self-review) * Design: tests and dependency resolution, third revision (mcpp test spec with base and optional capabilities, the session as an optional capability, the global review) * build: a package's root is its own file (package_root.cpp) makePackageRoot and the expansion of include directories move out of graph.cpp, which had passed the 2,500-line limit; the graph's steps and the later phases take a root from there. * config: a borrowed registry keeps the index places its owner recorded A home whose [xlings] home names an existing registry wrote its own index directory and store into that registry's configuration. The e2e homes under a temporary directory did, and later builds over the shared registry were sent to a store deleted with its home ("install path missing after fetch" on Windows and macOS). Such a home now records no place of its own there; e2e 1067 fails before and passes after. * e2e 1066: the replaced family's implementation is absent on every system The test named openkal-linux; on Windows and macOS the pinned os brings the 0.24 family's implementation of that system instead. * CHANGELOG: requests of a replaced version, the case summary, BSD C environments, borrowed registries * test: release the build directory before running; build programs by the fast path; state only work done - The build directory's lock is dropped once the tests are built, and each invocation reports into its own protocol directory, test-protocol/<pid>-<start>/, removed when it ends and swept when its process is gone (#915). e2e 1068 runs a build and a second test beside a running one; it fails before and passes after. - The programs a test finds as MCPP_BIN_<NAME> are built by try_fast_build when no override applies, which now hands back the recorded programs. - The packages are no longer announced before the build; Phase A's report names a package when one of its steps runs, and a test's Compiling line is written when the bulk pass ran a step of its own. - The test graph is written to test.ninja (set on the three test plans). * build: the test graph is test.ninja, and a scan both graphs name has one command BuildPlan::graphFile names the file the backend writes and drives (-f). test.ninja shares the directory's objects, .ninja_log and .ninja_deps with build.ninja, so an output both graphs name with different commands is rebuilt rather than reused. The dyndep rule's text no longer depends on the plan: $module_map carries its own leading separator, and obj/main.cpp.ddi.dd was rescanned on every switch between mcpp build and mcpp test because its command differed by a space. The e2e that read the test graph from build.ninja read test.ninja. * targets: the built-in platform of the openkal targets is openkal-platform 0.25.0 openkal-platform 0.25.0 (mcpp-index#751) groups openkal 0.25.0, openkal-image 0.5.5, openkal-musl 0.29.0 and the implementations of the 0.25 family; its mcpp floor is 2026.11.9.1. * CHANGELOG: test.ninja, the programs' fast path, Compiling lines, the released build directory, platform 0.25.0 * test: the tests of an unchanged project run from the plan's record A full mcpp test writes test-plan.json beside test.ninja (every test of the package: its program, its own sources, its protocol or the objects that state it, its guide; the runtime directories and the tool directory; [test] split and store) and a build-cache entry for the test graph (selection @test). The next mcpp test admits that entry through admit_recorded_build, which now takes the graph it replays, asks that the discovered tests are the recorded ones, that nothing under tests/ is newer than the graph and that ninja has nothing to do for the selected tests, and runs them from the record; the environment, the arguments after -- and the programs' places are joined at run time. A workspace's root package matches its own record (selection and group '.') on both fast paths. e2e 1069 fails before and passes after; on a workspace of 1,500 sources one program's unchanged tests went from 5.8 s to 0.13 s. * e2e 1068: a test that builds its own project neither waits nor plans (#915) The issue's shape: the test runs mcpp build in its project with the test's environment. Measured for T9 on 2026.11.9.1 and 2026.11.10.1, with gcc and with an llvm workspace: the test's environment (the subos's bin first on PATH, its library variables, MTEST_*) leaves the configuration's fingerprint as it is; the rebuilds the issue saw were the test graph written over build.ninja and the lock held through the run. * test spec: SPEC-017 v2.0, launch records, framework capabilities and sessions, check details, a case's output docs/specs/test.md is the mcpp test spec: SPEC-017 v1, the mtest protocol's normative text (P1-P12 kept) and the [test] keys, as base capabilities B1-B6 and optional ones O1-O9; test-runner.md is folded into it. B5: --no-run records carry each program's launch. B6: an entry target's test-capabilities and test-session, reported by --guide. O3: failure source and fatal, case checks, in records and the store. O8: a case's output from the program's output events, or from a program that ran that case alone; the output of several cases is not divided by arrival, which a buffered stream does not allow (measured). Features test-launch-records, test-frameworks, test-checks, test-output. e2e 1070 fails before and passes after. * pack: the generated launchers depend on mcpplibs.os 0.4.4; e2e 1068 and 1069 on every host The Windows launcher and the single-file launcher pinned mcpplibs.os 0.4.1, of the openkal 0.24 family, which the built-in platform 0.25.0 refuses (cross/mingw-cross, e2e 988); 0.4.4 ranges over the 0.24 and 0.25 families. e2e 1068 bounds its commands without timeout(1), which macOS lacks; e2e 1069 asserts that no dev-dependency is resolved, since the programs' build plans on hosts where mcpp build plans each time (macOS). * dependencies: the root overrides a package for the whole graph (#914) override = true on a root's dependency or in [workspace.dependencies] answers every request for the package in the graph its table governs ([dependencies]: build and tests; [dev-dependencies]: tests; [build-dependencies]: build programs). A replaced request that does not already admit the override is named once (Overrode); mcpp.lock marks the package and --locked reads the marker; an override of a platform version group's member is taken with a warning; a library's override is ignored and said to be. A refusal of two irreconcilable versions names the overriding line; a library's exact pin of a package every consumer shares (a target-side layer, a kernel ABI) is noted to its users and refused by mcpp publish. src/build/prepare/overrides.cpp holds the steps. e2e 1071 fails before and passes after. * unit: the Windows launcher's manifest names mcpplibs.os 0.4.4 * manifest: test-capabilities and test-session are known target keys An entry target that states them is not warned of an unsupported key. * e2e 1070: the framework's path in host spelling * link: the toolchain's C++ archives built for another target are not linked flags.cppm reads the triple of the directory the payload's libc++.a was found in; another architecture or system marks MechanismInput::foreignCxxArchives, and resolve() links no C++ runtime there and states that the row's is a package's (mcpp:c++-abi). Measured on aarch64-freebsd-musl from a Linux host: ld.lld: libc++.a(algorithm.cpp.o) is incompatible. The OpenKal conformance suite now takes openkal-llvm-runtime there (openkal-freebsd). * bench: mcpp's own costs as mtest Bench cases with a history (no-op build, why flags, one interface edit) bench/tests/engine.cpp times the mcpp under test (MCPP) on a small module fixture; each cost enters the mtest store as a metric with its samples. The engine comparisons remain the standard set run by hand. * CI: mtest pinned once and every test run reported through it .github/versions.env pins mtest (MTEST_VERSION, MTEST_SHA256); the composite action mtest installs it and exports MTEST, and e2e-mtest takes it from there. test-report merges the stores mcpp test kept in a job, writes the job's Markdown report into its summary and uploads the store; the unit jobs of the three hosts and the Linux bench run use it. Each e2e shard writes its report, run_all.sh groups the shards by the workflow run, and ci.yml's test-report job renders one report over every job (mtest ci report). * Design notes: implementation records of the ecosystem plan and its supplement * CI: mtest is installed into the global subos, so the report runs it outside the repository * resources: a cross gcc's Windows headers are the toolchain's; an include nothing provides is the script's own - system_include_dirs reads a cross gcc's own <root>/<triple>-w64-mingw32/include when no payload is paired: under the mingw provider, a script's "winres.h" was taken for a file of the project that no action produces, and the build failed in ninja (e2e 1058, the cross gcc case). - A quoted include found in no directory is an input only when a build action writes it; otherwise the script's preprocessing decides (#if __has_include) and the resource compiler names a missing one with the script and line (e2e 1072). - docs/04 (en, zh) and CHANGELOG. * Design notes: the resource findings of the validation in the implementation record
1 parent 9edccc4 commit 4d9e037

155 files changed

Lines changed: 6954 additions & 647 deletions

File tree

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-11-10-cross-platform-ecosystem-design.md‎

Lines changed: 621 additions & 0 deletions
Large diffs are not rendered by default.

‎.agents/docs/2026-11-10-test-and-resolution-supplement-design.md‎

Lines changed: 471 additions & 0 deletions
Large diffs are not rendered by default.

‎.agents/docs/README.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ superseded_by: 2026-09-07-....md # when status is superseded
1818
---
1919
```
2020

21-
356 records.
21+
358 records.
2222

2323
## By subject
2424

@@ -42,6 +42,10 @@ Records that declare one. Everything else is listed by date below.
4242

4343
- [Compiler attempt lifetime and output recovery](2026-11-06-compiler-attempt-recovery.md) — active
4444

45+
### cross-platform
46+
47+
- [生态方案:跨平台通用基础设施(mcpp + openkal + xim),以一个 C89 工程为验证](2026-11-10-cross-platform-ecosystem-design.md) — active
48+
4549
### design
4650

4751
- [升级的连续性:打包修订不在使用路径上替换载荷、替换失败不拆掉可用状态、home 中的悬空记录自愈、真实的升级 lane](2026-10-17-upgrade-continuity-design.md) — active
@@ -75,6 +79,7 @@ Records that declare one. Everything else is listed by date below.
7579

7680
### ecosystem
7781

82+
- [测试与依赖解析补充方案:mcpp、mcpp test、mtest、mcpp-ide](2026-11-10-test-and-resolution-supplement-design.md) — active
7883
- [生态顶层方案:#885 收尾之后的工作流、原则与依赖](2026-11-08-ecosystem-top-level-design.md) — active
7984
- [#885 收尾补充方案:目标角色、平台事实、系统接口与版本书写](2026-11-08-ecosystem-885-supplement-design.md) — active
8085
- [生态 #885 收尾设计:核心、插件、openkal、语言服务与编辑器的一轮闭合](2026-11-07-ecosystem-885-closeout-design.md) — active
@@ -183,6 +188,8 @@ Records that declare one. Everything else is listed by date below.
183188

184189
### 2026-11
185190

191+
- [测试与依赖解析补充方案:mcpp、mcpp test、mtest、mcpp-ide](2026-11-10-test-and-resolution-supplement-design.md) — active
192+
- [生态方案:跨平台通用基础设施(mcpp + openkal + xim),以一个 C89 工程为验证](2026-11-10-cross-platform-ecosystem-design.md) — active
186193
- [目标与提供者:统一的目标模型(结合 mcpp#911)](2026-11-09-target-model-design.md) — active
187194
- [生态顶层方案:#885 收尾之后的工作流、原则与依赖](2026-11-08-ecosystem-top-level-design.md) — active
188195
- [#885 收尾补充方案:目标角色、平台事实、系统接口与版本书写](2026-11-08-ecosystem-885-supplement-design.md) — active

‎.github/actions/e2e-mtest/action.yml‎

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: e2e-mtest
22
description: >
33
mtest for the e2e suite (design 2026-11-08 W8; tests/e2e/mtest.toml): the
4-
release this action pins, installed by xlings, and the stores main's last
4+
release .github/versions.env pins (.github/actions/mtest), and the stores main's last
55
successful CI run kept for this host, taken into tests/e2e/.mtest so that
66
`--shard` divides the suite by measured time and a run orders its tests
77
longest first. Exports E2E_MTEST for run_all.sh. A run with no store of main
@@ -11,14 +11,6 @@ inputs:
1111
host:
1212
description: the host's name in the stores' artifact names (linux, macos, windows)
1313
required: true
14-
version:
15-
description: the mtest release, an xlings package (xim:mtest), whose sha256 the index states
16-
required: false
17-
default: '0.5.2'
18-
sha256:
19-
description: sha256 of mtest-<version>-openkal-bundle-all.tar.gz, for the release taken when xlings cannot install it
20-
required: false
21-
default: 'be443f8c546b3f4628dcd3f1eb6f45b4d698a7f805232f966349faf8250863c6'
2214
token:
2315
description: a token that reads this repository's actions
2416
required: false
@@ -27,42 +19,10 @@ inputs:
2719
runs:
2820
using: composite
2921
steps:
30-
# THE ENGINE IS AN XLINGS PACKAGE (xim:mtest), installed as the job installs
31-
# mcpp, verified by the index's sha256, and kept in the job's xlings cache:
32-
# by the configured mirror (GLOBAL), then by CN (GitCode first), each with a
33-
# refreshed index; else the release bundle itself (fetch_release.sh: the
34-
# web address, then the API's), checked against the pinned sha256.
35-
- name: mtest
22+
- uses: ./.github/actions/mtest
23+
- name: The engine for run_all.sh
3624
shell: bash
37-
env:
38-
MTEST_VERSION: ${{ inputs.version }}
39-
MTEST_SHA256: ${{ inputs.sha256 }}
40-
GITHUB_TOKEN: ${{ inputs.token }}
41-
run: |
42-
set -euo pipefail
43-
launcher=""
44-
for mirror in GLOBAL CN; do
45-
xlings config --mirror "$mirror" > /dev/null 2>&1 || true
46-
xlings update > /dev/null 2>&1 || true
47-
if xlings install "mtest@$MTEST_VERSION" -y; then launcher=$(command -v mtest); break; fi
48-
done
49-
xlings config --mirror GLOBAL > /dev/null 2>&1 || true
50-
if [ -z "$launcher" ]; then
51-
echo "::warning::xlings could not install mtest $MTEST_VERSION; taking the release itself"
52-
archive="mtest-$MTEST_VERSION-openkal-bundle-all.tar.gz"
53-
temp="$RUNNER_TEMP"; python=python3
54-
if [ "$RUNNER_OS" = Windows ]; then temp=$(cygpath -u "$RUNNER_TEMP"); python=python; fi
55-
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \
56-
"https://github.com/mcpp-community/mtest/releases/download/v$MTEST_VERSION/$archive" "$temp/$archive"
57-
actual=$("$python" -c "import hashlib,sys; print(hashlib.sha256(open(sys.argv[1],'rb').read()).hexdigest())" "$temp/$archive")
58-
[ "$actual" = "$MTEST_SHA256" ] || { echo "::error::$archive: sha256 $actual, the action pins $MTEST_SHA256"; exit 1; }
59-
mkdir -p "$temp/mtest" && tar xzf "$temp/$archive" -C "$temp/mtest"
60-
launcher="$temp/mtest/mtest-$MTEST_VERSION-openkal-bundle-all/bin/mtest"
61-
[ "$RUNNER_OS" = Windows ] && launcher="$launcher.exe"
62-
fi
63-
"$launcher" --version | grep -qF "$MTEST_VERSION" \
64-
|| { echo "::error::the mtest at $launcher is not $MTEST_VERSION: $("$launcher" --version)"; exit 1; }
65-
echo "E2E_MTEST=$launcher" >> "$GITHUB_ENV"
25+
run: echo "E2E_MTEST=$MTEST" >> "$GITHUB_ENV"
6626
# The pull request's change, for the `pr` set: the base's tip and HEAD's
6727
# parents, so that `git diff <base>...HEAD` has its merge base. When they
6828
# cannot be fetched, mtest selects every test and says why.

‎.github/actions/mtest/action.yml‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: mtest
2+
description: >
3+
The mtest engine CI runs and reports with: the release .github/versions.env
4+
pins (MTEST_VERSION), an xlings package (xim:mtest) the index verifies, else
5+
the release bundle checked against MTEST_SHA256. Exports MTEST, the launcher.
6+
7+
runs:
8+
using: composite
9+
steps:
10+
# THE ENGINE IS AN XLINGS PACKAGE (xim:mtest), installed as the job installs
11+
# mcpp, verified by the index's sha256, and kept in the job's xlings cache:
12+
# by the configured mirror (GLOBAL), then by CN (GitCode first), each with a
13+
# refreshed index; else the release bundle itself (fetch_release.sh: the
14+
# web address, then the API's), checked against the pinned sha256.
15+
- name: mtest
16+
shell: bash
17+
env:
18+
GITHUB_TOKEN: ${{ github.token }}
19+
run: |
20+
set -euo pipefail
21+
. .github/versions.env
22+
launcher=""
23+
for mirror in GLOBAL CN; do
24+
xlings config --mirror "$mirror" > /dev/null 2>&1 || true
25+
xlings update > /dev/null 2>&1 || true
26+
# Into the global subos (-g): inside the repository xlings would install it
27+
# for the project, and its shim refuses to run it from another directory.
28+
if xlings install "mtest@$MTEST_VERSION" -y -g; then launcher=$(command -v mtest); break; fi
29+
done
30+
xlings config --mirror GLOBAL > /dev/null 2>&1 || true
31+
if [ -z "$launcher" ]; then
32+
echo "::warning::xlings could not install mtest $MTEST_VERSION; taking the release itself"
33+
archive="mtest-$MTEST_VERSION-openkal-bundle-all.tar.gz"
34+
temp="$RUNNER_TEMP"; python=python3
35+
if [ "$RUNNER_OS" = Windows ]; then temp=$(cygpath -u "$RUNNER_TEMP"); python=python; fi
36+
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \
37+
"https://github.com/mcpp-community/mtest/releases/download/v$MTEST_VERSION/$archive" "$temp/$archive"
38+
actual=$("$python" -c "import hashlib,sys; print(hashlib.sha256(open(sys.argv[1],'rb').read()).hexdigest())" "$temp/$archive")
39+
[ "$actual" = "$MTEST_SHA256" ] || { echo "::error::$archive: sha256 $actual, the action pins $MTEST_SHA256"; exit 1; }
40+
mkdir -p "$temp/mtest" && tar xzf "$temp/$archive" -C "$temp/mtest"
41+
launcher="$temp/mtest/mtest-$MTEST_VERSION-openkal-bundle-all/bin/mtest"
42+
[ "$RUNNER_OS" = Windows ] && launcher="$launcher.exe"
43+
fi
44+
"$launcher" --version | grep -qF "$MTEST_VERSION" \
45+
|| { echo "::error::the mtest at $launcher is not $MTEST_VERSION: $("$launcher" --version)"; exit 1; }
46+
echo "MTEST=$launcher" >> "$GITHUB_ENV"
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: test-report
2+
description: >
3+
The runs `mcpp test` kept in the mtest store's form ([test] store, docs/08;
4+
SPEC-017 §6): taken into one store of the job, written as one Markdown report
5+
of this workflow run's runs into the job's summary, and kept as an artifact
6+
for the report over every job of the workflow run (ci.yml `test-report`).
7+
inputs:
8+
name:
9+
description: the artifact's name, unique in the workflow run (mtest-unit-<host>)
10+
required: true
11+
stores:
12+
description: the stores `mcpp test` kept in this job, relative to the workspace, separated by spaces
13+
required: false
14+
default: target/mtest
15+
runs:
16+
using: composite
17+
steps:
18+
- uses: ./.github/actions/mtest
19+
- shell: bash
20+
env:
21+
STORES: ${{ inputs.stores }}
22+
run: |
23+
set -euo pipefail
24+
job="$(cygpath -u "$RUNNER_TEMP" 2> /dev/null || printf '%s' "$RUNNER_TEMP")/mtest-job"
25+
mkdir -p "$job"
26+
taken=0
27+
for store in $STORES; do
28+
[ -f "$store/index.ndjson" ] || continue
29+
(cd "$job" && "$MTEST" store import --from "$GITHUB_WORKSPACE/$store")
30+
taken=1
31+
done
32+
if [ "$taken" = 0 ]; then echo "mcpp test kept no run here"; exit 0; fi
33+
(cd "$job" && "$MTEST" report --format md --group "$GITHUB_RUN_ID") >> "$GITHUB_STEP_SUMMARY" \
34+
|| echo "::warning::no run of this workflow run in the store"
35+
echo "MTEST_JOB_STORE=$(cygpath -w "$job/.mtest" 2> /dev/null || printf '%s' "$job/.mtest")" >> "$GITHUB_ENV"
36+
- uses: actions/upload-artifact@v4
37+
if: env.MTEST_JOB_STORE != ''
38+
with:
39+
name: ${{ inputs.name }}
40+
path: ${{ env.MTEST_JOB_STORE }}
41+
include-hidden-files: true
42+
if-no-files-found: ignore
43+
retention-days: 7

‎.github/versions.env‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# The engines CI pins, read by the composite actions (.github/actions/mtest).
2+
# mtest: an xlings package (xim:mtest) whose sha256 the index states; the release
3+
# bundle's sha256 checks the fallback download.
4+
MTEST_VERSION=0.5.2
5+
MTEST_SHA256=be443f8c546b3f4628dcd3f1eb6f45b4d698a7f805232f966349faf8250863c6

‎.github/workflows/ci-linux-e2e.yml‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ jobs:
107107
"$MCPP" self config
108108
bash tests/e2e/run_all.sh
109109
110+
# The shard's run as Markdown in the job's summary (mtest report).
111+
- name: The shard's report
112+
if: always()
113+
shell: bash
114+
run: |
115+
[ -n "${E2E_MTEST:-}" ] || exit 0
116+
(cd tests/e2e && "$E2E_MTEST" report --format md --group "$GITHUB_RUN_ID") >> "$GITHUB_STEP_SUMMARY" \
117+
|| echo "::warning::no e2e run of this workflow run in the store"
118+
110119
# The shard's store: main's are the history the next runs divide the suite by.
111120
- name: Upload the shard's store
112121
if: always()

‎.github/workflows/ci-linux.yml‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,21 @@ jobs:
9696
echo "::endgroup::"
9797
done
9898
99+
# The engine's own costs as metrics with a history (bench/tests, mtest
100+
# Bench cases; design 2026-11-10 §16): this commit's mcpp timed on a small
101+
# fixture, kept in bench/target/mtest beside the unit runs.
102+
- name: The engine's costs (bench, mtest Bench)
103+
run: |
104+
cd bench && MCPP="$MCPP_FRESH" "$MCPP_FRESH" test
105+
106+
# The runs `mcpp test` kept: this job's report in its summary, and the
107+
# store for the workflow run's report (ci.yml test-report).
108+
- uses: ./.github/actions/test-report
109+
if: always()
110+
with:
111+
name: mtest-unit-linux
112+
stores: target/mtest bench/target/mtest
113+
99114
# A cold, from-scratch self-host build by this commit's binary with the
100115
# manifest-pinned GCC: mcpp building itself, where build.yml has the
101116
# bootstrap build it. `mcpp test` is deliberately NOT repeated here; it would

‎.github/workflows/ci-macos-e2e.yml‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ jobs:
104104
set -o pipefail
105105
bash tests/e2e/run_all.sh 2>&1 | tee "$RUNNER_TEMP/e2e-suite.log"
106106
107+
# The shard's run as Markdown in the job's summary (mtest report).
108+
- name: The shard's report
109+
if: always()
110+
shell: bash
111+
run: |
112+
[ -n "${E2E_MTEST:-}" ] || exit 0
113+
(cd tests/e2e && "$E2E_MTEST" report --format md --group "$GITHUB_RUN_ID") >> "$GITHUB_STEP_SUMMARY" \
114+
|| echo "::warning::no e2e run of this workflow run in the store"
115+
107116
# The shard's store: main's are the history the next runs divide the suite by.
108117
- name: Upload the shard's store
109118
if: always()

0 commit comments

Comments
 (0)