10 KiB
BreezeCLI
breeze: a global command line tool for projects built on the breeze SDK (the CMake template in breeze/).
It is written with CLIForge and is itself a breeze project: build it with
breeze/scripts/build.sh (or, once you have a breeze, breeze build).
Three things, kept apart on purpose:
| What it is | Where it lives | Versioned by | |
|---|---|---|---|
| CLI | this program; one per machine, any number of versions installed | ~/.breeze/cli/<version>/ |
its own version (breeze cli version) |
| SDK | the template: breeze/, replaced as a whole on an update |
in each project | breeze/VERSION (breeze sdk version) |
| Tools | extensions a project installs from a repository | <project>/.breeze/tools/<id>/ |
the tool's tags |
The CLI is global and the SDK is per project, so one CLI works on projects that are on different SDK versions, and on
the layouts before breeze/ existed (see Older SDKs).
Commands
Run breeze --help, or breeze <command> --help, for the exact options. The commands inside a project find it by
walking up from the current directory.
Projects and modules
breeze project new <name> [--id] [--sdk] a new project (no demo code, one executable module to start from)
breeze project version|name|id [--set] the project's version, name (CMake project()) and id
breeze add exec|obj|test|example <name> [--id] [--deps ...]
breeze add lib <name> (--static|--shared) [--id] [--deps ...]
breeze delete <id> [--yes] refuses while another module depends on it
breeze rename <id> [--name] [--id] renames the directory and/or id, fixing the DEPENDS that name it
breeze ls [--filter] [--exec] [--obj] [--lib] [--test] [--example] [--shared] [--static]
breeze deps of <module> [--recursive] what it depends on
breeze deps on <module> [--recursive] what depends on it
Modules are read from, and written as, the add_*_module(...) calls in each CMakeLists.txt; the CLI changes only
what it must (a rename touches the id, the directories and the DEPENDS entries, nothing else in the files). Ids default
to <name in snake case> plus _exe, _lib, _obj, _test or _example; --deps takes modules (by id or
directory) or any other CMake target (fmt::fmt).
Building and running
breeze setup [--required|--all]
breeze build [-P platform] [-A arch] [-C compiler] [-M mode] [-j jobs] [-p preset] [--cargs ...] [--bargs ...] [--no-configure]
breeze install [the same, and --no-build]
breeze run [id] [-p/-P/-A/-C/-M ...] [-x arguments ...]
breeze docs
breeze clean [--no-build] [--docs]
breeze defaults build platform|arch|compiler|preset|mode [--set <value>]
breeze defaults run [--set <id>]
These drive the SDK's own scripts (breeze/scripts/*.sh, .bat on Windows), so the environment they set up (the
pinned Ninja, the MSVC environment) is the one used. A platform, architecture and compiler name a preset
(-P linux -A x64 -C gcc is linux-x64-gcc, ignoring case and punctuation: ClangCl finds clang-cl); whatever is
missing comes from the project's defaults, then this machine. --set none clears a default. Defaults are kept in
.breeze/defaults.json, meant to be committed.
--cargs and --bargs take everything up to the next option, dashes included:
breeze build --cargs -DBUILD_TESTS=ON -DBUILD_EXAMPLES=ON -j 8. --bargs (and --no-configure) run
cmake --build on the directory the scripts configured, which the SDK's scripts have no way to do; so there must be a
configured build first, and on Windows these two are not supported yet (the MSVC environment comes from the scripts).
-j reaches the build through CMAKE_BUILD_PARALLEL_LEVEL.
run with no id runs breeze defaults run, or the project's only executable. -M is accepted for run and ignored:
the SDK keeps one build directory per preset.
The CLI itself
breeze cli version | ls
breeze cli install <version> | pick <version> | uninstall <version>
Versions live in ~/.breeze/cli/<version>/ ($BREEZE_HOME moves ~/.breeze); cli/current names the picked one.
Every other command first hands itself over to the picked version, so whichever breeze your shell finds is the
picked one, and cli ... commands always run in the version you started. Put ~/.breeze/bin on PATH: the first
cli install puts a copy of breeze there. Installing this program's own version needs nothing else:
./breeze cli install $(./breeze cli version)
Other versions come from the CLI source: breeze config cli-source --set <URL or directory>, expected to hold
<version>/breeze-<platform>-<arch>[.exe] (platform linux, macos, windows; arch x64, arm64, arm32, x86).
A URL is downloaded with curl. What is installed must run and say it is that version, or nothing is kept.
SDK versions
breeze sdk version | update | upgrade | migrate <version>
An SDK version is a snapshot of the whole template: breeze/ (the SDK proper) plus the files a project starts from.
Versions come from the SDK source: breeze config sdk-source --set <git repository (URL or path) | directory>.
A repository's tags are the versions (v1.2.0 or 1.2.0); a directory has one subdirectory per version
(1.0.0/, 1.1.0/). The version of an SDK is the one line in breeze/VERSION, which the repository's tag should match.
updatelooks at the source and says what is there, and whether this project is behind.upgrademoves to the newest version with the same major version.migrate <version>moves to exactly that version, any way, across majors;latestis the newest release.
Moving replaces breeze/ (the old one is kept in .breeze/backup/), adds to project/Configuration.cmake any setting
the new SDK has and the project's file lacks, and says which dot files (.clang-format, ...) now differ from the
SDK's. Nothing else of the project is touched.
Tools
breeze tool install <repo> | uninstall <id> | update <id> | upgrade <id> | migrate <id> <version> | ls
breeze tool <id> <arguments...>
A tool is a git repository (or, while it is being written, a directory) with a breeze-tool.json at its root:
{ "id": "resembed", "version": "1.0.0", "description": "Embeds resources", "entry": "bin/resembed.sh" }
entry may be { "posix": "...", "windows": "..." }. Installed, it is copied into .breeze/tools/<id>/ and recorded in
.breeze/tools.json (commit both); breeze tool <id> ... then runs the entry with those arguments, in the project's
directory, with BREEZE_PROJECT_ROOT, BREEZE_SDK_DIR, BREEZE_SDK_VERSION, BREEZE_TOOL_ID, BREEZE_TOOL_DIR,
BREEZE_CLI, BREEZE_HOME and BREEZE_EDITOR set. Everything after the id belongs to the tool, --help included, and its
exit code is the CLI's. So breeze tool san asan enable <module> is whatever the san tool does with
asan enable <module>. install, uninstall, update, upgrade, migrate and ls can't be tool ids.
Configuration
breeze config editor [--set] the editor tools open files with (BREEZE_EDITOR in their environment)
breeze config sdk-source [--set] where SDK versions come from
breeze config cli-source [--set] where CLI versions come from
Kept in ~/.breeze/config.json; BREEZE_EDITOR, BREEZE_SDK_SOURCE and BREEZE_CLI_SOURCE in the environment win.
--set none clears one.
Older SDKs
The CLI asks each project's SDK where things are instead of assuming:
- breeze/ layout (with or without
breeze/VERSION): everything above. - The flat layout (
scripts/,cmake/,Configuration.cmakeat the root):ls,deps,add,rename,delete,project name|version|id,build,run,install,cleanwork through that layout's scripts and presets; what an old SDK lacks is said when asked for (add objon an SDK without objects modules; a preset on one without presets).breeze sdk migrate <version>moves a flat project to thebreeze/layout: the oldCMakeLists.txt,Configuration.cmake,cmake/,scripts/and.githooks/go to.breeze/backup/, and the project's name, version, description, languages, C++ standard and any setting it had changed go intoproject/Configuration.cmake. The project's ownREADME.md, sources and dot files stay.
Building and testing
breeze/scripts/build.sh --preset linux-x64-gcc --cargs -DBUILD_TESTS=ON
out/build/linux-x64-gcc/bin/tests/core_tests # unit tests
tests/e2e.sh # drives the built program through every command group
tests/e2e.sh needs cmake, a compiler and git, and no network: it builds its own SDK source, tool and releases in a
temporary directory.
Layout: source/CLIForge (the command line library), source/BreezeCore (everything the commands do; unit tested),
source/Breeze (the breeze executable: command registration only), source/tests/CoreTests.
nlohmann/json is used for the files the CLI keeps: an installed 3.11 or newer is found, else the release is fetched (pinned by hash) when you configure.
Notes on CLIForge
CLIForge is used as it came, with these changes to source/CLIForge, to be taken back into the library:
CliError::kind()returnedkind()(endless recursion); it now returnsm_kind.#pragma onceremoved from the four.cppfiles (a compiler warning each).
Things to know when writing commands with it: an action's return value is ignored (so Commands.cpp leaves exit
codes in breeze::cli::exitCode() for main()); an exception that is not a CliError leaves Engine::run; a token
starting with - is always read as an option (which is why main() rewrites the values of --cargs, --bargs and
-x to the --cargs=-DX=1 form, see breeze/Arguments.hpp); parameters are required, so run [id] is two commands.
Status
Built and tested on Linux with gcc and clang (x64) and gcc for arm64 (run under qemu): the unit tests and the 94 checks
of tests/e2e.sh pass. Downloading a CLI release over HTTP was tried against a local web server with curl; git
sources were tried with local repositories only. MinGW compiles the Windows code (process creation, cmd.exe scripts,
paths) but nothing has been run on Windows, and nothing has been built on macOS.