CMake Best Practices for Modern C++ Projects
CMake has evolved significantly, but many projects still use patterns from the CMake 2.x era. After modernizing build systems for multiple large C++ projects at NVIDIA, here's a comprehensive guide to modern CMake that scales.
Modern CMake Principles
- Target-based approach: Everything revolves around targets, not variables
- Usage requirements: Targets know how to use themselves
- No global state: Avoid
CMAKE_CXX_FLAGSand similar globals - Export/Install properly: Make your library consumable
Project Structure
A scalable structure that works for both small and large projects:
cmake/- CMake modules and find scriptssrc/- Implementation filesinclude/project/- Public headerstests/- Test filesexamples/- Example applicationsthird_party/- Vendored dependencies
Dependency Management
Modern CMake offers several approaches:
- FetchContent: Download at configure time
- CPM.cmake: Enhanced FetchContent with caching
- Conan/vcpkg: External package managers
- find_package: System-installed libraries
CUDA Integration
Special considerations for CUDA projects:
- Use
CMAKE_CUDA_ARCHITECTURESfor GPU targets - Separate device and host code properly
- Handle CUDA toolkit versioning
- Link CUDA libraries as IMPORTED targets
Performance Tips
- Use Ninja generator for faster builds
- Enable ccache or sccache
- Precompiled headers for large projects
- Unity builds for template-heavy code
Complete guide with CMakeLists.txt templates coming soon...