Cuppa is an extensible C++ build system on top of SCons. It keeps sconscript files declarative while handling toolchains, variants, dependencies, tests, and coverage. From a project tree you typically run:
cuppa -Dand cuppa builds the relevant sconscript files (the -D SCons flag finds the sconstruct and runs scripts relative to your starting directory).
Full reference documentation: https://ja11sop.github.io/cuppa/ (Antora site in docs/). Contributing to cuppa itself (versioning, releases): Contributing. Agent-oriented guidance: AGENTS.md. Feature roadmap: ROADMAP.md. Release notes: CHANGELOG.md. Design notes and plans: design/.
- Make-like CLI via
cuppaorsconswith cuppa loaded in thesconstruct - Multi-variant builds: debug (
--dbg), release (--rel), coverage (--cov, GCC/Clang) - Multi-toolchain: GCC, Clang, and MSVC (
vcon Windows), with wildcards (--toolchains=gcc*,clang21) - Out-of-tree builds under
_build/, with dependencies and downloads shared under~/.cuppa/ - Dependencies: Boost, Qt4/Qt5, Quince, location-based libraries, GitLab package registry
- Test runners and HTML coverage (gcovr), plus optional HTML test reports
- Optional C++20 modules (
--modules): named modules, partitions, header units,import stdwhere supported - Persistent config:
configure.confand~/.cuppaconfig
pip install cuppaThe cuppa console script wraps scons, enables --cuppa-mode, and masks environment values whose names contain TOKEN.
Other install options (local pip install cuppa -t ., site_scons, bootstrap from sconstruct) are covered in the install guide.
sconstruct:
import cuppa
cuppa.run()sconscript:
Import('env')
for source in env.GlobFiles('*.cpp'):
env.Build(str(source)[:-4], source)Build:
cuppa -D
cuppa -D --dbg
cuppa -D --relTreat sources as tests and run them:
Import('env')
for source in env.GlobFiles('*.cpp'):
env.BuildTest(str(source)[:-4], source)cuppa -D --dbg --test --show-test-outputA self-contained smoke project lives in examples/minimal/.
import cuppa
cuppa.run(
default_options = {
'boost-location': '/path/to/boost',
},
default_dependencies = [
'boost',
],
)Import('env')
env.AppendUnique(STATICLIBS=env.BoostStaticLibs(['system', 'filesystem']))
env.BuildTest('my_test', 'my_test.cpp')| Flag | Purpose |
|---|---|
-D |
SCons: find sconstruct upward; run scripts from cwd |
--dbg / --rel / --cov |
Build variants |
--test / --force-test |
Run BuildTest / Test targets |
--toolchains=LIST |
Toolchains (comma-separated; wildcards allowed) |
--scripts=LIST |
Limit which sconscripts run |
--parallel |
Parallel compile (-j sized to the machine) |
--offline |
Skip PyPI version check and remote repo updates |
--develop |
Prefer configured develop locations / package develop paths |
--show-test-output |
Print test process output |
--verbosity=exception |
Full stack traces on failure |
--save-conf / --show-conf |
Persist or inspect project configure.conf |
Coverage needs both flags: --cov does not imply --test. Typical coverage run:
cuppa -D --cov --testBenchmarks and generic runners: --benchmark, --run (and --force-* variants).
See the CLI reference for the full option list (storage, location matching, Boost, GitLab packages, Code::Blocks export, and more).
| Purpose | Default | Override |
|---|---|---|
| Build output | _build |
--build-root |
| Dependency trees | ~/.cuppa/dependencies |
--dependencies-root |
| Downloaded archives | ~/.cuppa/downloads |
--downloads-root |
The last two are shared between projects. --storage-root moves both together, so
--storage-root=_cuppa keeps all storage inside the project.
Layout under the build root:
<build_root>/<sconscript_path>/<toolchain>/<variant>/<target_arch>/<abi>/working/
<build_root>/<sconscript_path>/<toolchain>/<variant>/<target_arch>/<abi>/final/
If the script file is named sconscript, that filename segment is omitted.
| Term | Meaning |
|---|---|
| Methods | Env helpers such as Build, BuildTest, BuildWith, Coverage — variant- and toolchain-aware |
| Dependencies | Named compile/link (and optional fetch) packages: Boost, Qt, locations, registry packages |
| Profiles | Small reusable env tweaks (example: quad_float) |
| Variants / actions | How to compile (dbg/rel/cov) vs extra work (test/benchmark/run) |
| Toolchains | Concrete compilers discovered at configure time (gcc, gcc15, clang, clang21, …) |
Toolchains are discovered from the machine; supported aliases currently extend through gcc16 and clang22, plus MSVC vc / vc* on Windows (coverage is GCC/Clang only). Details: toolchains.
Save local defaults:
cuppa -D --develop --offline --save-conf- Project file:
configure.conf(or--use-conf=PATH) - Global file:
~/.cuppaconfig(see--save-global-confand related flags)
GitLab package auth typically uses GITLAB_REGISTRY_TOKEN or CI_JOB_TOKEN.
- Location dependencies —
cuppa.location_dependency(...)for header-only or VCS/archive libraries - Registry packages —
cuppa.package_dependency(...)andcuppa.packages.boost_package.define(...)for prebuilt GitLab generic packages
--develop does not replace a missing registry archive; the package must exist remotely or already be cached.
Canonical deep reference is the Antora site under docs/, including the full Integration tests section (generated sconstruct / sconscript for each pytest scenario).
Build locally (includes Lunr full-text search):
cd docs
npm ci
npm run buildOutput is written to _docs_build/site/. Open _docs_build/site/index.html.
- Keep
sconscriptfiles declarative - Encapsulate dependency and toolchain knowledge once, reuse everywhere
- Codify SCons best practices behind intent-oriented methods (
Build,BuildTest,BuildWith)
Historical talks and write-ups (prefer this README / the docs site / the code when details disagree):
- clearpool.io — posts tagged cuppa
- Managing C++ Build Complexity using Cuppa (ACCU 2016, A Quick Cuppa)
- Modern C++ Builds and ACCU Autumn Preview (Another Quick Cuppa)
- C++20, Cuppa and the ¡Three Asios! (includes Building Codes;
SContext-style bootstrapping described there is not upstream cuppa)