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.mcpp runs, whether or not the build uses it. A build.mcpp that names its own tool (o.cmake = "/usr/bin/cmake") still downloads xim:cmake, and with MCPP_NO_AUTO_INSTALL=1 the build is refused before build.mcpp runs (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 (
bundletool for every Android build, appimagetool for every Linux build, emit build-database downloads).
- 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, program or host, with its origin (file:line, environment variable, global config). One decision record (in resolution.json) drives the output, mcpp why, machine output, the build information and the pack record.
- Output: a build whose sources are all
managed/pinned prints exactly what it prints today. A non-default source gets one Using ... [class · origin] line; the Finished line summarises them; a failure names the source of the tool that failed. --managed-only / MCPP_MANAGED_ONLY=1 refuses 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_dir answers the override; xpkg_program/xpkg_source are added.
- On-request provisioning: a payload entry may state
provision = "on-request"; a build program asks with xpkg_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>, a bootstrap key, 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.
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: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.bundletoolfor every Android build,appimagetoolfor every Linux build,emit build-databasedownloads).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/docswith the implementing PR. In short: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.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.[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.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.[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.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.