Dotfiles-nix cmkr-build
Guide for setting up and using cmkr.build, a modern CMake-based build system using TOML configuration. Use when creating new C++ projects, setting up CMake builds, converting from CMakeLists.txt, or when users mention cmkr, cmake.toml, or "CMake TOML".
git clone https://github.com/not-matthias/dotfiles-nix
T=$(mktemp -d) && git clone --depth=1 https://github.com/not-matthias/dotfiles-nix "$T" && mkdir -p ~/.claude/skills && cp -r "$T/modules/home/programs/cli-agents/shared/skills/cmkr-build" ~/.claude/skills/not-matthias-dotfiles-nix-cmkr-build && rm -rf "$T"
modules/home/programs/cli-agents/shared/skills/cmkr-build/SKILL.mdcmkr.build - Modern CMake with TOML
cmkr (pronounced "cmaker") is a modern build system that parses cmake.toml files and generates idiomatic CMakeLists.txt. It simplifies CMake by using TOML syntax while maintaining full CMake compatibility.
Quick Start - New Project Setup
1. Bootstrap cmkr in Your Project
# Download the bootstrap script curl https://raw.githubusercontent.com/build-cpp/cmkr/main/cmake/cmkr.cmake -o cmkr.cmake # Run the bootstrap (downloads cmkr and generates initial files) cmake -P cmkr.cmake
What this does:
- Downloads the cmkr executable to
build/_deps/cmkr-src/ - Creates a minimal
file if it doesn't existcmake.toml - Generates
from yourCMakeLists.txtcmake.toml
2. Configure Your Project in cmake.toml
[project] name = "myproject" version = "1.0.0" description = "My awesome C++ project" languages = ["CXX"] [target.myapp] type = "executable" sources = ["src/main.cpp"]
3. Build Your Project
# Configure (cmkr auto-regenerates CMakeLists.txt if cmake.toml changed) cmake -B build # Build cmake --build build # Run ./build/myapp
No extra steps! After modifying
cmake.toml, just run cmake --build build and cmkr automatically regenerates CMakeLists.txt.
Understanding cmkr Architecture
How It Works
cmake.toml → [cmkr parses] → CMakeLists.txt → [CMake processes] → Build files
- You edit
(clean, readable TOML syntax)cmake.toml - cmkr generates modern, idiomatic
CMakeLists.txt - CMake processes the generated file normally
- Your build system (Make, Ninja, Visual Studio) compiles
File Commit Guide
Commit these to version control:
- ✅
- Your project configurationcmake.toml - ✅
- Bootstrap script (enables CI builds)cmkr.cmake - ✅
- Generated (regenerates automatically)CMakeLists.txt
cmake.toml Reference
Project Section [project]
[project] name = "myproject" # Required: project name version = "1.0.0" # Optional: project version description = "Description here" # Optional: project description languages = ["CXX", "C"] # Optional: enabled languages cmake-before = """ # Optional: CMake code before project() message(STATUS "Before project") """ cmake-after = """ # Optional: CMake code after project() message(STATUS "After project") """
Supported languages: C, CXX (C++), CSharp, CUDA, OBJC, OBJCXX, Fortran, HIP, ISPC, Swift, ASM, ASM_MASM (MASM), ASM_NASM, ASM_MARMASM, ASM-ATT
Target Section [target.<name>]
[target.mylib] type = "static" # Required: executable, library, shared, static, interface, object, custom sources = ["src/*.cpp"] # Source files (supports globbing) headers = ["include/*.hpp"] # Header files (for documentation) include-directories = ["include"] # Public include paths compile-definitions = ["MYLIB_EXPORT"] # Preprocessor defines compile-features = ["cxx_std_20"] # C++ standard version compile-options = ["-Wall", "-Wextra"] # Compiler flags link-libraries = ["otherlib"] # Link dependencies link-options = [] # Linker flags precompile-headers = ["pch.hpp"] # Precompiled headers [target.mylib.properties] CXX_STANDARD = 17 CXX_STANDARD_REQUIRED = true
Target Types:
| Type | Purpose | Visibility Default |
|---|---|---|
| Program you run (.exe) | PRIVATE |
| Static library (.lib, .a) | PUBLIC |
| Dynamic library (.dll, .so, .dylib) | PUBLIC |
| Let CMake decide static/shared | PUBLIC |
| Header-only library | INTERFACE |
| Object files collection | PUBLIC |
Visibility Controls:
- Public properties:
,include-directories
,compile-definitionslink-libraries - Private properties: Prefix with
(e.g.,private-
)private-compile-options - Interface-only: Use on
targetsinterface
Conditions [conditions]
[conditions] # Predefined (override if needed): windows = "WIN32" macos = "CMAKE_SYSTEM_NAME MATCHES \"Darwin\"" linux = "CMAKE_SYSTEM_NAME MATCHES \"Linux\"" unix = "UNIX" msvc = "MSVC" clang = "CMAKE_CXX_COMPILER_ID MATCHES \"Clang\"" gcc = "CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\"" x64 = "CMAKE_SIZEOF_VOID_P EQUAL 8" root = "CMKR_ROOT_PROJECT" # Custom conditions: build-tests = "MYPROJECT_BUILD_TESTS" ptr64 = "CMAKE_SIZEOF_VOID_P EQUAL 8"
Using conditions:
[target.myapp] type = "executable" sources = ["src/main.cpp"] windows.sources = ["src/win32_specific.cpp"] linux.compile-options = ["-fPIC"]
Options [options]
[options] MYPROJECT_BUILD_TESTS = false MYPROJECT_BUILD_EXAMPLES = { value = true, help = "Build example programs" } MYPROJECT_ENABLE_FEATURE = "root" # Only true if this is root project
Usage:
cmake -B build -DMYPROJECT_BUILD_TESTS=ON
Each option creates a condition with the same name (lowercase, dashes).
Variables [variables]
[variables] MY_CUSTOM_VAR = "value" MY_BOOL_VAR = true
Emits:
set(MY_CUSTOM_VAR "value")
Dependencies
vcpkg [vcpkg]
[vcpkg] version = "2024.11.16" # vcpkg version (auto-generates URL) packages = ["fmt", "zlib", "boost"] # Packages to install # Package with features: # packages = ["imgui[docking-experimental,freetype,sdl2-binding]"] # Disable default features: # packages = ["cpp-httplib[core,openssl]"] overlay-ports = ["my-ports"] # Custom ports directory overlay-triplets = ["my-triplets"] # Custom triplets directory overlay = "vcpkg-overlay" # Both in one directory
FetchContent [fetch-content.<name>]
[fetch-content.fmt] git = "https://github.com/fmtlib/fmt" tag = "10.2.1" shallow = true # --depth 1 [fetch-content.somelib] url = "https://example.com/lib.zip" sha256 = "abc123..."
Find Package [find-package.<name>]
[find-package.Boost] required = true version = "1.82" components = ["filesystem", "system"] [find-package.OpenSSL] required = false config = true
Subdirectories [subdir.<name>]
[subdir.thirdparty] condition = "root" # Only add if this is root project
Templates [template.<name>]
[template.example] condition = "build-examples" type = "executable" link-libraries = ["mylib::mylib"] add-function = "" # Custom add function (e.g., pybind11_add_module) add-arguments = [] # Arguments to add-function pass-sources = false # Pass sources to add-function [target.example1] type = "example" sources = ["examples/example1.cpp"]
Common Project Examples
Simple Executable
[project] name = "hello" version = "1.0.0" [target.hello] type = "executable" sources = ["src/main.cpp"]
Library with Examples
[project] name = "mylib" version = "2.0.0" [options] MYLIB_BUILD_EXAMPLES = { value = true, help = "Build examples" } [target.mylib] type = "static" sources = ["src/mylib.cpp"] headers = ["include/mylib.hpp"] include-directories = ["include"] [template.example] condition = "mylib-build-examples" type = "executable" link-libraries = ["mylib"] [target.example_basic] type = "example" sources = ["examples/basic.cpp"]
Using vcpkg Dependencies
[project] name = "app-with-deps" [vcpkg] packages = ["fmt", "spdlog", "nlohmann-json"] [target.app] type = "executable" sources = ["src/main.cpp"] link-libraries = ["fmt::fmt", "spdlog::spdlog", "nlohmann_json::nlohmann_json"]
Platform-Specific Code
[project] name = "cross-platform" [target.app] type = "executable" sources = ["src/main.cpp", "src/common.cpp"] # Windows-specific windows.sources = ["src/win32.cpp"] windows.link-libraries = ["kernel32"] # Linux-specific linux.sources = ["src/linux.cpp"] linux.compile-options = ["-fPIC"] linux.link-libraries = ["pthread"] # macOS-specific macos.sources = ["src/macos.cpp"] macos.compile-options = ["-mmacosx-version-min=10.14"]
Header-Only Library
[project] name = "header-lib" [target.header-lib] type = "interface" headers = ["include/header-lib/*.hpp"] include-directories = ["include"]
Multiple Targets
[project] name = "multi-target" [target.lib1] type = "static" sources = ["lib1/*.cpp"] include-directories = ["lib1/include"] [target.lib2] type = "static" sources = ["lib2/*.cpp"] include-directories = ["lib2/include"] link-libraries = ["lib1"] [target.app] type = "executable" sources = ["app/main.cpp"] link-libraries = ["lib2"]
CLI Commands
If you install cmkr to your PATH:
cmkr init [type] # Create new project (executable|library|shared|static|interface) cmkr gen # Regenerate CMakeLists.txt manually cmkr build [args] # Configure and build cmkr install # Run cmake --install cmkr clean # Clean build directory cmkr help # Show help cmkr version # Show version
Without cmkr in PATH (using CMake only):
# Regenerate (if cmake.toml changed) cmake -B build # Force regeneration cmake -B build --fresh
CMake Integration
In CI/CD
# GitHub Actions example steps: - uses: actions/checkout@v4 - name: Configure run: cmake -B build - name: Build run: cmake --build build - name: Test run: ctest --test-dir build
No special setup needed! The
cmkr.cmake bootstrap handles everything. In CI, cmkr downloads itself automatically on first configure.
With IDEs
VS Code:
- Install CMake Tools extension
- cmkr automatically regenerates
when you saveCMakeLists.txtcmake.toml - Works seamlessly with IntelliSense and debugging
CLion:
- Open project with
CMakeLists.txt - Edit
, savecmake.toml - CLion auto-detects changes and reloads
Visual Studio:
- Open folder with
CMakeLists.txt - cmkr manages regeneration automatically
Build Types
# Debug (default) cmake -B build -DCMAKE_BUILD_TYPE=Debug cmake --build build # Release cmake -B build -DCMAKE_BUILD_TYPE=Release cmake --build build # RelWithDebInfo (optimized with debug symbols) cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo # MinSizeRel (minimum size) cmake -B build -DCMAKE_BUILD_TYPE=MinSizeRel
Troubleshooting
Issue: CMakeLists.txt not regenerating
Solution:
# Force regeneration cmake -B build --fresh # Or manually trigger cmake -B build
Issue: vcpkg packages not found
Solution:
# Delete build directory to reset vcpkg cmake -E rm -rf build cmake -B build
Issue: Link errors with libraries
Solution:
- Ensure
uses target names (e.g.,link-libraries
not justfmt::fmt
)fmt - Check visibility: Public for libraries, Private for executables
- Verify Find Package or Fetch Content is configured
Issue: cmkr bootstrap fails
Solution:
# Manual download curl -L https://github.com/build-cpp/cmkr/releases/latest/download/cmkr -o cmkr chmod +x cmkr ./cmkr gen
Best Practices
- Start simple: Begin with minimal
, add complexity incrementallycmake.toml - Use templates: For repeated target patterns (examples, tests)
- Leverage conditions: Keep platform-specific code organized
- Commit bootstrap: Include
in version control for CIcmkr.cmake - Prefer vcpkg: For dependencies, use vcpkg when available
- Check before commit:
andcmake.toml
should both be committedCMakeLists.txt
Migration from CMakeLists.txt
- Create
with equivalent structurecmake.toml - Run
to generatecmake -P cmkr.cmake - Compare generated
with originalCMakeLists.txt - Adjust
until output matches desired CMakecmake.toml - Remove manual
edits (they get overwritten)CMakeLists.txt
Resources
- Documentation: https://cmkr.build/
- GitHub: https://github.com/build-cpp/cmkr
- Examples: https://cmkr.build/examples/
- Template: https://github.com/build-cpp/cmkr_for_beginners