一、CMake现代配置范式
CMake 3.21+ 引入了许多现代化特性:正确传播的导入目标、依赖管理协议(DEPfetcher)、NVIDIA/Apple编译器原生支持等。掌握这些特性是写出可维护构建配置的基础。
1.1 导出目标与依赖传播
# CMake 3.x 现代写法(优先使用):
cmake_minimum_required(VERSION 3.21)
project(MyProject VERSION 1.0.0 LANGUAGES CXX)
# 启用C++20
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) # 用-std=c++20而非-gnu++20
# 现代 target_* 属性(自动传播):
add_library(my_lib STATIC src/lib.cpp)
target_compile_features(my_lib PUBLIC cxx_std_20)
# ✅ PUBLIC:自己和依赖者都用
# ✅ PRIVATE:只有自己用
# ✅ INTERFACE:只有依赖者用
target_include_directories(my_lib
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src
)
# 依赖其他库(优先find_package):
find_package(Threads REQUIRED) # 系统线程库
find_package(fmt REQUIRED) # 第三方库
find_package(OpenSSL 1.1 REQUIRED) # 带版本约束
add_executable(my_app src/main.cpp)
target_link_libraries(my_app
PRIVATE
my_lib
Threads::Threads
fmt::fmt
OpenSSL::SSL
)
二、依赖管理:从vcpkg到CMake Presets
2.1 vcpkg集成
# vcpkg.json(项目级依赖管理)
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"name": "my-project",
"version": "1.0.0",
"dependencies": [
"fmt",
"nlohmann-json",
"boost-asio",
{
"name": "opencv",
"features": ["jpeg", "png", "gtk3"]
}
],
"overrides": [
{ "name": "fmt", "version": "10.2.1" }
]
}
# CMakeLists.txt中集成vcpkg:
# 方式一:工具链文件
# $ cmake -B build -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake
# 方式二:CMake 3.27+ 直接支持
find_package(nlohmann_json REQUIRED)
find_package(fmt REQUIRED)
2.2 CMake Presets(跨平台构建配置)
# CMakePresets.json(项目级,构建只需cmake --preset)
{
"version": 6,
"configurePresets": [
{
"name": "dev",
"hidden": true,
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"CMAKE_COLOR_DIAGNOSTICS": "ON"
}
},
{
"name": "linux-release",
"inherits": "dev",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"ENABLE_TESTING": "ON"
}
},
{
"name": "windows-debug",
"inherits": "dev",
"generator": "Visual Studio 17 2022",
"architecture": {"value": "x64"},
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
}
],
"buildPresets": [
{
"name": "release",
"configurePreset": "linux-release",
"jobs": 8
}
]
}
# 用户使用:
$ cmake --preset linux-release # 配置
$ cmake --build --preset release # 构建
$ ctest --preset release # 测试
三、CTest与测试集成
enable_testing()
# 添加单元测试
find_package(GTest REQUIRED)
add_executable(test_geometry test/geometry_test.cpp)
target_link_libraries(test_geometry PRIVATE
geometry_lib
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(test_geometry)
# 测试分级:单元/集成/性能
add_test(NAME Unit.BenchmarkFixture COMMAND test_benchmark)
set_tests_properties(Unit.BenchmarkFixture
PROPERTIES PASS_REGULAR_EXPRESSION "ALL TESTS PASSED"
FAIL_REGULAR_EXPRESSION "[ FAILED ]"
)
# Benchmark(使用Google Benchmark):
add_executable(benchmark_algorithm
benchmark/algorithm_benchmark.cpp)
target_link_libraries(benchmark_algorithm
PRIVATE benchmark::benchmark)
3.1 GitHub Actions CI配置
# .github/workflows/cmake.yml
name: CMake Build
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
cmake-generator: [Ninja, "Unix Makefiles"]
include:
- os: windows-latest
cmake-generator: "Visual Studio 17 2022"
runs-on: $
steps:
- uses: actions/checkout@v4
- name: Configure CMake
run: |
cmake -B build -G "$"
-DCMAKE_BUILD_TYPE=Release
-DENABLE_TESTING=ON
- name: Build
run: cmake --build build --parallel
- name: Test
run: ctest --output-on-failure --build-dir build
- name: Benchmark
if: matrix.os == 'ubuntu-latest'
run: |
cmake --build build --target benchmark_algorithm
./build/benchmark_algorithm --benchmark_format=json > benchmark.json
- name: Upload benchmark
if: matrix.os == 'ubuntu-latest'
uses: benchmark-action/github-action-benchmark@v1
with:
tool: 'googlebenchmark'
outputFilePath: benchmark.json
四、预编译头与增量构建优化
# 预编译头(PCH):加速编译约30-50%
target_precompile_headers(my_lib
PRIVATE
<vector>
<string>
<memory>
)
# 实际效果(1000个cpp文件,包含相同头):
# 无PCH: 3分12秒
# 有PCH: 1分28秒 ← 提速55%
# 模块化构建(CMake 3.28+,C++20 Modules):
# 注意:模块化构建还在成熟中,生产使用需谨慎
add_library(my_lib STATIC)
target_sources(my_lib
PUBLIC
FILE_SET my_modules
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/modules
MODULES std.cppm # C++20模块
)
# 分层构建(超级构建模式):
# Project/
# ├── CMakeLists.txt(主构建)
# └── src/
# ├── superbuild/CMakeLists.txt
# └── deps/(第三方库存放)
# 安装规则(跨平台):
include(GNUInstallDirs)
install(TARGETS my_lib my_app
EXPORT MyProjectTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
install(EXPORT MyProjectTargets
FILE MyProjectTargets.cmake
NAMESPACE MyProject::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyProject
)