Open-source project
StableCoder/cmake-scripts avatar
StableCoder/cmake-scripts

cmake-scripts: sanitizers, coverage and fuzzing as one include away

Easy-to-add enhancements for any C/C++ CMake project. Including AFL fuzzing, code-coverage, Thread/Address/Leak/Address/Undefined sanitizer instrumentation, compilation of GLSL shaders and more.

670 stars68 forksCMakeApache-2.0

At a glance

What is it?
StableCoder's cmake-scripts is a set of drop-in CMake files that add sanitizer builds, code coverage, AFL fuzzing, Doxygen, clang-tidy and GLSL shader compilation to any C or C++ project, with the emphasis on being trivially includable rather than on any one feature.
Who is it for?
cmake-scripts fits a C or C++ team that wants sanitizers, coverage and static analysis wired into an existing CMake build without rewriting it, since every capability is a separate .cmake file that is included and configured rather than a framework you adopt, and it fits a project that already uses CMake and wants AFL fuzzing instrumentation on the same targets.
Can I use it commercially?
Yes. Apache-2.0 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 86 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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A collection of files, not a framework

cmake-scripts is a collection of scripts that expand what is possible when building software with CMake, by making some things easier and otherwise adding new build types. The design choice that defines the project is that each capability lives in its own standalone .cmake file at the repository root, and you include the one you want. The top level lists sanitizers.cmake, code-coverage.cmake, afl-fuzzing.cmake, compiler-options.cmake, dependency-graph.cmake, doxygen.cmake, formatting.cmake, glsl-shaders.cmake, link-time-optimization.cmake, prepare-catch.cmake and tools.cmake, plus c-standards.cmake and c++-standards.cmake for language standard selection. There is no top-level CMakeLists.txt to adopt and no project to conform to. The project describes the philosophy as being tragically simple to add into any project using CMake, which is a more honest way of saying that the value is in the low cost of integration rather than in any capability being unique.

Sanitizers, and the check the module does for you

The sanitizers module covers the usual LLVM and GCC runtime checkers. LeakSanitizer detects memory leaks, where memory is allocated and never deallocated, causing a program to slowly consume more memory and eventually crash. AddressSanitizer is a fast memory error detector for out of bounds accesses to heap, stack and global, use after free, use after return, use after scope, double free, invalid free, and leaks. ThreadSanitizer detects data races in multi-threaded code. UndefinedBehaviourSanitizer detects listed undefined behaviour such as misaligned or null pointers, signed integer overflow, floating point conversions that would overflow the destination, division by zero and unreachable code. MemorySanitizer detects uninitialized reads, and Control Flow Integrity targets forms of undefined behaviour that could let an attacker subvert control flow. Enabling them is a single call with the sanitizer names, and the module checks for the availability and compatibility of the combined flags before applying them to following compile targets.

cmake
# apply address and leak sanitizers
add_sanitizer_support(address leak)
# future targets will be compiled with '-fsanitize=address -fsanitize=leak'

Per-sanitizer flags, from script or from the command line

Compile options can be set per sanitizer rather than globally, and there are three ways to do it. The first is a function call before enabling the sanitizers.

cmake
# set custom options that will be applies with that specific sanitizer
set_sanitizer_options(address -fno-omit-frame-pointer)

add_sanitizer_support(address leak)
# future targets will be compiled with '-fsanitize=address -fno-omit-frame-pointer -fsanitize=leak'

The second is setting the named variable, either in a script or on the command line, which is how you would set it in a CI job.

cmake
# CMake called from command line as `cmake -S . -B build -D SANITIZER_ADDRESS_OPTION='-fno-omit-frame-pointer'`

add_sanitizer_support(address)
# future targets will be compiled with '-fsanitize=address -fno-omit-frame-pointer' 
# despite no call to `set_sanitizer_options`

The third is a DEFAULT option, used so that flags coming from an external source are not overwritten, which means the flags are only used if none have been set previously. That is the variant to reach for when a downstream user of your project has already configured the flags and you do not want your defaults to stomp on them.

Code coverage that can be scoped to one target or to all of them

The coverage module is the most configurable of the set, and the documentation walks through four usage patterns rather than one. All targets can be instrumented through a global command, or individual targets through target commands. A single target can be instrumented with a regex pattern of files excluded from the report, so you can leave third party headers out of the numbers. A target can be added to the ccov and ccov-all aggregate targets explicitly, or all targets can be hooked so they participate automatically. The distinction between the ccov and ccov-all targets is the one to understand, because the coverage module adds several new targets to your build and a plain build invocation can therefore start doing more than it used to. The example/ directory in the repository is arranged to match those four cases, with directories named for all, target, public, hook and code-coverage-all, so you can read a working configuration instead of reconstructing one from the documentation.

AFL fuzzing instrumentation as a separate opt-in

