Add canon add target, add test, add dep and doctor
- add target lib|exe <name>: another library or executable in a source directory named after it (P1204R0's rule applied per target); a new executable links the project's library - add test <name>: tests/<name>/driver.cpp for a library, or a run of an executable, with --arg and --expect - add dep <dependency>: link a library of this project (no cycles, no executables) or an installed package's imported target such as fmt::fmt, adding its find_package() - doctor: read-only check of the files against .canon.toml and the P1204R0 layout; errors for missing declared files or broken markers, warnings for unbuilt sources, undeclared tests, a hand-edited managed block, .h/.cc extensions and include/ or src/ directories - every add command takes --target; the CLI rejects options a command does not take - manifest: packages, test args, and validation of target names, shared source directories and dependencies - templates moved to canon/templates.hpp - tests: multi-target and exe-tests scenarios; every scenario ends with canon doctor; CANON_CHECK accepts expressions containing commas; the CLI test no longer reads a destroyed temporary Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,24 +1,43 @@
|
||||
# canon
|
||||
|
||||
Scaffolds C++ projects that follow [P1204R0](https://wg21.link/p1204r0)
|
||||
(Canonical Project Structure), then keeps adding to them. Written in C++23, no
|
||||
third-party dependencies.
|
||||
(Canonical Project Structure), keeps adding to them, and checks them. Written in
|
||||
C++23, no third-party dependencies.
|
||||
|
||||
```bash
|
||||
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 # libhello/hello/hello.{hpp,cpp,test.cpp} + tests/basics
|
||||
canon new exe hello # hello/hello/hello.cpp
|
||||
canon new exe hello --dir ~/src # create the project somewhere else
|
||||
|
||||
cd libhello
|
||||
|
||||
# Modules: related .hpp/.cpp/.test.cpp files
|
||||
canon add module core # hello/core.hpp, core.cpp, core.test.cpp
|
||||
canon add module details/utility # hello/details/utility.*, namespace hello::details
|
||||
canon add module parser --no-test # no .test.cpp ...
|
||||
canon add unit-test parser # ... until you want one
|
||||
|
||||
canon add module core --dry-run # any command: show the changes, write nothing
|
||||
# Targets: more libraries or executables, each in its own source directory
|
||||
canon add target exe hello-cli # hello-cli/hello-cli.cpp, links libhello
|
||||
canon add module args --target hello-cli
|
||||
canon add target lib libextra # extra/extra.{hpp,cpp,test.cpp}
|
||||
|
||||
# Functional tests
|
||||
canon add test edge-cases # tests/edge-cases/driver.cpp, linked with libhello
|
||||
canon add test greets --target hello-cli --arg Paul --expect "Hello, Paul!"
|
||||
|
||||
# Dependencies
|
||||
canon add dep libextra # libhello links libextra
|
||||
canon add dep fmt::fmt --target hello-cli # find_package(fmt) + link
|
||||
canon add dep Boost::filesystem --package Boost # when the package name differs
|
||||
|
||||
# Checks
|
||||
canon doctor # compare the files with .canon.toml and P1204R0
|
||||
|
||||
canon add module core --dry-run # any add command: show the changes, write nothing
|
||||
```
|
||||
|
||||
`add` commands work from any directory inside the project. Every generated
|
||||
`add` and `doctor` work from any directory inside the project. Every generated
|
||||
project builds and passes its tests out of the box:
|
||||
|
||||
```bash
|
||||
@@ -50,19 +69,44 @@ The block between `# >>> canon:managed >>>` and `# <<< canon:managed <<<` in
|
||||
updates the manifest and re-renders the whole block, so:
|
||||
|
||||
- anything **outside** the block is yours and is never touched;
|
||||
- anything you edit **inside** the block is replaced on the next `add`;
|
||||
- anything you edit **inside** the block is replaced on the next `add`
|
||||
(`canon doctor` warns when the block has been edited);
|
||||
- `.canon.toml` is rewritten by canon, so comments you add to it are dropped.
|
||||
|
||||
canon reads `.canon.toml` strictly: unknown keys (usually typos) are errors
|
||||
canon reads `.canon.toml` strictly: unknown keys (usually typos), invalid
|
||||
names, targets sharing a source directory and links to executables are errors
|
||||
with a line number.
|
||||
|
||||
### Targets and P1204R0
|
||||
|
||||
P1204R0 describes a project as one library or one executable with a source
|
||||
directory named after it. `canon add target` applies the same rule to each extra
|
||||
target: `libextra` lives in `extra/`, `hello-cli` in `hello-cli/`. A new
|
||||
executable links the project's library automatically; a new library is linked
|
||||
explicitly with `canon add dep`.
|
||||
|
||||
### doctor
|
||||
|
||||
`canon doctor` never changes anything. It reports:
|
||||
|
||||
- **errors** (exit status 1): files `.canon.toml` declares that are missing, and
|
||||
a `CMakeLists.txt` without valid managed-block markers;
|
||||
- **warnings**: `.cpp` files in a source directory that no target builds, unit
|
||||
or functional tests that are not declared, a hand-edited managed block,
|
||||
`.h`/`.cc`-style extensions, and `include/` or `src/` directories.
|
||||
|
||||
Hidden directories and top-level build output (`build*`, `cmake-build-*`) are
|
||||
skipped.
|
||||
|
||||
| File | Role |
|
||||
|---|---|
|
||||
| `canon/canon.cpp` | `main`: wires the command line to the generators and executor |
|
||||
| `canon/cli.*` | argument parsing |
|
||||
| `canon/canon.cpp` | `main`: wires the command line to the generators, executor and doctor |
|
||||
| `canon/cli.*` | argument parsing, including which options each command takes |
|
||||
| `canon/name.*` | naming rules (`lib` prefix, stem, namespace, keywords) |
|
||||
| `canon/generate.*` | the manifest and plan for `canon new`; project templates |
|
||||
| `canon/add.*` | the plans for `canon add module` and `canon add unit-test` |
|
||||
| `canon/generate.*` | the manifest and plan for `canon new` |
|
||||
| `canon/add.*` | the plans for every `canon add` command |
|
||||
| `canon/doctor.*` | the checks behind `canon doctor` |
|
||||
| `canon/templates.hpp` | the contents of generated files |
|
||||
| `canon/project.*` | finds and loads an existing project |
|
||||
| `canon/manifest.*` | the manifest model, written to and read from TOML |
|
||||
| `canon/toml.*` | the small TOML subset canon reads and writes |
|
||||
@@ -75,7 +119,8 @@ with a line number.
|
||||
|
||||
- **Unit tests**: `canon/<unit>.test.cpp`, next to the code they cover.
|
||||
- **Scenarios**: `tests/scenarios.cmake` runs command sequences (for example
|
||||
`new lib` followed by several `add` commands) that both of the following use.
|
||||
`new lib` followed by several `add` commands, including ones that must fail)
|
||||
and ends each with `canon doctor`. Both of the following use them.
|
||||
- **Golden tests**: `tests/golden/<scenario>/` holds the exact expected result of
|
||||
each scenario. After an intentional template change, regenerate the copies and
|
||||
review the diff:
|
||||
@@ -87,7 +132,7 @@ with a line number.
|
||||
|
||||
1. ✅ `new lib`, `new exe`, plan/apply, `--dry-run`, manifest
|
||||
2. ✅ `add module`, `add unit-test`, reading `.canon.toml`, managed-block updates
|
||||
3. `add target`, `add test`, `add dep`, `doctor` (check a project against P1204R0)
|
||||
3. ✅ `add target`, `add test`, `add dep`, `doctor`
|
||||
4. User template overrides
|
||||
|
||||
## License
|
||||
|
||||
Reference in New Issue
Block a user