Repository navigation
feat: declared, programmable and observable sources for toolchains, payloads and plugin tools #755
Copy link
Copy link
Closed
Description
Motivation
A build uses three kinds of things whose source a project may want to state: the toolchain, the xlings payloads a plugin declares ([feature-xlings.<f>]), and the tools a plugin runs. Today:
- A payload a plugin declares is provisioned before any
build.mcppruns, whether or not the build uses it. Abuild.mcppthat names its own tool (o.cmake = "/usr/bin/cmake") still downloadsxim:cmake, and withMCPP_NO_AUTO_INSTALL=1the build is refused beforebuild.mcppruns (measured on 2026.9.30.2 with a stand-in plugin;[tools.overrides]does not apply to payloads). Only manifest gates (feature,cfg,when) avoid the download. - A payload is installed when it is declared, not when it is used (
bundletoolfor every Android build,appimagetoolfor every Linux build,emit build-databasedownloads). - The toolchain can only be a managed payload: a toolchain a developer already has (a self-built LLVM, a vendor cross toolchain) cannot be named by path, and a build program cannot configure one.
- Output and records do not say which of these came from the ecosystem default and which a project or machine chose, so a failure cannot be attributed.
Design
Recorded in mcpp-community/mcpp-plugins .agents/docs/2026-10-01-ecosystem-build-plugin-framework-design.md (v3) and in this repository's .agents/docs with the implementing PR. In short:
- A source model: each toolchain, payload and plugin tool has one source of class
managed,pinned,custom,programorhost, with its origin (file:line, environment variable, global config). One decision record (inresolution.json) drives the output,mcpp why, machine output, the build information and the pack record. - Output: a build whose sources are all
managed/pinnedprints exactly what it prints today. A non-default source gets oneUsing ... [class · origin]line; theFinishedline summarises them; a failure names the source of the tool that failed.--managed-only/MCPP_MANAGED_ONLY=1refuses any non-default source. - Payload overrides:
[xlings.overrides]in the root manifest (also under[target.'cfg(..)']),MCPP_XLINGS_OVERRIDE_<NS>_<NAME>, and~/.mcpp/config.toml. An overridden payload is not provisioned; it still takes part in version unification;xpkg_diranswers the override;xpkg_program/xpkg_sourceare added. - On-request provisioning: a payload entry may state
provision = "on-request"; a build program asks withxpkg_request, the engine installs every request in one batch and re-runs only the programs that asked. - Custom toolchains:
[toolchain] <key> = { path = ..., prefix, sysroot, family, launcher, tools }(a normalized layout, a path is enough),MCPP_TOOLCHAIN=path:<dir>, abootstrapkey, and{ configure = "build.mcpp" }: the root build program, compiled with the bootstrap toolchain, runs once in a toolchain phase before the dependency graph is resolved and states the build toolchain. - Specifications and documentation of the plugin framework (SPEC build-plugins, SPEC-004, docs/20, 23, 30, 31, 50, English and Chinese).
Modules involved
modules/manifest, modules/buildmcpp, src/build/prepare/*, src/build/build_program.cppm, src/build/hostprogram.cppm, src/toolchain/*, src/ui.cppm, src/cli*, src/config.cppm, docs and specs.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
2026.10.1.3: a source for every tool a build uses, declared, programm…
0.19.0: one resolver for a member's tool, payloads installed on reque…
speak-agent commentedon Oct 1, 2026
Landed in mcpp 2026.10.1.3
Every tool a build uses now has a source that can be declared, decided by a build program, and read back. The design record is
.agents/docs/2026-10-01-tool-and-toolchain-sources-design.md; the ecosystem side is mcpp-plugins 0.19.0.What the engine gained
[xlings.overrides]states where a declared payload comes from — in the root manifest (also under[target.'cfg(..)']), asMCPP_XLINGS_OVERRIDE_<NS>_<NAME>, or in~/.mcpp/config.toml. An overridden payload is not provisioned and does not reach the offline gate. A statedversionis checked against every requirement a package of the graph made; without one, a note names the requirement that went unchecked. A dependency that writes the table is refused.provision = "on-request"installs a payload when a build program asks for it (mcpp::xpkg_request). Every request of one invocation is installed together and only the programs that asked run again, so a build whose program names its own tool downloads nothing.mcpp emit build-databaseinstalls nothing and recordsMCPP_BUILD_DATABASE_PAYLOAD_DEFERRED.[toolchain] <key> = { path, prefix, sysroot, family, launcher, tools }, orMCPP_TOOLCHAIN=path:<dir>. mcpp probes the drivers, drives them with its own link model, and writes nothing into the tree. The driver and each stated tool enter the fingerprint by content, and the fast paths decline once one changed.[toolchain] bootstrap, and[toolchain] <key> = { configure = "build.mcpp" }— a toolchain phase wheremcpp::phase()is"toolchain"and the root build program states the toolchain withmcpp::toolchain(key, value).Using … [custom · mcpp.toml:22]), a summary onFinished, a record inresolution.json, andmcpp why sources | tool <name> | payload <ns:name>, including asmcpp.why.sourcesunder--format json.--managed-onlyrefuses a build whose sources are not the ecosystem's, naming each.xpkg_source,xpkg_program,xpkg_request,xpkg_pending,phase,decision,toolchain.A project that writes none of the new keys builds exactly as before, and its output is unchanged.
Measured, not assumed. The behaviour this issue asked for is
MCPP_NO_AUTO_INSTALL=1plus a build program that names its own cmake: mcpp-plugins'tests/cmake-consumerbuilds, reportsUsing cmake (mcpp.deps.cmake) ← … [program · build.mcpp:10], and theFinishedline carriesprogram: cmake (mcpp.deps.cmake). A validation lab ran eight such cases on ubuntu-24.04, macos-15 and windows-2022.What the other platforms found, each with its measurement, is in the PR: a compile command that outgrew the Windows shell limit (and a response file that has to be written in each driver's grammar — LLVM's GNU tokenizer escapes backslashes inside quotes too), a stated linker that reached the link on Linux only, a manifest key that said nothing about the engine floor,
which()missing a name that is also a shell builtin, and an executable suffix a host appends itself.Released and verified in the ecosystem
4d81d062with 43 checks green (the two red lanes are thexcode-27ones documented inci-macos.ymland tracked in ci-macos xcode-27: ld64.lld cannot parse arm64e.x1 in either available SDK (upstream, tracked) #669); tagged, released with 21 assets, and registered through bump(mcpp): track 2026.10.1.3 as latest openxlings/xim-pkgindex#917.MCPP_HOME(xlings subos eco-1001):Three validation labs carry the measurements:
speak-agent/mcpp-framework-lab(10 cases on three platforms; naming the host's cmake instead of provisioning saves 23.2 s, 14.8 s and 14.2 s cold, and the saving is the one-time provisioning cost rather than a per-build one),speak-agent/mcpp-toolchain-lab(8 cases; it found that a stated linker reached the link on Linux only), andspeak-agent/llvm-macos27-lab(the upstream macOS 27 evidence recorded on #669).