A modern C++ module-first build tool — written in pure C++23 modules, fully self-hosted
English | 简体中文
| Documentation · Getting Started · mcpp.toml Guide · Examples · Toolchains |
|---|
| Package index mcpp-index · Module libraries mcpplibs · Community Forum · Issues · Releases |
- Modular build system — C++ modules first:
import stdhandled automatically, file-level incremental builds, automatic dependency analysis, nothing to configure - Build plugins and heterogeneous hardware —
build.mcppand rule packages extend the build; CUDA, HIP, SYCL, Vulkan/SPIR-V and Ascend C are each a rule package - Package management and a module-library ecosystem — SemVer constraints, lockfile, cross-project BMI cache, custom indices; a library from mcpplibs is two lines away from
import - Toolchain management and cross-compilation —
family@versioninstalled on demand;--targetmoves the same build to Windows, macOS, Cortex-M or RISC-V bare metal, and one source tree reaches several hosted targets over openkal - Environment and runtime — the user-space environment xlings provides: toolchains and dependencies stay in an isolated sandbox, and a runner puts the artifact on a board or an emulator
- Pure modular self-hosting — mcpp is written entirely in C++23 module interface units and builds itself
mcpp is built specifically for C++23 module-first development. If you want to use import std, module interface units (.cppm), module partitions, and other modern C++ features in your project, mcpp gives you a smooth, friendly experience on Linux, macOS ARM64, and Windows x86_64.
C++ normally spreads these five jobs across five tools, and mcpp is one command for all five. The second row names what each column is usually recognised as.
| mcpp | build system | build plugins | package manager | toolchain manager | environment and runtime |
|---|---|---|---|---|---|
| closest to | CMake + Ninja | CMake modules, xmake rules | vcpkg, Conan | rustup, nvm | conda, Nix |
Note
Early-stage project — mcpp is under active development; interfaces and behavior may change in future releases. Developers interested in modern C++ module-first build tooling are welcome to contribute. Questions / feedback / ideas — drop a note in issues.
Install via xlings (recommended)
xlings install mcpp -yDon't have xlings yet? Click for the install command
Linux / macOS
curl -fsSL https://d2learn.org/xlings-install.sh | bashWindows — PowerShell
irm https://d2learn.org/xlings-install.ps1.txt | iexMore about xlings → xlings.d2learn.org
Optional — short commands (mp, mbuild, mrun, …)
xlings install mcpp-short-cmd -yRegisters 30 shims, so mcpp build becomes mbuild. Naming rule: initial of
every word but the last, plus the last word in full — mcpp self doctor →
msdoctor. mp is bare mcpp. They alias the mcpp shim rather than a fixed
binary, so xlings use mcpp <ver> switches them too.
| Short | Expands to | Short | Expands to |
|---|---|---|---|
mp |
mcpp |
mexpkg |
mcpp emit xpkg |
mnew |
mcpp new |
mxparse |
mcpp xpkg parse |
mbuild |
mcpp build |
mtinstall |
mcpp toolchain install |
mrun |
mcpp run |
mtlist |
mcpp toolchain list |
mtest |
mcpp test |
mtdefault |
mcpp toolchain default |
mclean |
mcpp clean |
mcdir |
mcpp cache dir |
madd |
mcpp add |
mclist |
mcpp cache list |
mremove |
mcpp remove |
mcinfo |
mcpp cache info |
mupdate |
mcpp update |
mcgc |
mcpp cache gc |
msearch |
mcpp search |
milist |
mcpp index list |
mpublish |
mcpp publish |
miadd |
mcpp index add |
mpack |
mcpp pack |
miremove |
mcpp index remove |
msdoctor |
mcpp self doctor |
miupdate |
mcpp index update |
msenv |
mcpp self env |
msconfig |
mcpp self config |
msversion |
mcpp self version |
msexplain |
mcpp self explain |
Other options
Option 1 — one-line installer (Linux x86_64/aarch64, macOS ARM64)
curl -fsSL https://github.com/mcpp-community/mcpp/releases/latest/download/install.sh | bashThis installer does not support Windows; use the PowerShell xlings route above.
It installs into ~/.mcpp/ and adds it to your shell PATH. Deleting ~/.mcpp
uninstalls cleanly.
Option 2 — Homebrew (macOS / Linux)
brew install mcpp-community/mcpp/mcpp-mOne command — it taps mcpp-community/homebrew-mcpp
and installs the same prebuilt release binary. macOS needs Apple silicon +
macOS 14; per-user data lives in ~/.mcpp/.
Homebrew's mcpp is an unrelated C preprocessor, hence the mcpp-m formula
name — the command it installs is still mcpp.
Homebrew 6 gates third-party taps. The fully-qualified command above is
read as explicit intent and works as-is, but every other spelling — the short
brew install mcpp-m, the mcpp alias, and later upgrades — is refused with:
Refusing to load formula mcpp-community/mcpp/mcpp-m from untrusted tap
mcpp-community/mcpp.
Trust the tap once and all of them work:
brew trust mcpp-community/mcppOption 3 — Arch Linux (AUR)
yay -S mcpp-bin # prebuilt release binary
yay -S mcpp-m # or build from source (bootstrapped with mcpp-bin)Installs the mcpp command system-wide; per-user data still lives in ~/.mcpp/.
On Arch the name mcpp is an unrelated C preprocessor, so the packages are
mcpp-bin / mcpp-m (see scripts/aur/).
Stable-release automation reconciles mcpp-bin only; mcpp-m and mcpp-git
remain manually maintained and may intentionally lag.
Option 4 — let an AI assistant install it for you
Copy the following prompt to your AI coding assistant (Claude Code / Cursor / Copilot, etc.):
Read the README of https://github.com/mcpp-community/mcpp,
then install mcpp for me and create a C++23 module project, build and run it.
The repo's .agents/skills/mcpp-usage/SKILL.md has a detailed usage guide.
mcpp new hello
cd hello
mcpp build
mcpp runNote: the first build initializes the environment and fetches the toolchain, which may take a while.
hello/
├── mcpp.toml ← project manifest
├── src/
│ └── main.cpp ← import std; works directly
└── tests/
└── test_smoke.cpp ← discovered by `mcpp test`
# mcpp.toml
[package]
name = "hello"
version = "0.1.0"
description = "A modular C++23 package"
license = "Apache-2.0"The built-in scaffold relies on convention: it does not write [targets.hello].
src/main.cpp infers the binary target, and mcpp test automatically discovers
tests/test_smoke.cpp.
Add a two-line dependency to mcpp.toml to pull in a community module library from mcpplibs:
[dependencies]
cmdline = "0.0.2"Then import it directly in your code:
import mcpplibs.cmdline;For more dependency options (version constraints, namespaces, Git references, local paths, etc.), see the mcpp.toml guide — dependency management.
Build system
- Native C++20/23/26 module support (interface units, implementation units, module partitions), plus
c++latest/c++flyexperimental modes - Fully automatic precompilation and caching of
import std/import std.compat - Three-layer incremental optimization: front-end dirty check + per-file P1689 dyndep + BMI copy-if-different restat
- Fingerprinted BMI cache: hashed by compiler/flags/standard library, shared across projects
- Ninja backend: auto-generated build.ninja, parallel compilation
compile_commands.jsongenerated automatically (ready for clangd / ccls); usemcpp build --configure-onlyto refresh it before ordinary sources compile- First-class C support:
.cfiles auto-detected, mixed C/C++ projects - User-defined cflags / cxxflags / ldflags / c_standard
Toolchain management
- Bundled GCC 16.1.0 + LLVM/Clang 20.1.7, one-command install
- Host-aware defaults: native glibc GCC on Linux x86_64, musl GCC on other Linux architectures, LLVM on macOS and on Windows with usable MSVC, MinGW-w64 GCC on bare Windows
- Multiple versions side by side:
mcpp toolchain install gcc 16/mcpp toolchain install llvm 20 - Isolated sandbox: all toolchains live in
~/.mcpp/registry/, leaving the system untouched - Per-platform selection:
linux = "gcc@16",macos = "llvm@20" - GCC and Clang compile pipelines at parity (driven by the
BmiTraitsabstraction layer)
Cross-compilation, bare metal and devices
mcpp build --target <triple>— one flag; the toolchain payload for that target is resolved and installed automatically- Targets from
x86_64-linux-gnuto Cortex-M, Cortex-A and RISC-V bare metal; the full table is under Platform Support - Freestanding targets carry no operating system: the C library, startup code, memory layout and emulator travel with a board-support package rather than with mcpp
- Runners reach an artifact that cannot run on the build machine —
mcpp run --runner flash,--list-runners,mcpp why runners mcpp new --template riscv-virt-rt— a board template a package ships, instantiated by name- Cross-compilation over openkal: a portable program builds for a target whose kernel interface and C library come from packages
Heterogeneous builds and accelerators
[build] accel = "cuda12.9+{sm_89}, vulkan1.2"— a build names one or more device backends, andcfg(accelerator = "cuda")is true in that build- Five programming models have rule packages today: CUDA, HIP, SYCL, Vulkan/SPIR-V and Ascend C
- Device translation units are compiled by their own compiler and join the ordinary link; the host/device boundary is generated rather than written twice
- A constrained glob selects device sources:
{ glob = "src/kernels/**/*.cu", accel = "cuda12.9+{sm_89}" } - Nothing in the engine holds a vendor name, so a sixth backend is a package rather than an engine change
Package & dependency management
- SemVer constraint resolution:
^,~, ranges, exact versions - Three-stage resolution: constraint merging → multi-version mangling fallback → exact match
- Lockfile mcpp.lock (v2 format: index snapshot + namespaces)
- Namespace system:
[dependencies.myteam] foo = "1.0" - Custom package indices:
[indices] acme = "git@..."/{ path = "..." } - Project-level index isolation (
.mcpp/directory, no global pollution) - Dependency sources: index / Git / local path
Workspaces
[workspace] members = ["libs/*", "apps/*"]- Unified lockfile + unified target directory
- Centralized version management:
[workspace.dependencies]+.workspace = true - Selective builds:
mcpp build -p member-name - Config inheritance: toolchains, build flags, and indices cascade from root to members
Packaging & publishing
mcpp pack: four Linux release modes — system / vendored (default) / self-contained / static;bundle-projectandbundle-allremain compatibility aliases- Fully static musl binaries: single-file distribution, no glibc dependency (matching Linux x86_64 or aarch64 target)
mcpp publish: generates xpkg.lua + publishes to a package index- Automatic RPATH fix-up via patchelf (Linux)
Extending the build
build.mcpp— a build program for a step mcpp has no rule for, speaking a directive protocol that is versioned rather than guessedmcpp::actiondeclares work with explicit inputs and outputs, so a generated file takes part in the incremental graph instead of sitting outside it- A rule package carries that step to other projects: it declares a rule module, and a consumer selects it as a feature
- Payloads, runtime adapters and board-support packages are ordinary packages — a tool, a driver or a board is installed by the resolver that installs a library
Developer experience
mcpp new— create a modular project;--template [ns.]name[@version][:tname]uses a package-provided template with the same exact identity style asmcpp add. A sole template is the default even withoutdefault = true;--list-templates [ns.]name[@version]lists ambiguous setsmcpp run [-- args]— build and runmcpp test [pattern] [-- args]— auto-discover and run tests (filter by name;--list,--timeout <s>,--message-format json)mcpp search— search package indicesmcpp add / remove / update— dependency management- Profiles and features on the command line:
--release/--profile <name>onbuildandrun,--features <list>onbuild,runandtest mcpp why [toolchain|runtime|deps|runners]— explain resolved build decisions;--format jsonfor a machine readermcpp emit sbom— a CycloneDX bill of materials for the resolution just recordedmcpp --offline/MCPP_OFFLINE=1— use only already available local statemcpp explain E0001— detailed error-code explanationsmcpp self doctor— environment self-diagnosis
Building mcpp itself — 137 module interface units and 57k lines at the
pinned workload, every one of them import std; — with four engines handed the
same compiler binary. Each cell is the median of 3 samples and how many
times faster it is than cmake. Every column comes from one run.
| scenario | mcpp |
mcpp +opt |
mcpp (old) |
cmake |
xmake |
|---|---|---|---|---|---|
cold |
86.69s · 1.1x | 35.73s · 2.6x | 86.75s · 1.1x | 91.74s · 1.0x | 90.54s · 1.0x |
noop |
0.16s · 2.0x | 0.18s · 1.8x | 0.24s · 1.3x | 0.32s · 1.0x | 0.38s · 0.8x |
touch-hub |
0.42s · 197.7x | 0.42s · 197.2x | 81.72s · 1.0x | 83.21s · 1.0x | 82.48s · 1.0x |
edit-body |
80.87s · 1.1x | 29.83s · 2.9x | 81.19s · 1.1x | 85.30s · 1.0x | 84.33s · 1.0x |
edit-comment |
0.40s · 207.0x | 0.40s · 207.0x | 79.11s · 1.1x | 83.21s · 1.0x | 82.15s · 1.0x |
cold nothing built yet · noop nothing at all · touch-hub mtime only, content unchanged · edit-body a real edit inside a function body · edit-comment a comment added to a hub interface.
mcpp = mcpp@2026.8.13.1, the build under test · mcpp +opt = the SAME binary as mcpp, with the opt-in key [build] bmi_schedule = "on" (off by default) · mcpp (old) = mcpp@2026.8.11.3, the previously published release.
Linux x86_64 · i9-13900K · gcc 16.1.0 · n=3 · pinned workload a749e9f ·
cmake 4.4.2 / xmake 3.1.0 · min/max sit within 4% of every median above 1s ·
data: standard-20260814-linux-x86_64.
- Cascade suppression accounts for the
touch-hubandedit-commentrows. cmake and xmake decide by timestamp and rebuild every downstream unit; mcpp compares the BMI the compiler has just produced against the previous one and skips the cascade when the interface is unchanged. This is default behaviour and requires no configuration.mcpp (old)measures the previous release at 81.72s, level with cmake, so the effect is new in this revision. edit-bodyis the control, and mcpp is deliberately not fast on it. The perturbation inserts a statement into an interface unit, which moves the source positions GCC records, so the BMI changes and every importer is owed a rebuild — an engine that were fast on that row would be skipping work it owes. Whether an edit owes a cascade depends on where the body lives: an in-place edit of the same length, or a body in a separate.cpp, owes none and lands near the 200x rows. Measured in.agents/docs/2026-08-15-module-edit-granularity.md.bmi_scheduleis opt-in and disabled by default (autoresolves to off). It moves code generation off the critical path, so it pays only where a cascade is owed —cold86.69s → 35.73s,edit-body80.87s → 29.83s, and nothing on the two rows mcpp already skips. An incorrect scheduling change fails silently rather than loudly, so the default is not changed on the evidence of a single machine.
Methodology, pinned versions, and the full data →
bench/README.md · 简体中文
mcpp's identity model has two orthogonal axes: a toolchain is
family@version (family ∈ gcc | llvm | msvc), a target is a triple
arch-os[-env]. Cross-compiling is just mcpp build --target <triple> —
the right toolchain payload is resolved and installed automatically.
mcpp toolchain list shows live status on your machine.
Hosts (where mcpp itself runs): Linux x86_64 / aarch64, macOS arm64, Windows x86_64.
Targets (what --target accepts; the rows and their tiers are the ones in
modules/toolchain-model/src/triple.cppm, which is also what mcpp toolchain list reports for this machine):
| Target | Convention toolchain | Tier |
|---|---|---|
x86_64-linux-gnu |
gcc (Linux default) or llvm | verified |
x86_64-linux-musl |
gcc 16, fully static | verified |
aarch64-linux-musl |
gcc 16, fully static — cross from x86_64 (qemu) or native | verified |
x86_64-windows-gnu |
gcc 16 MinGW-w64 — native on Windows, cross from Linux (wine) (Windows default without Visual Studio) | verified |
x86_64-windows-msvc |
msvc@system (detected VS/BuildTools) or llvm ¹ (Windows default with Visual Studio) |
verified |
x86_64-windows-musl |
llvm 22 — a PE with a musl C library, which no gcc emits; the system comes from the dependency graph | preview |
aarch64-macos |
llvm (macOS default) | verified |
riscv64-none-elf · riscv32-none-elf |
llvm 22 — bare metal, xim:picolibc-riscv ² |
verified |
thumbv6m-none-eabi · thumbv7m-none-eabi |
llvm 22 — Cortex-M0/M0+/M1, Cortex-M3 ² | verified |
thumbv7em-none-eabihf · thumbv8m.main-none-eabi |
llvm 22 — Cortex-M4F/M7F hard float, Cortex-M33/M55 soft float ² | verified |
armv7a-none-eabi · armv7a-none-eabihf |
llvm 22 — Cortex-A 32-bit, the first row with an MMU ² | verified |
aarch64-none-elf · x86_64-none-elf |
llvm 22 — bare metal, no C library by default ² | preview |
thumbv7em-none-eabi · thumbv8m.base-none-eabi · thumbv8m.main-none-eabihf |
llvm 22 — Cortex-M4/M7 soft float, M23, M33F/M55F ² | preview |
riscv64-linux-musl · aarch64-linux-gnu · x86_64-macos |
— | planned |
verified an image has been built and run for the row, qemu and wine
included · preview it builds and links, and no emulator run has been recorded
· planned registered in the vocabulary and nothing wired yet — a build for
such a target is refused rather than attempted.
Linux release binaries are fully static musl builds for x86_64 and aarch64 (
x86_64-linux-muslandaarch64-linux-musl). Legacy spellings —x86_64-w64-mingw32,gcc@16.1.0-musl,mingw-cross@…,musl-gcc@…— stay permanently accepted as aliases and normalize to the canonical forms above.¹ On Windows, llvm targets the MSVC ABI and therefore requires an existing MSVC BuildTools or Visual Studio (UCRT, Windows SDK, MSVC STL). You do not have to arrange this: on first run mcpp checks for a usable MSVC and, finding none, defaults to
x86_64-windows-gnu(winlibs MinGW-w64) — fully self-contained, no Visual Studio,import stdincluded. Nothing to install or configure;mcpp new && mcpp buildjust works on a stock Windows box. An explicit[toolchain]inmcpp.tomlis always respected as written — mcpp revises its own default, never yours.² The bare-metal rows carry no operating system: clang and lld are cross-compilers by construction, so any host that can install the LLVM payload produces these targets. The C library, startup code, memory layout and emulator travel with a board-support package rather than with mcpp — see 40 — Bare-Metal and Freestanding Targets.
docs/ is the manual. A chapter's first digit says which part
it belongs to, and the index carries the reverse lookup — from a manifest key or
a command in front of a reader, to the chapter that owns it.
| Part | Start at |
|---|---|
0x fundamentals |
01 Getting Started · 04 The mcpp.toml Manifest · 09 Commands by Scenario |
1x publishing |
10 Packaging an Application for Release · 11 Publishing a Library to mcpp-index · 12 Distributing a Prebuilt Library |
2x toolchains and targets |
20 Toolchain Management · 21 The Target Triple · 24 Cross-Compilation Over openkal |
3x extending mcpp |
30 Build Programs: build.mcpp · 31 Authoring a Rule Package · 34 Authoring a Board-Support Package |
4x devices and accelerators |
40 Bare-Metal and Freestanding Targets · 41 Reaching a Device · 42 Heterogeneous Builds |
5x contracts for programs |
50 Machine-Readable Output · 51 Supported Versions and Compatibility · the specifications |
9x mcpp itself |
90 Building from Source and Contributing · 92 Releasing mcpp |
Every directory under examples/ is a project that builds, and
03 — Examples says which one teaches what. Full options
for any command are available via mcpp <cmd> --help.
AI-assisted learning: send the following prompt to an AI coding assistant to get up to speed with mcpp quickly:
Read .agents/skills/mcpp-usage/SKILL.md and the docs/ directory of the
https://github.com/mcpp-community/mcpp repository,
then tell me how to create a C++23 module project with dependencies using mcpp.
Real projects built with mcpp — import-able C++23 modules and the toolchain it builds on:
| Project | Description |
|---|---|
| mcpp | mcpp itself — written in C++23 modules, fully self-hosted |
| xlings | Toolchain and package-management foundation mcpp builds on |
| tinyhttps | Minimal C++23 HTTP/HTTPS client with SSE streaming |
| llmapi | Modern C++ LLM API client (OpenAI-compatible) |
| imgui-m | Dear ImGui as a C++23 module package |
| cmdline | Command-line parsing library / framework (mcpp uses it) |
More modular libraries → mcpplibs · package index → mcpp-index
Contributions via issues and PRs are welcome. The project accepts contributions developed with AI agents.
Basic workflow
- Open an issue — for bug fixes, new features, or improvements, start a discussion in issues first
- Implement the change — fork the repo, create a branch, and verify according to scope (
mcpp buildplus relevant tests for behavior changes; examples and links for documentation-only changes) - Submit a PR — use
gh pr createand make sure CI passes - CI must pass — PRs with failing CI will not be merged
Commit message convention: feat: / fix: / test: / docs: / refactor: prefixes
AI agent contributions: the repo's .agents/skills/mcpp-contributing/SKILL.md provides a complete agent contribution workflow and project structure guide. Just send this prompt to your AI assistant:
Read .agents/skills/mcpp-contributing/SKILL.md of the
https://github.com/mcpp-community/mcpp repository,
then follow the guide to help me submit a contribution to mcpp.
- Community Forum — chat group (QQ: 1067245099)
- mcpp-index — default package index
- mcpplibs — collection of modular C++ libraries
Dependencies and sources of inspiration:
- xlings — toolchain / package-management foundation
- mcpplibs.cmdline — CLI framework
- ninja — underlying build engine
- xmake — cross-platform build tool
- cargo — Rust package manager
