Keeps LICENSE from the server and the full README, which now links to it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
canon
Scaffolds C++ projects that follow P1204R0 (Canonical Project Structure). Written in C++23, no third-party dependencies.
canon new lib libhello # library: libhello/hello/hello.{hpp,cpp,test.cpp} + tests/basics
canon new exe hello # executable: hello/hello/hello.cpp
canon new lib libhello --dry-run # show the plan, write nothing
canon new exe hello --dir ~/src # create the project somewhere else
Every generated project builds and passes its tests out of the box:
cd libhello
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure
Build canon
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failure
cmake --install build --prefix ~/.local # puts canon in ~/.local/bin
How it works
Generators never touch the filesystem. They return a plan (a list of
make_directory / create_file operations) and the executor applies it.
The executor checks every operation first, so a conflict writes nothing, and
--dry-run is just "check, don't write". canon never overwrites files.
Each project gets a .canon.toml manifest recording what canon declared.
The block between # >>> canon:managed >>> and # <<< canon:managed <<< in
CMakeLists.txt is rendered entirely from that manifest. Upcoming canon add
commands will update the manifest and re-render the block, so running a command
twice gives the same result. Anything outside the block belongs to you.
| File | Role |
|---|---|
canon/canon.cpp |
main: wires the command line to the generators and executor |
canon/cli.* |
argument parsing |
canon/name.* |
project name rules (lib prefix, stem, namespace) |
canon/generate.* |
builds the manifest and plan for canon new; file templates |
canon/manifest.* |
the manifest model and its TOML output |
canon/cmake.* |
renders CMakeLists.txt and the managed block from a manifest |
canon/plan.* |
operations and plans (pure data) |
canon/executor.* |
checks and applies a plan |
canon/template.* |
{{key}} substitution |
Tests
- Unit tests:
canon/<unit>.test.cpp, next to the code they cover. - Golden tests:
tests/golden/holds the exact expected output forlibhelloandhello. After an intentional template change, regenerate the copies and review the diff:cmake -DCANON=build/canon -DWORK_DIR=build/tests/golden -DUPDATE=ON -P tests/golden/check.cmake - End to end:
tests/e2e/scaffolds both kinds, then configures, builds and runs their tests. Skip it withctest -LE e2e.
Roadmap
- ✅
new lib,new exe, plan/apply,--dry-run, manifest add module,add unit-test: read.canon.tomland re-render the managed blockadd target,add test,add dep,doctor(check a project against P1204R0)- User template overrides
License
MIT, see LICENSE.