CLI tool
cpp-best-practices/cmake_template avatar
cpp-best-practices/cmake_template

cmake_template ships a C++ build preset, not just a build script

CMake for C++ Best Practices

1,818 stars203 forksCMakeUnlicense

At a glance

What is it?
cpp-best-practices/cmake_template is a GitHub template in the Unlicense that turns a new C++ repository into one with sanitizers, warnings as errors, clang-tidy, cppcheck, CPM dependencies and a CI matrix out of the box. Sanitizers and warnings-as-errors apply only when the build is the top-level project.
Who is it for?
Adopt cmake_template if you are starting a new C++ repository and want the CI, sanitizer and lint scaffolding decided once rather than assembled by hand, particularly if you want the same checks locally that run in CI. Do not adopt it as a build system to retrofit onto an existing CMake project, since its defaults are written for a repository created from the template, and do not expect the warning settings to apply when your project is consumed as a subdirectory.
Can I use it commercially?
Yes. Unlicense is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 67 days ago.
What is it written in?
Mainly CMake, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The top-level project condition changes every default

The README introduces its default behaviour with a qualifier that is easy to skim past: the defaults apply "By default (when building as the top-level project)".

That single clause shapes the template. Address Sanitizer and Undefined Behavior Sanitizer enabled where possible. Warnings as errors. clang-tidy and cppcheck static analysis. CPM for dependencies.

The reason for the condition is ordinary CMake structure. A project that is the top-level build is a project you own, so turning warnings into build failures is defensible. A project consumed as a subdirectory via `add_subdirectory` or `FetchContent` belongs to someone else's build, and failing their compile because of your warning flags would be hostile. The template separates the two cases.

The practical consequence for you: if you clone this and wire it into a larger build, you may find the strict settings silently inactive, with no error to tell you. That is correct behaviour and still a surprise the first time it happens.

The requirements section is deliberately short, which is a good sign for a build template: it needs cmake and a compiler. Nothing else is a prerequisite, because the dependencies come in through CPM rather than a system package manager.

Creating a repository from the template, and the cleanup workflow you have to wait for

The getting started path is GitHub's template mechanism rather than a clone-and-edit.

Click the green `Use this template` button near the top of the page, which takes you to GitHub's 'Generate Repository' page. Fill in a repository name and short description, then click 'Create repository from template'. That creates a new repository in your account, prepopulated with the contents of this project.

Then one instruction catches people out: after creating the project, wait until the cleanup workflow has finished setting up your project and committed the changes. A repository created from this template is not ready the instant it appears. There is automation that renames and reconfigures it, and pushing your own commits before it finishes means fighting it.

Once it settles, you clone your own new repository:

bash
git clone https://github.com/<user>/<your_new_repo>.git

The three detail documents are separate files rather than sections of the main README: `README_dependencies.md` for dependency setup, `README_building.md` for building details, and `README_docker.md` for Docker. There is also a `README_design.md` at the repository root that the main README does not link, so if you want the rationale rather than the steps, that is where to look.

Presets and split options files, which is where the structure lives

The repository layout shows how the template organises its CMake logic, and it is a more interesting design than a single `CMakeLists.txt`.

At the root there are `CMakeLists.txt`, `CMakePresets.json`, `Dependencies.cmake` and `ProjectOptions.cmake`. Presets give named build configurations that both humans and CI can select consistently, which is how the same flag set gets applied in a local shell and on a CI runner without drifting.

Splitting dependencies and options out of the main script is the other half. `ProjectOptions.cmake` holds the project-wide switches, `Dependencies.cmake` holds dependency acquisition, and `CMakeLists.txt` composes them. `configured_files/` suggests template substitution into generated headers, a common pattern when version numbers and build metadata have to reach the C++ source without a configure step at runtime.

Quality tooling is committed as configuration, not instructions: `.clang-format`, `.clang-tidy` and `.cmake-format.yaml` at the root, plus `gcovr.cfg` for coverage reporting. That last one pairs with the codecov badge in the README.

The `cmake/` directory holds the helper modules, and `.devcontainer/` is present, which means a container-based development environment is defined even though the Docker instructions live in a separate document. `out/` in the repository root indicates a build output directory is expected at that location.

Test types: unit, fuzz and constexpr, each with its own home

Three kinds of testing are wired up, and the directory layout separates them.

`test/` holds the unit tests, with the README pointing at the Catch2 tutorial for the framework's usage. `fuzz_test/` is a separate top-level directory for fuzz targets, with the README linking the libFuzzer tutorial.

The constexpr example is the interesting one. It sits alongside unit and fuzz testing as a distinct category, which in practice means a compile-time test target that checks values are computable at compile time rather than only correct at runtime. For a template aimed at best practices, that is a deliberate signal about where you should be putting assertions.

`include/` and `src/` are the ordinary split between headers and implementation, and `web/` sits at the root for the WebAssembly target.

The CI side is described in the README as a large GitHub action testing matrix, with badges for CI, codecov and CodeQL. The repository also carries `.gitlab-ci.yml`, so the same project has a GitLab CI definition alongside the GitHub Actions workflows in `.github/`. CodeQL analysis has its own workflow badge, so static security analysis runs in CI as well as the compile-time linting.

