programming-cmake-best-practices
Skill5 starsChanged 16 days agoMITView on GitHub
Create, refactor, link, and build CMake projects following modern CMake guidelines from official documentation
- Deletes or force-pushes
In this repository50 other files it gives its agents.
- analyze-pr-commentsSkill
- architecture-analyzeSkill
- architecture-tradeoffSkill
- askSkill
- code-smellsSkill
- debugging-rocprof-sysSkill
- exploration-explore-codeSkill
- git-commitSkill
- git-gh-clientSkill
- git-prepare-pull-requestSkill
- git-pull-request-statusSkill
- gitSkill
- grill-meSkill
- library-amd-smiSkill
- notify-meSkill
- planning-architectureSkill
- planning-baseSkill
- planning-bugfixSkill
- planning-docsSkill
- planning-featureSkill
- planning-refactorSkill
- programming-cpp-constexprSkill
- programming-cpp-design-patternsSkill
- programming-cpp-naming-rulesSkill
- programming-cpp-policy-based-diSkill
- programming-cppSkill
- programming-cpp-stl-algorithmsSkill
- programming-pythonSkill
- pr-review-interactiveSkill
- pr-reviewSkill
- radisha-create-skillSkill
- radisha-helpSkill
- radisha-improve-skillSkill
- radisha-skillsSkill
- radisha-updateSkill
- refactoring-techniquesSkill
- review-architectureSkill
- rocprofsys-buildSkill
- rocprofsys-configureSkill
- rocprofsysSkill
- static-analysisSkill
- testing-gtest-gmockSkill
- testing-pytestSkill
- testing-testplanSkill
- therock-build-to-commitSkill
- therock-commit-in-buildSkill
- therock-first-build-with-commitSkill
- update-pr-descriptionSkill
- verify-pmc-metricsSkill
- watchSkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 2 are distinctive, and 8 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
8
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 12
Think in terms of targets, not variables: - Use target_*() commands instead of global variables
- Distinctive: line 14
Avoid global scope pollution: - Keep settings attached to specific targets
- Distinctive: line 78
PRIVATE: Only this target needs it
- Very specific: line 172
Modularize with subdirectories: - Use add_subdirectory() for organized structure
- Very specific: line 184
Always use cmake_minimum_required() at the top
- Very specific: line 185
Never use file(GLOB) for source files in production - list them explicitly
- Very specific: line 186
Use target_sources() to add sources after target creation
- Very specific: line 187
Prefer option() for user-configurable settings
- Very specific: line 188
Use CMAKE_PROJECT_NAME instead of hardcoded project names
- Very specific: line 190
Use cmake_path() (CMake 3.20+) for path manipulation
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CMake Best Practices
You are an expert in modern CMake (3.15+) following official guidelines. Your task is to help create, refactor, and maintain CMake build systems using target-based, declarative patterns.
Core Principles
- Think in terms of targets, not variables - Use
target_*()commands instead of global variables - Be declarative, not imperative - Describe what you want, not how to build it
- Avoid global scope pollution - Keep settings attached to specific targets
- Use generator expressions for conditional logic that depends on build configuration
- Prefer
PUBLIC,PRIVATE,INTERFACEkeywords to control transitive dependencies
Creating New CMake Projects
Minimum CMakeLists.txt Structure
cmake_minimum_required(VERSION 3.15...3.28)
project(ProjectName
VERSION 1.0.0
DESCRIPTION "Brief description"
LANGUAGES CXX)
# Set C++ standard as a project-wide default
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Create executable or library target
add_executable(myapp src/main.cpp)
# OR
add_library(mylib src/mylib.cpp)
# Link dependencies (modern way)
target_link_libraries(myapp PRIVATE mylib)Directory Structure Best Practices
project/
├── CMakeLists.txt # Root CMake file
├── cmake/ # Custom CMake modules
├── src/ # Source files
│ └── CMakeLists.txt # Add with add_subdirectory()
├── include/ # Public headers
│ └── project/
├── tests/ # Test files
│ └── CMakeLists.txt
└── external/ # Third-party dependenciesRefactoring to Modern CMake
Replace Global Variables with Target Properties
OLD (avoid):
include_directories(${PROJECT_SOURCE_DIR}/include)
add_definitions(-DMY_DEFINE)
link_directories(${SOME_LIB_DIR})NEW (use this):
target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$)
target_compile_definitions(mylib PRIVATE MY_DEFINE)
target_link_libraries(mylib PUBLIC somelib)Visibility Keywords (PUBLIC/PRIVATE/INTERFACE)
- PRIVATE: Only this target needs it
- INTERFACE: Consumers of this target need it, but this target doesn't
- PUBLIC: Both this target and its consumers need it
target_include_directories(mylib
PUBLIC include/ # Headers consumers will use
PRIVATE src/ # Internal implementation headers
)
target_link_libraries(mylib
PUBLIC fmt::fmt # Appears in public API
PRIVATE sqlite3 # Internal implementation detail
)Modern Linking Patterns
Using find_package() with Imported Targets
find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem)
target_link_libraries(myapp PRIVATE Boost::system Boost::filesystem)Using FetchContent for Dependencies (CMake 3.14+)
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG v1.14.0
)
FetchContent_MakeAvailable(googletest)
target_link_libraries(mytests PRIVATE GTest::gtest_main)Creating Interface Libraries (Header-Only)
add_library(myheaderlib INTERFACE)
target_include_directories(myheaderlib INTERFACE include/)
target_compile_features(myheaderlib INTERFACE cxx_std_17)Building and Configuration
Proper Out-of-Source Build Commands
# Configure
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
# Build
cmake --build build --config Release
# Install
cmake --install build --prefix /usr/local
# Test
ctest --test-dir buildSetting Compiler Flags (Modern Way)
target_compile_options(myapp PRIVATE
$<$:-Wall -Wextra -pedantic>
$<$:/W4>
)Export and Install Targets
install(TARGETS mylib
EXPORT mylibTargets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
install(EXPORT mylibTargets
FILE mylibTargets.cmake
NAMESPACE mylib::
DESTINATION lib/cmake/mylib
)Common Refactoring Tasks
Converting to Modern target-based CMake
- Identify all executables and libraries - List all
add_executable()andadd_library()calls - Replace global commands - Convert
include_directories(),link_libraries(), etc. totarget_*()equivalents - Add visibility keywords - Determine what should be PUBLIC vs PRIVATE
- Use generator expressions - Replace if/else with
$<...>for config-dependent settings - Modularize with subdirectories - Use
add_subdirectory()for organized structure
Testing the Refactoring
# Clean build to ensure no leftover state
rm -rf build && cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failureGuidelines Summary
- Always use
cmake_minimum_required()at the top - Never use
file(GLOB)for source files in production - list them explicitly - Use
target_sources()to add sources after target creation - Prefer
option()for user-configurable settings - Use
CMAKE_PROJECT_NAMEinstead of hardcoded project names - Set properties with
set_target_properties()when needed - Use
cmake_path()(CMake 3.20+) for path manipulation - Enable testing with
enable_testing()and useadd_test()
Resources
- Official CMake Documentation: https://cmake.org/cmake/help/latest/
- Modern CMake guide: Search for "cmake-buildsystem(7)"
- Command reference: https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html
- CMake Discourse: https://discourse.cmake.org/ (for specific questions)
- "An Introduction to Modern CMake": https://cliutils.gitlab.io/modern-cmake/
- CMake Generator Expressions: https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html
- For package finding: Search official docs for "Find
<PackageName>.cmake" modules - For debugging: Use
cmake --traceormessage(STATUS "...")statements
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

