Skip to content

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

Merged
Sunrisepeak merged 59 commits into
mainfrom
feat/cross-platform-infra
Nov 10, 2026
Merged

Sunrisepeak merged 59 commits into
mainfrom
feat/cross-platform-infra

Conversation

@Sunrisepeak

@Sunrisepeak Sunrisepeak commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Summary

mcpp 2026.11.10.1. The engine changes of the cross-platform design record (.agents/docs/2026-11-10-cross-platform-ecosystem-design.md, fourth version) and of its supplement on tests and dependency resolution (.agents/docs/2026-11-10-test-and-resolution-supplement-design.md, third version); each records its implementation. The engine stays free of system names: every new identity and provider is data.

Item Change e2e
E1 A platform-defined row, and a built-in row no built-in provider serves, is read as a built-in row: march/link-emulation reach the compile and an ld.lld link; nothing the payload built for its own host (libc++ headers, runtime directories, host -L/RPATH) reaches it; host-loader checks apply only to rows that run here (mcpp#911 N2, N3, N4, N7) 1057
E2 Programs that share an entry compile it once per program whose flags differ (N1) 1054
E3 A GNU-ABI Windows row finds its resource compiler in the paired payload or uses llvm-rc 1058
E4 FreeBSD's identities are built-in rows; clang-triple is row data unit
E5 Base packages: a sysroot whose root carries a package manifest is read as any package is (provides, [build] include_dirs/ldflags/std-module*, new compiler_runtime_dir); the package root is the sysroot; a provider's sysroot is its identity's base (SPEC-002 §2.5) 1059
E6 patches on a git workspace member apply in a copy of the whole repository (N5) 1060
E7 A foreign artifact is packed from its DT_NEEDED; --mode static links and checks a static program (N8) 1061
E8 [platform.link] flags on a compiler link are named in a warning (N6) 1062
E9 mingw-llvm provider and aarch64-windows-gnu: Windows GNU-ABI from every host over xim:mingw-w64-sysroot (mcpp#913); the unserved-target remedy names a parseable spelling 1063
E10 A scan_overrides glob whose files exist but are excluded from this build is kept (mcpp#902) 1064
E11 i686-linux-musl, i686-linux-gnu, i686-openkal are planned rows unit
E13 MCPP_KERNEL_ABI_INTERFACES / mcpp::kernel_abi_interfaces() for build programs 1056
E14 Layer suppliers that require one another in a circle are refused (layer-cycle) 1055
mcpp#917 mcpp test states what its programs report as they report it, for any framework that implements the test protocol: parts/part_of (test-parts), case records as cases begin and end (test-case-stream), cases' kind/tags/metrics/bounds and the program's usage in the records and in the kept run (test-metrics, protocol P6, P10.2, P12). New SPEC-017 states the runner. Kept as mcpp's contract: --list's main keeps its meaning (a field never changes meaning); the end record carries a case exactly as cases does (duration_ms); build_started_ms is not written (every test program is built in one build) 1065
mcpp#914 override = true on a dependency entry of the root decides that package for the whole graph; the lock records it and --locked names a drift (override); a library's override is ignored with a warning, a platform group member's is warned; an irreconcilable request names the override spelling; an exact pin of a shared package is noted (dependency/exact-pin) and refused by mcpp publish for a library. A version a merge replaces withdraws its requests (T1) 1066, 1071
mcpp#915 mcpp test releases the build directory's lock before tests run; each invocation's protocol files are its own (test-protocol/<pid>-<started_ns>/) 1068
Test fast path The test graph is test.ninja, sharing .ninja_log/.ninja_deps with build.ninja (one dyndep rule text); the package's programs are built through the build fast path; an unchanged project's tests run from test-plan.json without planning; Compiling lines only for real work 1069
mcpp test spec docs/specs/test.md (SPEC-017 v2.0): base B1–B6, optional O1–O9, protocol P1–P12. A built, unrun program's record carries its launch (B5, test-launch-records); a framework states its capabilities and session in its entry target (test-capabilities, test-session; B6, test-frameworks); a case's checks (O3, test-checks) and output (O8, test-output) 1070
Registry A home that borrows another's registry ([xlings] home) leaves the registry's index places as their owner recorded them 1067
Platform openkal-platform 0.25.0; the ok-image launcher depends on mcpplibs.os 0.4.4 (the openkal 0.24 and 0.25 families); a toolchain's C++ archives built for another target are not linked (degraded diagnostic) 1025, unit

Fixes from this PR's first CI run (42704688606): a provider's default base yields to a dependency graph that supplies the system (a carrier for windows-aarch64 had been linked over the MinGW base beneath openkal-windows); a carrier that names no hosts is built only where the platform's runner exists (runner.hosts), so --systems all leaves windows-aarch64 out with the reason. The other failures of that run were index fetches (install path missing after fetch from a mirror) and a temporary-directory race, unrelated to the change.

Specs: SPEC-002 v1.6, SPEC-006 v0.11, SPEC-013 v1.7, SPEC-014 v2.2, SPEC-016 v1.1, SPEC-017 v2.0 (new: the mcpp test spec). Usage docs 04, 05, 08, 10, 21, 22, 25, 30, 35, 50 and the READMEs, in English and Chinese. CHANGELOG, version 2026.11.10.1; CI bootstraps from 2026.11.9.1. New AGENTS.md: the repository's rules in their shortest form, linked to the documents that state them.

The base packages this release names are in xim-pkgindex (openxlings/xim-pkgindex#1132, #1133): mingw-w64-sysroot@20261104-1, x86_64-freebsd-sysroot@14.5, aarch64-freebsd-sysroot@14.5.

Refs mcpp#911, mcpp#913, mcpp#902, mcpp#917, mcpp#914, mcpp#915.

Test plan

  • Local (Linux x86_64): mcpp test 166/166; e2e 1054–1065 pass, 1063 against the published base; the windows-gnu, pack and target-side regression sets pass (669 fails identically on 2026.11.9.1: an environment limit of this host).
  • FreeBSD 14.5 VM: import std + exceptions, dynamic and static, on the per-identity base packages; wine: import std on x86_64-windows-gnu over the MinGW base.
  • CI on the existing suites: run 42763700279 (6350768), and run 42771952446 after the last functional commit (a02607a).
  • Then the e2e/bench migration onto mtest and the CI use of mtest's store, shards and reports (design §16), green again: run 42784172603 (5b1d024). mtest is installed into the global subos, so the report step runs it outside the repository.
  • The cross-platform validation (Linux gnu and musl, aarch64 musl under qemu, Windows GNU under wine, FreeBSD over its base packages in the VM, the ok image under okrun, packing) found two resource defects, fixed here with e2e: a cross gcc's "winres.h" taken for a project file (1058), and an include nothing provides failing in ninja (1072).

… interfaces for build programs; layer suppliers may not require one another in a circle
…g of the payload's host side reaches a row whose C library a platform describes
…ayload or uses llvm-rc; a quoted toolchain header is the toolchain's
…; the rows' systems are words of the language; a platform-served row names the platform as its remedy
…olds beside its C library; its headers, libraries and std module stand where the payload's would
…repository, so its edges to sibling members hold
…tatic 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.
…; 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.
…lvm 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).
…ilds 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.
…686-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.
…C-013 v1.7, SPEC-014 v2.2, SPEC-016 v1.1; MCPP_KERNEL_ABI_INTERFACES and layer-cycle in docs/30 and docs/50
…1), foreign ELF closure and the static check (docs/10), defined rows, served FreeBSD rows and link.flags (docs/35); en and zh
…he documents that state them; design record 2026-11-10 (cross-platform ecosystem, fourth version)
…ers, [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.
…t, the rows snapshot; freebsd is a platform name
…ames 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.
…ase 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.
@Sunrisepeak Sunrisepeak changed the title 2026.11.10.1: base packages, Windows GNU-ABI from every host, FreeBSD rows, foreign packing, mcpp#911 N1–N8, #913, #902 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 Nov 9, 2026
…n function

step13_windows_resources stays within the 400-line function limit.
…oot 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.
…es 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.
…s; 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.
…ot 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.
-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.
…oked 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 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.
The test named openkal-linux; on Windows and macOS the pinned os brings the 0.24 family's implementation of that system instead.
…he 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).
…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.
…form 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.
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.
…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.
…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.
…nd 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).
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.
An entry target that states them is not warned of an unsupported key.
…inked

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).
…ild, 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.
.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).
…ude 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant