PluginBench
Skill
Review
Audit score 70

cmake

mohitmishra786/low-level-dev-skills

Modern CMake for C/C++ projects: targets, dependencies, generators, and cross-compilation.

What is cmake?

CMake is a build system generator for C/C++ projects. Use it when writing or refactoring CMakeLists.txt, configuring out-of-source builds, managing dependencies with find_package or FetchContent, selecting generators (Ninja, Make, Visual Studio), enabling sanitizers, cross-compiling, or setting up CMake Presets for CI/IDE integration.

  • Define and link targets using modern target-first CMake (target_link_libraries, target_compile_options)
  • Manage external dependencies via find_package (system libraries), FetchContent (download and build), or pkg-config fallback
  • Configure out-of-source builds with multiple generators (Ninja, Make, Visual Studio) and build types (Debug, Release, RelWithDebInfo)
  • Enable compiler sanitizers (AddressSanitizer, etc.) with generator expressions and conditional compilation flags
  • Set up cross-compilation toolchain files for different architectures (e.g., aarch64-linux-gnu)
  • Use CMake Presets (3.20+) to standardize build configurations across IDEs and CI systems

How to install cmake

npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill cmake
Prerequisites
  • CMake 3.20 or later (for most features; 3.15+ for basic usage)
  • A C/C++ compiler (gcc, clang, MSVC, etc.) installed and in PATH
  • For cross-compilation: appropriate cross-compiler toolchain installed
Claude Code
Cursor
Windsurf
Cline

How to use cmake

  1. 1.Define a minimal CMakeLists.txt with cmake_minimum_required, project(), and add_executable or add_library
  2. 2.Use target_include_directories and target_compile_options to configure targets (not legacy include_directories)
  3. 3.Add external dependencies with find_package (system libraries) or FetchContent (download and build)
  4. 4.Run cmake -S . -B build to configure out-of-source, then cmake --build build to compile
  5. 5.For Debug builds with sanitizers, use target_compile_options with generator expressions like $<$<CONFIG:Debug>:-fsanitize=address>
  6. 6.Create CMakePresets.json to define standard configurations (Debug, Release) and use cmake --preset <name> to build

Use cases

Good for
  • Writing a CMakeLists.txt for a new C/C++ project with proper target definitions and include paths
  • Adding and linking external libraries (OpenSSL, Threads, ZLIB) to an executable or library target
  • Debugging CMake configuration errors like "Could not find package" or missing compiler detection
  • Enabling AddressSanitizer or other sanitizers for Debug builds with conditional compilation flags
  • Cross-compiling a project for ARM or other architectures using a custom toolchain file
Who it's for
  • C/C++ developers writing or maintaining CMakeLists.txt files
  • Build engineers setting up cross-platform or cross-architecture builds
  • Teams adopting modern CMake practices (target-first, out-of-source builds)
  • Developers integrating external dependencies and managing complex build configurations

cmake FAQ

What's the difference between find_package and FetchContent?

find_package locates system-installed libraries (e.g., OpenSSL, ZLIB) and requires the package to be pre-installed. FetchContent downloads and builds a dependency from a Git repository or URL, useful for vendoring or when a library isn't system-installed.

Why should I use out-of-source builds?

Out-of-source builds (cmake -S . -B build) keep generated files separate from source, making it easy to clean up, support multiple configurations simultaneously, and avoid polluting the source tree.

What do PUBLIC, PRIVATE, and INTERFACE mean in target_link_libraries?

PUBLIC: linked library is visible to both the target and consumers of that target. PRIVATE: only the target itself uses it. INTERFACE: only consumers of the target use it (rarely needed for executables).

How do I enable AddressSanitizer in CMake?

Use target_compile_options and target_link_options with generator expressions: $<$<CONFIG:Debug>:-fsanitize=address -g -O1> for compile and $<$<CONFIG:Debug>:-fsanitize=address> for link, or wrap in an option() for conditional enabling.

What's the minimum CMake version I should use?

CMake 3.20 is recommended for modern features (Presets, FetchContent stability). CMake 3.15+ works for basic projects, but avoid versions below 3.10.

Full instructions (SKILL.md)

Source of truth, from mohitmishra786/low-level-dev-skills.


name: cmake description: CMake build system skill for C/C++ projects. Use when writing or refactoring CMakeLists.txt, configuring out-of-source builds, selecting generators (Ninja, Make, VS), managing targets and dependencies with target_link_libraries, integrating external packages via find_package or FetchContent, enabling sanitizers, setting up toolchain files for cross-compilation, or exporting CMake packages. Activates on queries about CMakeLists.txt, cmake configure errors, target properties, install rules, CPack, or CMake presets.

CMake

Purpose

Guide agents through modern (target-first) CMake for C/C++ projects: out-of-source builds, dependency management, generator selection, and integration with CI and IDEs.

Triggers

  • "How do I write a CMakeLists.txt for my project?"
  • "How do I add an external library with CMake?"
  • "CMake can't find my package / library"
  • "How do I enable sanitizers in CMake?"
  • "How do I cross-compile with CMake?"
  • "How do I use CMake Presets?"

Workflow

1. Modern CMake principles

  • Define targets, not variables. Use target_* commands.
  • Use PUBLIC/PRIVATE/INTERFACE to control property propagation.
  • Never use include_directories() or link_libraries() (legacy).
  • Minimum CMake version: cmake_minimum_required(VERSION 3.20) for most features.

