Repository navigation
Releases
v2026.11.12.1
Added
aarch64-linux-gnuhas a cross arrangement: the providerglibc-sysroot
serves it on linux-x86_64 from the base package
xim:aarch64-linux-gnu-sysroot(glibc, the kernel headers, libc++ with its
std module, compiler-rt), with llvm. A C program, a C++ program and one that
imports std build for it, dynamically and statically. The entry stands at
priority 40, below the musl entries, so the requestaarch64-linuxis
answered as before on every host and the whole identity reaches the new
entry; the native arrangement on an aarch64 host is unchanged.- A provider states how its artifacts are started:
runner = { cmd, hosts, requires }on a provider entry is the lowest tier of the runner statement,
under the platform's, a build program's, the machine's and the project's.
{}is the artifact,{sysroot}the arrangement's base,{pkg:<name>}the
root of the required package of that name; the packages ofrequiresare
installed on the firstmcpp runormcpp test, never by a build.
mcpp run --target aarch64-linux-gnuon linux-x86_64 runs the artifact
underqemu-aarch64-static -L {sysroot}with nothing declared. - The system table:
[[platform.system]] name, unamestates the facts of a
system that no single row carries, in the built-in data and in a platform
package alike. A file that carries one program per system selects by
uname; FreeBSD joins it through the table. - Provider keys
tier(the tier of one arrangement, where it differs from its
row's) andsystem-headers(the package whose headers state the system's
own interfaces). Row keysloaderandexecutionare read on built-in rows
as on rows a platform defines. - A platform's runner states
built-as = { "<os>-<arch>" = "<identity>" }:
the identity its runner program for that host pair is built as. A package
that carries its runner builds it so for a system the engine holds no
convention for;mcpp pack --systems alltakes every system of the table
and writes the pairs no program is built for as not covered. longjmpjoinsthreadsandexceptionsas a member of
[target.<selector>.abi]: howsigsetjmpandsiglongjmpcross the
WebAssembly boundary on an Emscripten row."wasm"renders
-sSUPPORT_LONGJMP=wasmon every C and C++ translation unit and on the
link;"js"states the JavaScript model the same way. Unstated, the model
followsexceptions, as the SDK's default does. A build that states one
model forexceptionsand the other forlongjmpis refused with both
statements, and the member is refused on a row that is not Emscripten's.- A Windows row whose system the graph supplies compiles its resources: its
provider names the package of the system's headers (system-headers), read
where the toolchain states no header source. A row that states its own (the
MSVC SDK, a paired payload) resolves nothing and installs nothing. .github/tools/check_system_names.pyholds the number of times the engine's
sources name a system. The count is compared with a baseline that only
falls.tests/unit/test_link_line_golden.cppstates the C-library group of the
link line for each combination of compiler family, C library supplier and
machine.
Changed
- An artifact of another system is not started when nothing states how it
runs.mcpp runandmcpp testanswer "built, not run" before any process
is spawned, for built-in rows as for rows a platform defines, and name the
[target.<triple>]runner declaration; the exit status is 2. The kernel of
this machine gives another system's call numbers its own meaning, so a
launch was not an observation.--no-runnerstates that the triple is
native here and is believed. An artifact of this system and another
architecture is launched as before. A host that runs another system's
programs through a registered interpreter passes--no-runneror declares
the runner. - A dynamic artifact that this machine does not load names the row's
loader
as its program interpreter and carries no RUNPATH of this machine. A native
dynamic artifact names the base's own loader, as before. - A base package has one reading: a sysroot whose root carries a manifest is
rendered as a sysroot whatever its directories are called. The layout is
probed only for a directory without a manifest. - Whether this host serves a target from a payload is answered by the
providers'hosts, the data the selection reads; the per-system conditions
ofhost_can_serveare removed. - The messages that print a runner declaration print its shape and no
program. - Android's rows state
execution = "android": the kernel is Linux and the
system is not. - The openkal targets' platform is openkal-platform 0.27.1 (from 0.26.0):
0.27.0 states the runner'sbuilt-asfor FreeBSD, and 0.27.1 is a patch of
the version group. Its implementations retire a handle before closing it
(openkal-linux 0.26.1, openkal-macos 0.23.1, openkal-windows 0.21.1): a
file one thread opened while another closed a socket was left with a stale
handle, and above the C library its reads and writes reached descriptor 0
(mcpplibs/openkal-linux#53). openkal-musl 0.29.4 returns what has arrived
from arecvthat follows apoll, asreaddoes, where it returned one
byte (mcpplibs/openkal-musl#52).
Fixed
- A base package's compiler run-time directory reaches the C link as well as
the C++ one. - The loader name of a row is read from the row; the per-architecture table
in the link model is removed. - A C unit of an MSVC-ABI build with clang receives the C library model
and its standard (SPEC toolchain-management §3.7). The model's word and
the standard's were written as one,-fms-runtime-lib=dll-std=c11, on the
C line only: clang read neither and said nothing, so every C unit named the
static C library (/DEFAULTLIB:libcmt.lib) in a build whose C++ units named
the DLL's, and was compiled at the compiler's default C standard. The cache
key of a dependency's objects states the C line's form, so objects built
with the joined word are not taken again. mcpp pack --compress xzno longer faults on Windows. mcpp names
mcpplibs.mwrap.xz 5.8.3.1, whose module readslzma.has the static library
it links (LZMA_API_STATIC). With 5.8.3 the calls went through
__imp_lzma_*slots the linker made, the release link collected the
functions behind them, and the first call into liblzma was an access
violation at the image's first byte. Dependency objects kept in the global
cache since before they were compiled a function to a section kept it from
view until the toolchain's packaging revision changed.mcpp why platformin a project that selects a platform lists the rows the
platform defines and the identities it serves again (the statement kept only
its merged fields in this version's first form).- An e2e part whose only script does not apply on the machine is a run that
reported a case, not an empty run. - Six e2e scripts run on a runner again. A script that does not apply on a
machine leaves with 77 and is reported as a skip; it left with 0 and was
reported as a pass, and the coverage check of the first full run named six
scripts no runner had run. The probes of 13, 28 and 31 named a payload
release or a store the runners no longer have, and read the release from
the home now (_toolchain_env.sh), as does Mode A of 30, which was left out
for the same reason. 650, 653 and 657 need the emsdk payload and run in the
job that installs it, beside 981 and 1079.
v2026.11.10.2
Added
- FreeBSD's musl identity is served:
x86_64-freebsd-musland
aarch64-freebsd-muslare preview rows of the openkal provider, through
openkal-platform 0.26.0's hosted part — openkal-musl 0.29.2 over
openkal-freebsd 0.1.0 in its standalone arrangement, with
openkal-llvm-runtime 0.20.1 above it, as one static program with no C library
of the system beneath. A request of<arch>-freebsdwith no platform selected
for it takes this identity, asaarch64-macostakes the musl identity on a
host that is not a Mac; a project that selects a platform for<arch>-freebsd
keeps the system's own ABI, by whichever selector chose it ([target.<row>],
[target.freebsd]orcfg(os = "freebsd")): a platform package chosen for a
request that no built-in provider names serves it, and another package's
provider does not compete with it. - A cfg bareword names any system a row names:
unixis the family word, and
any other word without a dash isos = "<word>", so[target.freebsd],
cfg(freebsd)and the system of a row a platform defines select aslinux
does. A row states its family (family,unixorwindows), and FreeBSD's
rows are of theunixfamily, socfg(unix)holds on them. A word that
names no row's system is reported as before.
Changed
- The openkal targets' platform is openkal-platform 0.26.0 (from 0.25.0): its
version group is openkal-image 0.6.1, whose runner binds only the interfaces
its implementation provides and is built for FreeBSD as well, openkal-musl
0.29.2, openkal-llvm-runtime 0.20.1 and openkal-freebsd 0.1.0.
Fixed
- The MSVC payload's C library is
ucrt, as the MinGW-w64 payload's is: the
triple's env segment names the toolset on Windows,msvcandgnualike.
It was answered asmsvc, sorequires = ["mcpp:c-abi=ucrt"](a Win32
backend's statement of its C runtime) refused the MSVC route while the GNU
routes satisfied it. SPEC-002 v1.7 states the names. - A dependency namespace holding a package named
version,path,gitor
workspaceis read as the namespace (#918):gpp.version = { path = "…" }
declares the packagegpp.version. A table was taken as one dependency
specification when it held any of those keys, whatever their values, and was
refused for naming no source; a specification'spath,versionandgit
are strings and itsworkspacea boolean, and only such a value decides it. - A platform refused for a row it does not serve names the rows its providers
serve; the list named only itstargetsand was empty for a platform that
states[[platform.provider]]. - A test of an unchanged project that this host cannot execute is reported for
the host's target:mcpp testwithout planning (2026.11.10.1) named an empty
target in the refusal and in the[target.…].runnerit proposes. - A compiler record that Windows refuses to a reader for longer than the
publication bound is asked for again at the witness's next audit, as an
unknown controller already was; the refusal ends the build only when it
outlasts the startup grace. It ended a Windows build with "a compiler
controller ended before completion" after a large package installation. The
target-matrix scan reports the supervision's ownmcpp:lines with a failed
cell.
v2026.11.10.1
Added
override = trueon a root's dependency, or in[workspace.dependencies],
answers every request for the package in the graph its table governs; each
replaced request is named once (Overrode),mcpp.lockrecords the
override and--lockedreads it, and an override of a platform version
group's member is taken with a warning. A library'soverrideis ignored
and said to be (mcpp#914).- A refusal of two irreconcilable versions ends with the line that overrides
the package; a library that pins one release of a package every consumer
shares (a target-side layer, a kernel ABI) is noted to its users, and
mcpp publishrefuses the pin in a library (mcpp#914). - The mcpp test spec (SPEC-017 v2.0,
docs/specs/test.md) is the one
contract between clients, mcpp and test frameworks: it merges SPEC-017 v1,
the normative text of the mtest test protocol (clauses P1–P12 kept) and the
[test]keys, and divides them into base capabilities (B1–B6) that every
runner and framework implements and optional ones (O1–O9) a framework or its
tools declare. mcpp test --no-run --message-format jsonrecords how each program starts,
launch(argv,env,cwd,via), for a launcher that runs the built
programs itself (B5; featuretest-launch-records).- A framework's entry states
test-capabilitiesandtest-session, and
mcpp test --guidereports them (B6; featuretest-frameworks). - A failure's
sourceandfataland a case'schecks(held,failed)
reach the records and the kept run as the program reported them (O3;
featuretest-checks), and a case has its ownoutput: the program's
outputevents, or all that a program which ran one case wrote (O8; feature
test-output). - Base packages (SPEC-002 §2.5). A sysroot whose root carries a package
manifest is read as any package is: itsprovidesanswers its layers and
its[build]keys state them --include_dirsthe C++ library's headers,
ldflagsits libraries,std-module,std-compat-moduleand
std-module-flagsits std module, and the newcompiler_runtime_dirthe
directory of its compiler runtime (-resource-dirfor clang,-Bfor gcc)
-- with paths relative to the package root, which is the sysroot. The build
takes those layers from the base, reports them asprebuiltwith the base's
name and version, and keeps the toolchain payload's C++ runtime out. A
provider'ssysroot(a package, or{ path }in a platform) is its
identity's base, ahead of the platform's own, so a platform gives each
identity its own base. The index carriesxim:x86_64-freebsd-sysroot@14.5,
xim:aarch64-freebsd-sysroot@14.5andxim:mingw-w64-sysroot@20261104-2. - Windows GNU-ABI rows from every host (mcpp#913). The
mingw-llvm
provider servesx86_64-windows-gnuand the newaarch64-windows-gnuwith
clang andxim:mingw-w64-sysroot(llvm-mingw's target side: MinGW-w64 on
UCRT, libc++, libunwind, compiler-rt), below the gcc payload where that
exists;import stdincluded, static by default. A provider's sysroot
package is the base statement of last resort; a MinGW row takes a base
package by name or path. - FreeBSD's identities are built-in rows:
x86_64-freebsdand
aarch64-freebsd(the system's own ABI, served by a platform that names a
base) and their-muslcounterparts (planned). A row'sclang-tripleis
data; built-in rows' systems are words of the language. - The 32-bit hosted identities
i686-linux-musl,i686-linux-gnuand
i686-openkalare planned rows: refused as planned, not as unknown. - Build programs of a package that requires
mcpp:kernel-abiread the
resolved provider'sprovides-interfaces(mcpp::kernel_abi_interfaces(),
MCPP_KERNEL_ABI_INTERFACES,;-joined; empty is unknown). mcpp teststates what its programs report as they report it (mcpp#917):
acaserecord as each case begins and ends, before the program's record
(featuretest-case-stream); the parts a program runs as, under--cases
(parts) and in each part's record (part_of, featuretest-parts); the
cases'kind,tags,metricsandboundsand the program'susage, in
the records and in the run kept undertarget/mtestwith the case's start
and its failures' expected and actual values (featuretest-metrics; mtest
spec P6, P10.2, P12). ABenchcase's measurements reachmtest analyze trend.- The suppliers of the layers may not require one another in a circle; the
build is refused before compiling, naming each package, the layer it
supplies and the one it requires (layer-cycle, SPEC-002 §3.8).
Changed
mcpp testwrites its graph totest.ninjabesidebuild.ninja; the two
share the directory's objects,.ninja_logand.ninja_deps. A test no
longer rewrites the build's graph, somcpp buildaftermcpp testtakes
its fast path, and a dependency scan both graphs name has one command in
both ($module_mapbegins with its own separator), so alternating the two
commands rescans nothing.- The tests of an unchanged project run without planning: a full
mcpp test
records what it planned for every test (test-plan.json, and a build-cache
entry fortest.ninja), and a later run that the build fast path's checks,
the package's discovered tests and a dry run of ninja admit runs the
selected tests from it. Measured on a workspace of 1,500 sources: one
program's tests, unchanged, from 5.8 s to 0.13 s. - The programs
mcpp testbuilds for its tests (MCPP_BIN_<NAME>) are built
bymcpp build's fast path when nothing changed; a run of an unchanged
project neither resolves nor scans to learn that they are current. - A package's and a test's
Compilingline states work done: it is written
when one of its steps runs, and a run with nothing to compile writes none. - The built-in platform of
x86_64-openkalandaarch64-openkalis
openkal-platform 0.25.0 (openkal 0.25, openkal-image 0.5.5, openkal-musl
0.29.0); it was 0.24.4. - Programs that share an entry source keep their own flags: the entry is
compiled once per program whose[targets.<name>]or
[targets.<name>.build]flags differ (obj/_entry/<name>/; mcpp#911 N1). - A row a platform defines, and a built-in row no built-in provider serves, is
read as a built-in row: itsmarchandlink-emulationreach the compile
and an ld.lld link; nothing the toolchain payload built for its own host
(libc++ headers, runtime directories, the host's-Land RPATH) reaches it;
the host loader's closure and symbol checks apply only to rows that run on
this machine (mcpp#911 N2, N3, N4, N7). - An artifact for another system is packed from the closure its file names
(DT_NEEDED): a library this build produced travels, other names are the
target system's;--mode staticlinks a static program on such a row and
refuses to pack a dynamic one under the-staticname (mcpp#911 N8). - The unserved-target diagnosis names a spelling the parser accepts:
[toolchain] <host> = { path, prefix }(mcpp#913). mcpp teststates, under its result line, the cases of the run
(cases: N passed, N failed, N skipped (in N programs), counting no case
that only declares others) and afailures:index that names each failed
program with its failed cases and their places. The failure blocks are the
framework's and are no longer repeated after the summary.- The C environment of FreeBSD and NetBSD rows is POSIX's: a default
architecture there adds no flag, as on Linux.
Fixed
- The toolchain's C++ archives built for another target are not linked: on a
row of another architecture or system (aarch64-freebsd-muslfrom a Linux
host) the payload's ownlibc++.awas put on the link and failed as
incompatible, or, of one architecture, linked another system's C++ runtime
by chance. The link states that the row's C++ runtime is a package's
(mcpp:c++-abi, openkal-llvm-runtime above openkal-musl). mcpp testreleases the build directory once its tests are built: a
mcpp build, or a secondmcpp testof the same configuration, no longer
waits for a running test, and each invocation keeps its protocol files in a
directory of its own (test-protocol/<pid>-<start>/), removed when it ends
(mcpp#915).- A version that a merge replaces takes its requests out of the graph: they
no longer constrain what remains. A graph where a pinned library brought a
package down to an older release was refused as "irreconcilable versions"
between that release's family and a request of the newer one (mcpp#914). - A home that names an existing registry (
[xlings] home) leaves the places
of the registry's indices as the home that made it recorded them. Each home
over a shared registry wrote its own index directory and store there, and a
later build was sent to the store of a home that no longer existed
("install path missing after fetch"). The message of that error now names
each place it looked in and the configuration that declared the stores. - A GNU-ABI Windows row finds its resource compiler in the paired payload or
usesllvm-rc, and a quoted"winres.h"is the toolchain's header, not a
generated input: the paired payload's, or a cross gcc's own
(<root>/x86_64-w64-mingw32/include). - A resource script's quoted include that no directory holds and no build
action writes is no longer an input of the build graph. Such a build failed
in ninja without the script's name, even when the script included the file
only#if __has_include; the resource compiler now reports a missing one
with the script's name and line. patcheson a git dependency that is a workspace member is applied in a
copy of the whole repository, so the member's edges to its siblings hold
(mcpp#911 N5).[platform.link] flagson a platform that links through the compiler are
named in a warning instead of be...
v2026.11.9.1
Added
- Targets and providers (SPEC-016). A target request is a pattern: the
rows it reaches, each with the providers that serve it, are ordered by
priority, then by row, then by provider name, and the first one available on
this host is taken; the build reports the request, the identity and, when the
first candidate is not available, why. The built-in rows and providers are
data (modules/toolchain-model/data/builtin.toml, compiled in by the
package's build program).[target.<selector>.priority] <provider> = <n>
changes the order;platform = "builtin:<name>"chooses a built-in provider. - A platform package defines rows and providers:
[[platform.define]](triple,
clang-triple, object format, family, execution, ...) and
[[platform.provider]](serves, priority, hosts, pairs, toolchain, layers,
link, hosted).cfg(os = ...)answers by a defined row; the parser accepts
the systems and C libraries the resolved platforms define (mcpp#911 G1). mcpp why targetlists a request's candidates with their priorities and
availability;mcpp why flags [<unit>]lists each word of a unit's command
line and of the link line with the layer that gave it (row, platform,
toolchain, package, engine; mcpp#911 G2). A row's defaults are not replaced
in place: a platform whose machine differs defines its own row (G1). Both take--format json. The build
record and theplanevent carry{request, identity, provider, priority, fallback}; build programs readmcpp::target_provider()
(MCPP_TARGET_PROVIDER).mcpp.lockrecords[target."<request>"]with the identity and the
provider;--lockedrefuses a build that selects another identity.- A sysroot or a provider that states a hosted C environment turns off
-ffreestanding(G3); a platform'slink.driver = "compiler"links any row
(G4); an artifact for another system is not judged by this machine's loader
(G5); a target-independent source artifact serves every target (G6). [defaults."<capability>"] <selector> = <package>: a package's default
provider of a capability it requires, taken when neither the graph nor the
platform provides it (G7).- A patch names files from the package's root;
patch_rootnames another
directory, and a patch written from the archive's top applies as before.
mcpp why depsreports each dependency's root, from whichgit diffwrites
a patch (G8). [targets.<name>.build]compiles the shared sources an artifact links with
its own defines and flags, as the artifact's variant (G9).- A row a platform defines is packed and carries as a built-in row does;
--systems alladds the systems the platforms define (G10). An artifact for
another system is built, not run, until a runner -- a runner package's tool
-- or an execution host states how it runs (G11). - The row
i686-none-elf(G12). - A test program that speaks the test protocol runs as one process per file of
its cases ([test] split = "file" | "case" | "none"), and a test keeps what
it reaches: units are compiled with one section per function and per object
and tests link with--gc-sections([test] link = "objects"keeps every
object whole); a protocol marker nothing references is read from the objects
the test was linked from. A run is kept in the mtest store's form under
target/mtest([test] store), whichmtest store importtakes in for
mtest report,analyzeandgraph. The tests of an archive run by the
same runner (mcpp test --archive): their protocol, recorded in
mcpp-tests.json, a process per file of their cases, the workers and the
store. A pattern names a part as the run names it (mcpp test unit/test_home).
mcpp's own unit tests are one program per directory: 166
programs of 32 MB became one of 37 MB, run as 166 processes. - clang pairs with the MinGW-w64 payload for
x86_64-windows-gnu: the payload
is clang's sysroot and libstdc++ its C++ library,import stdincluded. mcpp new --template platform. Reading a platform's manifest refuses a
definition of a built-in row and a row defined twice, and warns of a provider
that serves no row and of two providers at one priority for one identity;
mcpp why platformlists the rows a platform defines and the identities it
serves, with their providers and priorities.mcpp pack --all-programsships every program of a package.- The package being built stands for itself in its own graph: a test framework
that uses the package under test (mtest and mcpplibs.os) is built against it,
and the root's[dev-dependencies]close no cycle of packages. - A git reference that names no tag, rev or branch follows the remote's
default branch;--platform git+<url>[#tag=|rev=|branch=].
Changed
- A request that names only a system takes the first available identity of
that system:x86_64-windowson a host without MSVC is
x86_64-windows-musl(openkal-platform), no longerx86_64-windows-gnu;
aarch64-macosandx86_64-macoson another host are the-musl
identities;aarch64-linuxon an x86_64 host isaarch64-linux-musl. An
identity written whole is not replaced. - The identity follows the C library: a project whose graph supplies musl
buildsx86_64-linuxasx86_64-linux-musl; an explicit identity is the
project's spelling and is kept, and a disagreement with the graph's C library
is reported. - A git dependency names at most one of rev, tag and branch.
mcpp packwith several programs packs the one named after the package,
else the first by name as before, and names the others with
mcpp pack <program>and--all-programs.- mcpp's own unit tests are mtest cases (mtest 0.5.2, mcpplibs.os 0.4.1); a
skeleton's tests use mtest 0.5.2.
Fixed
- A manifest
mcpp packgenerates quotes a target name with a dot (B1). - A platform's artifact names stand over a build program's
artifact-name;
the conflict is reported (B2). mcpp packno longer packs one program of several without a word (B3).- A static ELF is not run to learn its closure.
- A build program under a cross
--targetwhose[target.<t>] toolchain
names the target's compiler is compiled by the spec that section replaced,
as under a row's pin: mcpp's own tree, built on Windows for
x86_64-linux-musl, compiled its build program with the musl cross gcc. - A test name that is another's directory (
unitandunit/own) is refused,
naming both; the two programs were a file and a directory of one path. - The repository's stray empty
.editedis removed; e2e 859 fails naming the
missing record rather than writing one in the working directory. - CI: a pull request's e2e shards report the scripts the
prset leaves out as
unaffected, and the check that every script runs somewhere accepts them
for that run; with main's coverage map in place, it had read them as
uncovered. A shard the set gives no script is not a failure of mtest. - A C library of the graph (
mcpp:c-abi, openkal-musl) leads a Mach-O image's
link. The loader runs initialisers in link order before the entry, and the
program's objects came first: a global constructor that allocated (an mtest
case's registration) stopped in openkal-musl's allocator before the library
was up, on hosted macOS (e2e 1053). x86_64-windows-gnuwith llvm on a host the MinGW-w64 payload does not
serve (linux-aarch64, macOS) is refused ashost-cannot-serve, as with gcc;
the paired payload's failed install was an unnamed refusal.- The target matrix's expected table states the cells the target model
changes, measured on the four hosts; e2e 1044 runs in the job that has wine. - e2e 298 picks a row whose compiler on this host is its convention's: a macOS
host servesaarch64-linux-muslthrough openkal-platform, whose compiler is
llvm, and there llvm alone overrides nothing.
v2026.11.8.1
Added
mcpp testruns the runner's side of the mtest test protocol, version 1
(docs/08 "Cases"). A test program whose entry statestest-protocol = 1, or
whose file carries the markermtest-protocol=1, is told the protocol's
variables and reports its cases: the record names the protocol and each
case's result and failures, a case a crash left open failed, and a failing
program's report names its failed cases with their places.--case PATTERN
runs the matching cases -- a name below a listed case selects the case that
case declares, which is reported when it runs (P3.4), and a pattern below it
runs the listed case whole --,--caseslists them,--seed Nstates the seed. A
program that implements no protocol is one case and receives none of the
variables.--no-runrecords each built test with its program and the files
it is compiled from;--print-launchstates the protocol; the feature
test-protocolnames all of it (e2e 1035).mcpp newscaffolds tests with mtest 0.4.0: the skeleton's test is a file of
mtest's cases with nomain(UTest smoke{"...", [] { ... }}: an object is a
case, its type its kind), with the dev-dependencymcpplibs.mtest, and
--template libscaffolds a library -- a module, a partition it exports and
the partition's implementation, named after the package -- with its test
(docs/01; e2e 1037).- An entry with
test-main = truebegins a test file that defines nomain.
The file's imports choose among offers, so in one package a file of mtest's
cases and a file of GoogleTest's begin each at its own; a dev-dependency's
source that definesmain(gtest_main.cc) begins a test as before, and two
beginnings left for one test are refused, naming them; a framework that is
a dependency as well as a dev-dependency offers its beginning once
(docs/08; e2e 1037). mcpp test --guidenames the package's test frameworks, each with the guide
its entry states (test-guide) and its repository, and the commands that
list, select and explain cases; a failed run points to it and a record
carriesguide(the protocol's P2.5; docs/08 "Writing a test"; e2e 1037).[test] programs = "directory": the files of one directory below a discover
glob's fixed directory are one test program, named by the directory, so a
suite of many files is linked once (docs/08; e2e 1038).mcpp test --since <commit>and--changed <path>build and run the tests a
change affects, read from the plan: a test built from a changed file (its own
files, the modules it imports transitively, its units of no module), a test
whose files name a changed file; a manifest, lock, build program or header
affects every test (docs/08; e2e 1038).mcpp::contextstates the engine's values to the build-program interface in
one process: every accessor reads the innermost context's values, then the
environment, so a test of a build program's or a plugin's logic needs no
change of its environment (docs/30; e2e 1036).[build] target_budgetkeepstarget/within a size: after a build or a test
run, the directories no configuration records as current are removed whatever
their age, and a build whose directories in use exceed it names the three
largest (#874; e2e 1031).
Changed
- The built-in platform of the two ok-image targets is openkal-platform 0.24.4,
whose okrun enters an image in its convention's floating-point state (openkal
SPEC 12.2): on Windows a thread began with the x87 at double precision, under
which an image's C library read a decimal number otherwise. - Both openkal rows are
verified: mcpp's CI builds an ok image over every layer
of the platform and runs it on Linux, macOS and Windows (e2e 1033, required on
each host bytests/e2e/host-requirements.tsv). docs/24 states the two roles,
an image as a release form and a native row as a build target. - A dev-dependency reaches the test units and nothing else of its package: its
include directories and definitions are given to the files undertests/,
and a kernel interface only a dev-dependency reaches is given to the
dev-dependencies and the test units. The package's own sources compile under
mcpp testwith the commandsmcpp buildgives them, somcpp buildand
mcpp testshare one build directory and one compile database and switching
between them compiles nothing again (docs/08; e2e 77, 783, 1037 K). Before,
a dev-dependency over mcpplibs.os (mtest's) gave the package's sources
__OPENKAL__and made the test a configuration of its own. - A program that carries the protocol's marker and writes no
programevent
-- a file of plainmainlinked beside mtest's library -- is one case, judged
by its exit status, when run and when listed (e2e 1038). - A failed test whose file imports a module no package of the build provides
names the module and the dev-dependency a framework is. - A product an earlier build left where this one places a program's directory,
or a directory where it places a program, is removed before the build. trim_pathsapplies to whatmcpp testcompiles as it does to whatmcpp buildcompiles, but for a test program's own files, which keep their paths:
under a shipping profile (release, mcpp's own default) build and test are
one configuration, where a test compiled the whole graph again in a
configuration of its own (637 of mcpp's objects; docs/04; e2e 1038 E).mcpp dyndepleaves an unchanged output untouched, so a unit whose module
edges are what they were is not compiled again when the rule's command
changed (#874).- The low-space warning's threshold is the larger of 2 GiB and 1.25 times what
the configuration's last build wrote (#874; e2e 1030). - mcpp's own dependencies are named by identity in one table, each by one
spelling of an exact release (#904), and so are those of the launchersmcpp packgenerates; mcpp, its modules and the launchers name mcpplibs.os 0.4.0.
Deprecated
- A quoted dotted dependency key (
"mcpplibs.cmdline" = "0.0.2") is the reading
quoted-dotted-dependency-key, reported with the unquoted key that replaces
it; removed in 2027.2. A quoted key that is the only spelling of a package
beside its parent or a child of its namespace in one table (mcpplibs.mtest
and"mcpplibs.mtest.gtest") is not deprecated (#904; e2e 1032).
Fixed
- Two builds that find a std module missing compile it once. The std module of a
toolchain and flag set is one entry of the home's build cache, and two
processes that found it missing compiled into the same files at once: one
compiler read a BMI the other was rewriting (a bus error) or found its
output gone, and a build went on with no std object. The entry is built
under its own lock; a second build waits, naming the first, and finds it
built (e2e 1039). - A dependency's source whose
mainis compiled only under a switch no command
defines -- zlib'scrc32.c(#ifdef MAKECRCH), QuickJS'slibregexp.c
(#ifdef TEST) -- is linked into a test that has its ownmain. Which
sources begin a program is read from the branches the preprocessor may
compile: a name the compiler or platform predefines is unknown, any other is
undefined; 2026.11.7.2 left such a source out, and the test's link failed
with undefined references (measured in Sunrisepeak/mui, #874; e2e 1037 L). - The warning on a quoted dotted dependency key names the key to write,
xrender.graph = ..., not an example (e2e 1032). - A configuration group's lock keeps the entries of the other groups (#903;
e2e 1027). - A project's state directory
.mcpp/ignores itself in a repository (e2e 1028). mcpp cache prune --older-thanandcache gc --older-thancollect a std
module unused for that long (#874; e2e 1029).- A test that has a beginning -- its own
main,[test] mainor an offered
entry -- links no dependency's source that definesmain, a direct
dev-dependency's or one beneath it:gtest_main.ccof compat.gtest beneath
the GoogleTest adapter was linked beside the adapter'smain(e2e 1037). - A test links its package's dev-dependency that is a shared library by the
library, as a dependency is; mtest's C ABI was left unresolved (e2e 1037). - A dependency's entry that imports
stdbuilds the std module for the
program that begins at it, though nothing else of the graph imports it; the
entry failed with "failed to read compiled module" (e2e 1037). - Under
--workspace, a member's test finds the member's programs as
MCPP_BIN_<NAME>, as under-p(e2e 1034).
v2026.11.7.2
Changed
-
mcpp run --print-launchtakes the fast path when nothing changed, asmcpp rundoes: 0.01 s in place of 0.1 to 0.3 s for each launch an editor asks for.
The full path records the launch it composes in the configuration's directory;
the fast path prints that record, with the request's program arguments, only
when the launch it composes itself is the recorded one, so a launch through a
runner, an execution host or carried files is still described by the full
path (e2e 1024). -
The built-in platform of the two ok-image targets is one release,
openkal-platform 0.24.3, the one this mcpp was qualified with (2026.11.7.1
selected the series^0.24): a project that states no platform builds the
same versions at any time, with or withoutmcpp.lock. A lock that records
another release does not decide, and the build says which it recorded. A
newer platform needs no new mcpp: a project selects it in its manifest, and a
build that fails over the default while the synced index holds a newer
release ends with atip:naming it and the line to write (e2e 1025;
SPEC-013 1.5). -
mcpp, its modules and the launchers
mcpp packgenerates name mcpplibs.os
=0.3.1, so a pack is the same at any later time.
Added
mcpp run --print-launch --message-format jsonstreams the build's events
(plan,waiting,progress,artifact) before themcpp.launchenvelope,
which is the last line; featurelaunch-stream. An editor shows the build of
a Run as it goes (e2e 1024).
Fixed
mcpp test -p <member> --no-run --archivecarries the files a workspace
member deploys from the member's product directory, where the build placed
them; 2026.11.7.1 named them where a plan of one package places them and
refused the archive: "cannot copy … into the test archive". A member's test
run through a runner names the same files (e2e 1026).
v2026.11.7.1
Fixed
-
A record being published is waited out before it is read, and only a
controller whose process has ended counts as lost: a transient refusal to open
a record no longer fails a compile on Windows (#885, 20 of 20 Windows-hosted
cross builds of mcpp, against 10 failures in 40 before). -
Every compiler of a build belongs to its generation, so a build killed with
kill -9leaves no compiler that races the next build (e2e 1016). The
generation carries the compiler cap and build.ninja names none, so the graph is
the same at every-j(e2e 861); the fast path opens its generation with the
cap its first drive recorded beside build.ninja. -
On macOS a compiler slot another compiler holds is now and then reported
missing from inside the executor (mcpplibs/openkal-macos#45); it is treated as
held while its directory exists, and refused after five seconds of it. -
The note for clang without coroutines on the 32-bit MSVC ABI finds the
compiler after the capped executor's--(e2e 892). -
msvc@systemis located for a build program of a cross target and never
looked for in the package index (e2e 1017). -
Two packages of one name,
fooandns.foo, both link into a program that
reaches them (#896, e2e 1018). -
An edge that asks a resolved package for a feature its earlier edges did not
ask walks that feature's[feature-deps]and forwards, so-p s -p vbuilds
what-p sbuilds (#897, e2e 1019). -
A build directory taken over by a new fingerprint of its configuration (an
mcpp upgrade) keeps no compiler record of its predecessor: the completion
certificates there named the predecessor's objects and failed the next
build's admission ("cached compiler certificate does not name its own
object") untilmcpp clean. A certificate of another directory found at
admission (a moved or restored directory) authorizes nothing and is dropped;
the object is compiled again (e2e 1022). -
mcpp testannounces a dependency with its resolved version, as the build
does, not the constraint (v0.3.1, notv^0.3.1; e2e 196). -
A compiler that registers with its build's generation is answered within the
startup grace: an owner that accepted the registration and did not answer in
two seconds (macOS CI, a scan of a two-configuration workspace: "compiler
registration channel closed or timed out") is asked again, and an owner that
accepts no connection has ended, so the compiler ends at once (e2e 840, 1016). -
cl.exe writes a debug build's debug information into each object (
/Z7), not
into a PDB shared through mspdbsrv.exe (/Zi /FS). The server outlived the
compile that started it, and retiring that compile's process unit ended it
under the concurrent compiles, one of which failed with C1090, PDB API error
23 (e2e 258, intermittently on Windows)./Zi,/ZIand/FSin a
package's flags are refused on cl.exe before anything compiles (e2e 1023). -
A finished detached compiler is recognized when its final status appears
between status and liveness checks. Recovery still validates its output proof. -
Windows launcher packages use the OS release required by the current default
platform, so their generated dependency resolves alongside openkal-platform 0.24. -
Compiler attempt journals preserve file timestamps on Clang/libc++ when the
file clock uses a wider integer representation. -
Compiler journals retry an open that raced with atomic record publication,
and BMI/object identity checks require a regular output file on every host.
A witness failure identifies its failed observation boundary, and a detached
supervisor's failure is available to the waiter even though its stdio is closed.
Status publication now distinguishes temporary open, write, close and rename
failures, including the OpenKal condition of a failed rename. -
Launch descriptions include the selected target, profile, resolved platform
and available named runners, including the reachable leg of a target set.
Editor debug launches can retain the configuration that actually built the program. -
Tests accept
--runner <name>with the same runner resolution asrun,
including--print-launchand archive execution. Missing names and a
simultaneous--no-runnerare refused. -
Cached builds load action ownership when an action starts, so internal progress
appears while Ninja is still buffering stdout. Idle builds retain lazy loading;
command results and output checks remain authoritative. -
New action snapshots request a normal UI frame, so short phases can appear
between Ninja status lines without waiting for the clock redraw. -
Foreign-build contracts exclude the consuming package's link flags and
libraries. A subproject can link its own executable without depending on
an installation that the same subproject has yet to produce. -
The macOS clean bootstrap keeps its stage-one compiler outside the output tree
removed by the second stage. -
GCC BMI publication requires a present replacement file; its unlink-before-rename
interval no longer releases importers. A successful compiler that produces no
BMI fails with a diagnostic and restores the previous BMI. -
Ordinary compiler invocations share the detached GCC compilers' concurrency
permits, so the additional Ninja scheduling slots do not exceed--jobs. -
Cancelled detached builds stop their compilers and finish state cleanup before
another generation starts. Stable kernel permits retain live ownership across
immediate rebuilds; runtime generations leave no-op build identities unchanged. -
Compiler units retain their concurrency reservation after a supervisor is
forcibly ended. Recovery waits for descendants and final state writers;
occupied or unknown units retain their outputs and fail within a bound. -
Missing completed module objects are recovered in the same build before Ninja
reads their BMIs. Corrupt completion evidence and redirected cache state refuse
recovery without authorizing changes to unrelated outputs. -
Captured idle bounds consume queued progress from both streams before
classifying silence, including progress buffered during a slow line callback. -
Child stop predicates apply with inherited and discarded streams, including
executions without an absolute deadline. Captured stream EOF retains stop,
absolute and observed-output idle bounds until the child exits. -
Queued downloads begin their progress budget when a worker starts them,
rather than inheriting time spent waiting for a slot. -
Provider progress timeouts identify the stalled download and source attempt,
independently of progress on other files and provider process deadlines.
Changed
-
A platform's version group takes part in resolution: a request of a member
resolves to the group's version when its constraint admits it, though the
index holds a newer patch, and is refused naming the request and the group
when it does not (SPEC-013 1.4 §7.5, e2e 1020). -
The ok-image targets' built-in platform is the series
openkal-platform@^0.24: its newest release whosemcppfloor this engine
meets, kept in mcpp.lock untilmcpp update(SPEC-013 §14, §15.1, e2e 1021).
A platform patch no longer needs an mcpp release.
It resolves to openkal-platform 0.24.2: openkal-llvm-runtime 0.19.2 keeps the
volume of a name it normalizes, without which a Windows launcher over 0.24.1
could not start its runner (e2e 988). -
mcpp and the launchers it generates depend on mcpplibs.os
^0.3.1, whose
os::fsreads a name in the long spelling (\\?\C:\...) as the name it
spells; the single-file launcher moves from os 0.2.0. -
Headers are included only in the two system lock files
(.github/tools/check_include_regions.sh): zlib, zstd and xz are their mwrap
modules, JSON is nlohmann.json from the index (the copied json.hpp is gone),
and the C library's macros come from mcpplibs.mwrap.libc. Package archives
are the bytes mcpp wrote before. -
CI bootstraps from the published, mirrored and indexed 2026.11.5.1 release.
-
Release guidance preserves published tags and uses a new reviewed patch version
for fixes. GitCode assets are supplemented locally as they become available.
v2026.11.5.1
Added
- Build actions can opt into internal stage reporting with
action.progress
(protocol 18). Each execution supplies a separate UTF-8 snapshot path;
bounded, ordered snapshots update the build status. Exit codes and output
checks still determine success, and completion or cancellation cleans the
channel. Existing actions leave reporting disabled.
Changed
- Both built-in openkal targets select platform 0.23.6. Its final ThinLTO link
retains emulated TLS; the group includes musl 0.27.5, runtime 0.18.6 and
loader/tools 0.4.4. Explicit platform selections continue to override the
built-in default.
Fixed
- Accelerator requests and constrained source declarations are validated in
full. Unclosed sets, trailing text and repeated implementation members are
refused; target and implementation ordering share one canonical identity.
Published legacy artifact matching remains compatible. - Capability requirements and exclusive providers are checked within each
consumer's dependency closure. Independent workspace products can use
different providers, and applications can supply library requirements.
Selected static libraries do not add duplicate consumer contexts; their own
programs, shared libraries, tests and standalone selections retain checks.
Provider pins accept qualified identities and preserve all link inputs. - Build-only providers and requirements no longer select the final artifact's
target ABI. Transitive build dependencies remain in the host graph, while
packages also used as ordinary dependencies retain their target instances.
v2026.11.3.1
The built-in openkal platform is 0.23.3 (openkal 0.23: an image at a base of
each boot, a snapshot of its initialisers, hardening); a format a package
provides is told the compression stated; mcpp cache gc reclaims the runner's
cache; a download source that sends nothing is left for the next one; a
requirement a layer decides is checked; design 2026-11-02 part 3 landed, and
design 2026-11-03 part 4.
Changed
- The built-in
<arch>-openkalplatform ismcpplibs.openkal-platform@0.23.3
(docs/35; design 2026-11-03 part 4), the version group of openkal 0.23:
openkal-image 0.4.3, openkal-musl 0.27.3, openkal-llvm-runtime 0.18.4,
openkal-linux 0.24.1 and openkal-macos 0.21.3.
An image is sealed at a base (okld place), and the runner moves it to a
base chosen once each boot, its data kept as a prepared copy. The runner
can start a background process to snapshot eligible initialisers; later
starts can map the completed snapshot. What a start spends follows the
program's resource preference. An image is built with frame pointers, a global stack
guard, zeroed locals, libc++'s fast hardening, CET or PAC/BTI marks and a
build-id; okprof is among the platform's tools. The Windows launchermcpp packwrites for an openkal set is built over mcpplibs.os 0.2.9. Against
2026.11.2.2's 0.21.0, the runner also admits an okb member it has compared
before by its shape alone (openkal-image 0.3.1): 0.3.0 computed the
member's CRC-32 at every start, 0.1 s of processor time for a 71 MB image.
Added
- A format a package provides is told the compression stated (docs/10,
docs/30).--compressand[pack] compressreach a provided format's
program asMCPP_PACK_COMPRESS(mcpp::pack_compress()), spelled as the
flag takes it, and the provider decides what its container does with it.
--compresswas refused with every provided format, so openkal-platform's
okbcould not be asked for its compressed form: its images stored
compressed undergzip, an okb kept small on disk that okrun expands into
its cache when it first runs it (design 2026-11-03 part 4 §16). A directory
is still refused. mcpp cache gcreclaims the ok-image runner's cache too (docs/09). It
asks the newestokrunamong the host tools it built to runokrun cache gc: the prepared copies and snapshots openkal-image 0.4 keeps for an image
in the user's runtime or cache directory, of another boot. The layout is the
runner's, and so is its reclaiming (design 2026-11-03 part 4 §16).
Fixed
- The platform group carries the corrected Linux read-only confinement.
Linux 0.24.1 requires Landlock ABI 3 before reporting confinement support;
earlier ABIs do not constrain file truncation within a read-only grant.
Its ABI probe cache uses atomic accesses. Image 0.4.3 builds the native
runner with the same corrected backend. - An object-only package builds all its objects alongside cache fills.
Explicit Ninja defaults for dependency cache fills previously omitted the
package's own terminal compile edges when it had no link target. The musl
producer build selected 69 dependency and embedded objects while omitting
its 1,332 own C objects. All compile objects are now default goals for a
package without link targets. - Runner cache collection selects valid versions and preserves native paths.
Malformed or overflowing runner versions are ignored. Cache paths and the
selected runner's executable path retain their native representation, so
Windows names outside the active ANSI code page do not abort collection. - The std module is compiled with the platform's compile words (docs/35,
SPEC-013 §2.5):[platform.build]and itscfgtables reach the std
module's two commands and the key its BMI is kept under, as they reach every
other unit of the target, whichever library supplies the module.
openkal-platform 0.23.0 compiles every unit on x86_64 with
-fcf-protection=full, which clang records in a BMI, and a std module built
without it was refused by every importer ("Control-Flow Branch Protection
enabled was disabled in precompiled file"); its-D_LIBCPP_HARDENING_MODE
is the library's own code inside the module. e2e 1010 states the flag in a
platform of this machine's triple and imports std. - A requirement a layer decides is checked (docs/22, docs/specs/target-side.md
§2.2).[target.'cfg(all(windows, compiler = "llvm"))'] requires = ["mcpp:compiler-runtime=compiler-rt"]names a layer in its selector, and
such a table's requirement was dropped without a word: the requirements were
gathered before any layer resolved. It is now checked once the layers are
resolved and before anything is compiled, with the refusal a[package]
requirement gets. openkal-musl 0.27.0 states this one: on PE under clang its
link names no runtime, and a graph without compiler-rt (openkal-llvm-runtime)
reached the link with___chkstk_msundefined. - A download source that connects and sends nothing no longer stops the
install (docs/specs/home-initialization.md §5). xlings leaves such a source
after 30 seconds without a byte and tries the next; mcpp stopped the install
after 30 seconds without a byte or a new source, so the next source was never
reached (CI, 2026-11-02: a GitHub proxy that accepted the connection,
attempt 1). mcpp's own bound is now 45 seconds; a source's bounds, 8 seconds
to connect and 30 without a byte, are unchanged.
Design
- Design 2026-11-02 part 3 (ok image performance parity) landed: the engine's
revisions measured on macOS (a worker's ceiling watched, an open directory's
count of names on APFS, one opening of a cache root), L2 on every system and
L3 on every system.
v2026.11.2.2
The built-in openkal platform is 0.21.0; an embedded dependency's link
requirements are its embedder's; a response file a link flag names is an input
of the link (design 2026-11-02, part 3 rev 4).
Changed
- The built-in
<arch>-openkalplatform ismcpplibs.openkal-platform@0.21.0
(docs/35): openkal 0.21, whose loader maps an image's instructions from its
file (kal_exec_map_part); openkal-linux 0.22, openkal-macos 0.19,
openkal-windows 0.17; openkal-musl 0.26 with mimalloc; openkal-llvm-runtime
0.17; openkal-image 0.3. The Windows launchermcpp packbuilds over it
depends on mcpplibs.os 0.2.7, the release written against openkal 0.21. - An embedded dependency's link flags and libraries are its embedder's
(docs/05). The embedder supplies the definitions, over the operating-system
layer it chose, and states what they link against; the dependency's
[build] ldflagsand[runtime] librariesdescribed the library it builds
on its own. openkal-musl embedscompat.mimallocwithout itsprim.c, and a
Windows program built on Linux was linked againstpsapi,user32and
advapi32, which no sysroot of that build has. e2e 1002.
Fixed
- A response file a link flag names (
@<file>), and every file it names,
are inputs of the link. A build program that lists the archives a
prepareaction makes in one (link_flag("@<file>")) left the link up to
date over rebuilt archives. The hermetic link check reads such a file in
place: with one on its command line the driver handed the linker a response
file of its own, which-###names and does not write, and the check refused
the link as taking the system's C library. e2e 1006. - The cache entry of a package whose units this build does not all need is
filled (bmi cache populate failed ... expected build output missing). The
engine package'smcpp.corewas compiled only where something imported it,
and a build plugin importingmcppalone left its entry unfilled on every
build. A unit whose outputs fill an entry is built whether or not a link or
an importer of this build asks for it. e2e 910. - A release's
SHA256SUMSnames every archive, the four builds and the
source; it named Linux x86_64 alone.