afl-fuzzing.cmake is a separate module from the sanitizers one, and that separation is deliberate rather than incidental, since the two instrument for different purposes. The sanitizers module adds runtime checks that report problems while your program executes its normal path, while the fuzzing module adds the instrumentation AFL needs to drive an input and observe coverage, so the fuzzer knows which new states it has reached. For a project with a parser, a protocol handler or anything else that takes untrusted input, having the instrumentation already in the build means the fuzzing setup is a matter of pointing AFL at an existing binary rather than a separate build system. The module has its own usage section in the documentation. It is worth reading together with the sanitizer module, since a common setup is to fuzz with instrumentation that also checks memory errors, but the two are kept in different files so you take only what you need.

Static analysis, formatting and documentation tooling

The tools module collects the analysis programs, with clang-tidy, include-what-you-use and cppcheck each documented. The formatting module has clang-format and cmake-format, which covers the two languages in a CMake project, the C++ sources and the build files themselves, and that pairing is a small detail that saves time, because a project that formats its C++ but not its CMakeLists is only half formatted. The doxygen module takes an optional ADD_TO_DOC flag, an INSTALLABLE flag, a PROCESS_DOXYFILE flag, a target name, an output directory, an install path and a Doxyfile path, so documentation generation can be part of the normal build or only run on demand. The dependency-graph module produces a graph of the target dependencies, taking a required output type and optional flags for adding to the dependency graph, the target name and the output directory, which is the quickest way to answer the question of why a rebuild of one library dragged in half the tree.

GLSL shaders and the Catch test framework

glsl-shaders.cmake handles targeted compilation of shader files, with a required target name and optional lists of interface, public and private files, plus compile options. That structure mirrors how CMake itself treats headers, which is the point: a shader is a build artefact with a dependency relationship, and treating it as one means a change to a shader triggers the right rebuild rather than being discovered at runtime. The prepare-catch.cmake module prepares the Catch test framework, with options for a pre-compiled Catch, the older Catch1 layout, and cloning the framework. Linking a test framework into a build is a recurring source of friction, since it usually means fetching a repository at configure time or vendoring a directory, and having a module that handles the fetch means the same approach applies to every project that includes it. There are also c-standards.cmake and c++-standards.cmake for setting the language standard, and link-time-optimization.cmake for turning on LTO and IPO.

Where this fits, and what it does not replace

The honest scope statement is that this is a toolbox of conveniences, not a build system, and the value depends entirely on how much of your build is already CMake. If your project is CMake-based, each module is an afternoon of integration that buys real checking: sanitizers that catch the memory bug you would otherwise ship, coverage numbers that show which parts of the code the tests actually reach, and fuzzing instrumentation on targets you already have. If your project is not CMake-based, there is nothing here to help, since the integration is CMake include statements and CMake targets. There is also a maintenance dimension worth thinking about. The project versions its releases by month, and the releases listed here are 25.08 from August 2025, 24.08.1 from August 2024 and 24.04.1 from April 2024, so the newest release is not recent relative to today, even though the last push to the repository was on 2026-07-29. The licence is Apache-2.0, which is permissive enough to vendor into a commercial project.

Editorial conclusion

cmake-scripts fits a C or C++ team that wants sanitizers, coverage and static analysis wired into an existing CMake build without rewriting it, since every capability is a separate .cmake file that is included and configured rather than a framework you adopt, and it fits a project that already uses CMake and wants AFL fuzzing instrumentation on the same targets. It does not fit a team that wants a single opinionated build system, because there is nothing here to replace CMake, and it does not fit a codebase that has not yet chosen a compiler, since the sanitizer and tooling modules assume a Clang or GCC toolchain is present. Before you include anything, read the module you are about to use end to end, because the coverage module alone adds several aggregate targets that change what a plain build produces, and check the release you pick against your CMake version, since the project versions its releases by month and the newest one listed here is 25.08 from August 2025.

Frequently asked questions

How do I enable sanitizers with cmake-scripts?

Include sanitizers.cmake and call add_sanitizer_support with the sanitizer names, for example add_sanitizer_support(address leak), and the module checks the availability and compatibility of the combined flags before applying them to following compile targets. Per-sanitizer options can be set with set_sanitizer_options or through the named SANITIZER_ variable.

What code coverage modes does the cmake-scripts coverage module offer?

The documentation covers four patterns: all targets instrumented through a global command, individual targets through target commands, a single target instrumented with a regex pattern of files excluded from the report, and a target added to the ccov and ccov-all aggregate targets, with a fourth option to hook all targets automatically.

Which static analysis and formatting tools does cmake-scripts cover?

The tools module covers clang-tidy, include-what-you-use and cppcheck, and the formatting module covers clang-format for C++ and cmake-format for the CMake files themselves. There are also modules for Doxygen documentation, dependency graph output, C and C++ standard selection, link time optimization, AFL fuzzing instrumentation and preparing the Catch test framework.

How do I add AFL fuzzing to a project using cmake-scripts?

The afl-fuzzing.cmake module is included separately from the sanitizers module and has its own usage section, adding the instrumentation AFL needs to drive inputs and observe coverage so a fuzzer can find new states. The example directory in the repository contains working configurations to read.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. Releases
  5. StableCoder/cmake-scripts on GitHub
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/stablecoder-cmake-scripts.svg)](https://hysenlabs.com/projects/stablecoder-cmake-scripts)

Was this useful?