2. Minimal project

cmake_minimum_required(VERSION 3.20)
project(MyApp VERSION 1.0 LANGUAGES C CXX)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(myapp
    src/main.c
    src/utils.c
)

target_include_directories(myapp PRIVATE include)
target_compile_options(myapp PRIVATE -Wall -Wextra)

3. Static / shared libraries

# Static library
add_library(mylib STATIC lib/foo.c lib/bar.c)
target_include_directories(mylib
    PUBLIC  include      # consumers get this include path
    PRIVATE src          # only mylib itself sees this
)

# Shared library
add_library(myshared SHARED lib/foo.c)
set_target_properties(myshared PROPERTIES
    VERSION   1.0.0
    SOVERSION 1
)

# Link executable against library
add_executable(myapp src/main.c)
target_link_libraries(myapp PRIVATE mylib)

4. Configure and build

# Out-of-source build (always do this)
cmake -S . -B build
cmake --build build

# With generator
cmake -S . -B build -G Ninja
cmake --build build -- -j$(nproc)

# Debug build
cmake -S . -B build-debug -DCMAKE_BUILD_TYPE=Debug
cmake --build build-debug

# Release
cmake -S . -B build-release -DCMAKE_BUILD_TYPE=Release
cmake --build build-release

# Install
cmake --install build --prefix /usr/local

Build types: Debug, Release, RelWithDebInfo, MinSizeRel.

5. External dependencies

find_package (system-installed libraries)

find_package(OpenSSL REQUIRED)
target_link_libraries(myapp PRIVATE OpenSSL::SSL OpenSSL::Crypto)

find_package(Threads REQUIRED)
target_link_libraries(myapp PRIVATE Threads::Threads)

find_package(ZLIB REQUIRED)
target_link_libraries(myapp PRIVATE ZLIB::ZLIB)

FetchContent (download and build dependency)

include(FetchContent)

FetchContent_Declare(
    googletest
    GIT_REPOSITORY https://github.com/google/googletest.git
    GIT_TAG        v1.14.0
)
FetchContent_MakeAvailable(googletest)

add_executable(mytest test/test_foo.cpp)
target_link_libraries(mytest PRIVATE GTest::gtest_main mylib)

pkg-config fallback

find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBFOO REQUIRED libfoo>=1.2)
target_link_libraries(myapp PRIVATE ${LIBFOO_LIBRARIES})
target_include_directories(myapp PRIVATE ${LIBFOO_INCLUDE_DIRS})

6. Compiler options by configuration

target_compile_options(myapp PRIVATE
    $<$<CONFIG:Debug>:-g -Og -fsanitize=address>
    $<$<CONFIG:Release>:-O2 -DNDEBUG>
    $<$<CXX_COMPILER_ID:GNU>:-fanalyzer>
    $<$<CXX_COMPILER_ID:Clang>:-Weverything>
)

target_link_options(myapp PRIVATE
    $<$<CONFIG:Debug>:-fsanitize=address>
)

Generator expressions: $<condition:value> evaluated at build time.

7. Enable sanitizers

option(ENABLE_ASAN "Enable AddressSanitizer" OFF)

if(ENABLE_ASAN)
    target_compile_options(myapp PRIVATE -fsanitize=address -fno-omit-frame-pointer -g -O1)
    target_link_options(myapp PRIVATE -fsanitize=address)
endif()

Build: cmake -DENABLE_ASAN=ON -S . -B build-asan && cmake --build build-asan

8. Cross-compilation toolchain file

# toolchain-aarch64.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)
set(CMAKE_C_COMPILER   aarch64-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
set(CMAKE_SYSROOT /opt/aarch64-sysroot)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
cmake -S . -B build-arm -DCMAKE_TOOLCHAIN_FILE=toolchain-aarch64.cmake

9. CMake Presets (CMake 3.20+)

{
  "version": 6,
  "configurePresets": [
    {
      "name": "release",
      "displayName": "Release",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/release",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release",
        "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
      }
    },
    {
      "name": "debug",
      "displayName": "Debug",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build/debug",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "ENABLE_ASAN": "ON"
      }
    }
  ],
  "buildPresets": [
    { "name": "release", "configurePreset": "release" },
    { "name": "debug",   "configurePreset": "debug" }
  ]
}
cmake --preset release
cmake --build --preset release

10. Common errors

ErrorCauseFix
Could not find package FooPackage not installed or wrong prefixInstall dev package; set CMAKE_PREFIX_PATH
No CMAKE_CXX_COMPILERNo C++ compiler foundInstall g++/clang++; check PATH
target_link_libraries called with wrong number of argumentsMissing PUBLIC/PRIVATE/INTERFACEAdd the keyword
Cannot find source fileTypo or wrong relative pathCheck path relative to CMakeLists.txt
generator expression errorWrong $<> syntaxCheck CMake docs for expression name

For a complete CMakeLists.txt template, see references/templates.md.

Related skills

  • Use skills/build-systems/ninja for Ninja generator details
  • Use skills/build-systems/make for Make generator
  • Use skills/compilers/cross-gcc for cross-compilation toolchain setup
  • Use skills/runtimes/sanitizers for sanitizer integration details