WebAssembly with GitHub Pages deploys main, develop and tags to three paths

The WebAssembly support is more than a compiler target, because the README describes a deployment scheme with three distinct paths.

It says that if you enable GitHub Pages in a project created from this template, you will have a working example. The live demo links are the template's own: the main branch deploys to the root, develop to `/develop/`, and tags to `/tagname/`.

Three deployment slots from one configuration is a considered choice. It gives you a live build of your default branch, a staging build for the develop branch, and a permanent URL per release tag, which is what makes a demo link in a bug report meaningful rather than pointing at whatever the default branch happens to be today.

The template pairs WebAssembly build support with automatic GitHub Pages deployment, including separate deployment paths for the main branch, the develop branch and tags.

CPM for dependencies, and the documentation split that follows from it

CPM is the dependency mechanism the template selects, listed among the top-level defaults alongside the sanitizers and linting.

CPM fetches dependency sources at configure time rather than requiring a system package or a submodule. For a template that needs to work on a fresh machine with only cmake and a compiler installed, that is the mechanism that makes the requirement list honest: nothing needs to be installed before the first configure.

The dependency setup instructions are in `README_dependencies.md` rather than the main README, and the main README links to it as Dependency Setup. Similarly Building Details and Docker have their own documents.

That split is worth a comment. A build template has three audiences with different questions: a new user who wants to build once, a contributor who wants to know how a flag is set, and someone deploying to a container. Putting all of that in one README produces either a wall of text or a README that omits the answers. Splitting into three documents keeps the entry page short enough to be read.

What the README does not document here is the CPM cache configuration, the offline configure behaviour, or how dependencies are pinned. Those are in the dependencies document, which is not reproduced in the main file.

Unlicensed for code, one tag from 2022, and what the badges do not tell you

Two maintenance facts frame any decision here.

The licence is Unlicense, which is a public domain dedication rather than a permissive licence with attribution requirements. The repository is under the `cpp-best-practices` organisation and carries an `org` name, so it is presented as a shared starting point rather than one person's project.

The release record is thin. The repository has a single release tag named `test_package`, described as a test of build and packing, dated 2022-03-16. There is no versioned release series, so there is nothing to pin and no upgrade path between tagged versions. You take the `main` branch as it is when you generate the repository, and you own it from then on.

That is consistent with what a template is, and it is worth stating plainly: the template is a starting point you fork, not a dependency you track. Once generated, your repository diverges immediately, so upstream changes reach you only if you watch for them.

The last push was on 2026-08-17, so the template is being worked on, but the badges tell you nothing about your build: the CI badge reflects the template's own pipeline, and the codecov and CodeQL badges describe analysis of the sample application. Once you generate a repository, all three become yours and mean whatever your code makes them mean.

Editorial conclusion

Adopt cmake_template if you are starting a new C++ repository and want the CI, sanitizer and lint scaffolding decided once rather than assembled by hand, particularly if you want the same checks locally that run in CI. Do not adopt it as a build system to retrofit onto an existing CMake project, since its defaults are written for a repository created from the template, and do not expect the warning settings to apply when your project is consumed as a subdirectory. Verify first that your compiler supports the sanitizer flags on your target platform, since the README qualifies them with where possible, and that the CI matrix covers the platforms you actually ship.

Frequently asked questions

How do I create a project from cmake_template?

Click the green `Use this template` button to reach GitHub's Generate Repository page, fill in a name and description, then click 'Create repository from template'. After that, wait for the cleanup workflow to finish setting up the project before pushing your own commits.

What does cmake_template enable by default?

When building as the top-level project, Address Sanitizer and Undefined Behavior Sanitizer where possible, warnings as errors, clang-tidy and cppcheck static analysis, and CPM for dependencies. It requires only cmake and a compiler.

Which testing types does cmake_template set up?

A basic CLI example plus examples for fuzz, unit and constexpr testing. Unit tests are in `test/` using Catch2, fuzz targets live in `fuzz_test/` using libFuzzer, and the WebAssembly target builds from `web/`.

How does the WebAssembly build get deployed?

If you enable GitHub Pages, the `main` branch deploys to the root, `develop` to `/develop/`, and tags to `/tagname/`, giving a live example for each case. The sample application uses FTXUI.

What licence is cmake_template released under?

The Unlicense, which is a public domain dedication. The licence file sits at the repository root alongside a CMakeLists.txt, ProjectOptions.cmake and Dependencies.cmake.

Where are the build and dependency instructions?

In separate documents rather than the main README: `README_dependencies.md` for dependency setup, `README_building.md` for building details, and `README_docker.md` for Docker. A `README_design.md` also exists at the repository root.

Official sources

  1. cpp-best-practices/cmake_template on GitHub
  2. Issues
  3. License: Unlicense
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/cpp-best-practices-cmake-template.svg)](https://hysenlabs.com/projects/cpp-best-practices-cmake-template)

Was this useful?