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 |
- Native C++23 module support —
import stdhandled automatically, file-level incremental builds, automatic module dependency analysis, zero manual configuration - Pure modular self-hosting — mcpp itself consists of 43+ C++23 modules and builds itself; the module pipeline is battle-tested
- Works out of the box — one-command install, bundled GCC 16 / LLVM 20 toolchains downloaded into an isolated sandbox, never polluting your system
- Integrated dependency management — SemVer constraint resolution, lockfile, cross-project BMI cache, custom package indices
- Multi-package workspaces — unified lockfile and version management for larger projects
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:
- Modular by default — projects created by
mcpp newuse C++23 modules directly;import stdjust works - File-level incremental builds — three-layer optimization based on P1689 dyndep (front-end dirty check + per-file scanning + BMI restat); only the modules that actually changed get recompiled
- Create & build in one go —
mcpp new hello && cd hello && mcpp build; toolchains install automatically, no compiler or build-system setup required - A modular ecosystem — mcpplibs offers a growing set of directly
import-able C++ module libraries, plus support for custom package indices
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)
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)
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 managementmcpp why [toolchain|runtime|deps]— explain resolved build decisionsmcpp --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, 57k lines, 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 · - would mean not measured, and there is none here ·
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. Themcpp (old)column measures the previous release at 81.72s, level with cmake, so the effect is new in this revision. -
edit-bodymeasures the case where the cascade is genuinely owed — and whether an edit owes one depends on where the body lives:the function body is in… editing it this row a .cppm, and the edit moves linesGCC records declaration positions, so the BMI changes → cascade owed what is measured: 1.1x, and 2.9x with +opta .cppm, edited in place (same line count)GCC does not serialise non-template bodies → BMI unchanged → no cascade ~200x, like touch-huba separate .cppimplementation unitthat file has no BMI at all → no cascade, on every compiler ~200x The perturbation here inserts a statement, so it takes the first row: every engine has to rebuild the importers, and one that did not would be skipping work.
+optdoes not skip it either — it does the same work 2.9x faster. Splitting interface from implementation is the sturdiest of the three, because it does not depend on GCC's body handling or on avoiding line shifts. 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 helps only where a cascade is required:cold86.69s → 35.73s,edit-body80.87s → 29.83s. On the two rows where mcpp already skips the cascade it yields no improvement. 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; this table mirrors the in-code vocabulary):
| Target | Convention toolchain | Status |
|---|---|---|
x86_64-linux-gnu |
gcc (Linux default) or llvm | ✅ |
x86_64-linux-musl |
gcc 16, fully static | ✅ |
aarch64-linux-musl |
gcc 16, fully static — cross from x86_64 (qemu-verified) or native | ✅ |
x86_64-windows-gnu |
gcc 16 MinGW-w64 — native on Windows, cross from Linux (wine-verified) (Windows default without Visual Studio) | ✅ |
x86_64-windows-msvc |
msvc@system (detected VS/BuildTools) or llvm ¹ (Windows default with Visual Studio) |
✅ |
aarch64-macos |
llvm (macOS default) | ✅ |
riscv64-linux-musl |
— | 🔄 |
aarch64-linux-gnu |
— | 🔄 |
x86_64-macos |
— | 🔄 |
✅ verified — CI builds and executes the artifact end-to-end (qemu/wine included) | 🔄 planned
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.
- Getting Started — install → new → build → run in 5 minutes
- Examples
- Packaging & Release
- Toolchain Management
- Building from Source
- mcpp.toml Guide
- Workspaces
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 — 43+ C++23 modules, fully self-hosted |
| xlings | Toolchain & 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
