Starter for C++20 apps with a sample main. Reusable code goes in lib/ (compiled as a library and automatically linked).
- CMake ≥ 3.10
- Ninja (Makefile aborts if missing)
- C++20 compiler (ccache used if present)
make configure— configures (CMake) and compiles inbuild/.make run— runs the binary (after build).make watch– auto-build & run on source change (requiresfswatchorentr).
make run— compiles if needed and runs.make build— recompiles using the existing configuration.make debug/make release— build profiles (Debug adds-Werror, Release uses-O2).make install— installs to/usr/local/bin/app(often requiressudo).make watch— recompiles/runs on changes (requiresfswatchorentr).make format— runsclang-formaton sources/headers (requires clang-format in PATH).make add-module LIB_URL=<git repo>— adds a git submodule underlib/external/.make fetch-modules– fetch all git submodules underlib/external/.make clean— deletesbuild/.
src/main.cpp— example entrypoint.lib/— shared code; if the directory is empty, the library is not built.include/— public headers (version.hppincludes the example version).CMakelists.txt— project configuration: warnings, standard C++20,compile_commands.jsonenabled.Makefile— Ninja build shortcuts; check for Ninja before starting.
- You can delete the example files (
lib/,src/main.cpp,include/version.hpp, ect.) and CMake will continue configuring itself: the library is created only iflib/has sources. .gitmodulestracks external libraries added withmake add-module; a default example (lib/external/json.git) is included. Rungit submodule update --init --recursiveafter cloning to fetch them.
- A GitHub Actions workflow (.github/workflows/ci.yml) runs
make first-buildandmake buildon clean runners (Linux and macOS) to ensuremake first-buildworks on new machines and PRs. - A
.pre-commit-config.yamlis included to help keep the codebase tidy — install pre-commit locally and register hooks with:
pip install pre-commit
pre-commit install
pre-commit run --all-filesAdd a .clang-format file if you want a stable formatting policy used by pre-commit's clang-format hook.
- Add
.vscode/to.gitignoreif you want to ignore IDE files.
This repository is a template — lib/external/json.git is just an example. Here you'll find general guidelines and options for adding libraries to your project in a clean and repeatable way.
- Vendoring / Submodule (Simple, Reproducible)
- Add the library into
lib/external/<name>(e.g., withmake add-module, which creates a git submodule). - If the library contains a
CMakeLists.txt, add its target toadd_subdirectory(lib/external/<name>). - Pros: Reproducibility, offline work, dependency version control.
- Cons: Multiple files in the repo, manual updates.
- FetchContent (downloads at configure time)
- CMake downloads the dependency if it's not vendored.
- Example:
include(FetchContent)
FetchContent_Declare(
foo
GIT_REPOSITORY https://github.com/someone/foo.git
GIT_TAG v1.2.3
)
FetchContent_MakeAvailable(foo)
# then link: target_link_libraries(my_target PUBLIC foo::foo)- add_subdirectory (if the library is present locally)
- When the library is included in the repo (submodule or subfolder), use
add_subdirectory(lib/external/<name>)and link its target. - This is the default behavior of the template when it finds a submodule with CMake.
- find_package (search for packages installed on the system or managed via the package manager)
- If the library exposes a package config (e.g.,
fooConfig.cmake), usefind_package(foo REQUIRED)and thentarget_link_libraries(my_target PRIVATE foo::foo).
- Package manager (conan / vcpkg)
- For real-world projects, use conan or vcpkg for centralized dependency management.
- Integrate with CMake via toolchain or
find_packageand configure CI to use the same technique.
Personalize as you want, and enjoy programming!
Made with love by Ornitorink0 ☕️❤️