本文最后更新于 31 天前,其中的信息可能已经有所发展或是发生改变。
平时在项目中使用,用的时候现搜,正好这次整理一下。
1. CMake基本概念与用法
1.1 基本概念
CMake是一个开源的跨平台构建系统,用于自动化生成平台特定的构建文件(如Makefile或Visual Studio项目)。其核心组件包括:
- CMakeLists.txt:配置文件,定义项目结构、依赖关系和编译规则。
- 构建目录(Build Directory):用于存放生成的构建文件,与源代码分离,保持整洁。
- 生成器(Generator):工具链(如Unix Makefiles、Ninja或Visual Studio),将CMakeLists.txt转换为本地构建系统文件。
CMake不直接编译代码,而是生成中间文件,由本地工具(如make或MSBuild)执行构建,简化跨平台开发流程。
1.2 核心特性
- 跨平台性:支持Linux、Windows、macOS等系统,生成适配不同编译器的构建文件(如Xcode或MSVC项目)。
- 高效性与可扩展性:优化大型项目管理(如KDE项目),构建速度比传统工具(如Autotools)快40%。
- 模块化设计:通过
find_package
等命令自动检测系统库,简化依赖管理。 - 声明式语法:CMakeLists.txt使用简洁的脚本语言,降低构建配置复杂度。
1.3 基本用法
CMake工作流程分为三步:
-
创建CMakeLists.txt:在项目根目录定义最小配置。
cmake_minimum_required(VERSION 3.10) # 指定最低CMake版本 project(MyProject LANGUAGES CXX) # 定义项目名称及语言(C++) add_executable(app main.cpp) # 添加可执行文件目标
-
生成构建系统:在构建目录运行
cmake
命令。mkdir build && cd build cmake .. # 生成Makefile或等效文件
-
构建项目:使用本地工具编译。
make # 或ninja、msbuild等
此流程确保源码与构建分离,提升可维护性。
2. CMake详细命令
以下命令分类整理自CMake官方文档(v3.28)及实践案例,覆盖常用场景。命令按功能分组,并标注关键参数。
2.1 必备命令
命令 | 描述 |
---|---|
cmake_minimum_required(VERSION x.x.x) |
设置项目所需的最低 CMake 版本 |
project(<name> [LANGUAGES] [<language>...]) |
定义项目名称及使用的语言(如 CXX、C) |
2.2 子项目管理
命令 | 描述 |
---|---|
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL]) |
添加一个子目录作为子项目 |
subdirs([dir1 dir2 ...]) |
已弃用,旧版用于添加多个子目录 |
aux_source_directory(<dir> <variable>) |
收集指定目录下的所有源文件到变量中 |
file(GLOB ...) |
使用通配符匹配文件(如 *.cpp )并存入变量 |
2.3 目标管理
命令 | 描述 |
---|---|
add_executable(<name> [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] source1 ...) |
创建可执行文件目标 |
add_library(<name> [STATIC | SHARED | MODULE] source1 ...) |
创建库目标(静态/共享/模块) |
target_sources(<target> [PRIVATE|PUBLIC|INTERFACE] source1 ...) |
向目标添加源文件 |
target_include_directories(<target> [SYSTEM] [BEFORE] INTERFACE|PUBLIC|PRIVATE [items...] |
设置目标的头文件包含路径 |
target_compile_definitions(<target> [PRIVATE|PUBLIC|INTERFACE] [items...] |
设置编译宏定义 |
target_link_libraries(<target> [PRIVATE|PUBLIC|INTERFACE] lib1 ...) |
链接库到目标 |
target_compile_options(<target> [PRIVATE|PUBLIC|INTERFACE] [items...] |
设置编译器选项 |
target_link_options(<target> ...) |
设置链接器选项 |
2.4 包管理
命令 | 描述 |
---|---|
find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [COMPONENTS ...]) |
查找系统中的第三方库或工具 |
find_path(<VAR> name path1 path2 ...) |
查找头文件路径 |
find_library(<VAR> name path1 path2 ...) |
查找库文件路径 |
find_file(...) |
查找普通文件 |
find_program(...) |
查找可执行程序 |
2.5 变量与控制流
命令 | 描述 |
---|---|
set(<var> [value] [CACHE TYPE DOCSTRING [FORCE]]) |
设置变量值 |
unset(<var> [CACHE]) |
删除变量 |
if(expression) / elseif() / else() / endif() |
条件判断语句块 |
while(condition) / endwhile() |
循环语句块 |
foreach(loop_var arg1 arg2 ...) ... endforeach() |
遍历循环 |
message([STATUS|WARNING|SEND_ERROR|FATAL_ERROR] "message") |
输出信息到控制台 |
option(<option_var> "description" [ON|OFF]) |
定义用户可配置的布尔选项 |
2.6 文件及路径操作
命令 | 描述 |
---|---|
file(WRITE filename "content") |
写入内容到文件 |
file(APPEND filename "content") |
追加内容到文件 |
file(READ filename variable) |
读取文件内容到变量 |
file(MAKE_DIRECTORY dir1 dir2 ...) |
创建目录 |
file(REMOVE file1 file2 ...) |
删除文件 |
file(COPY src DESTINATION dest) |
复制文件或目录 |
file(TO_CMAKE_PATH path result) |
转换路径格式为 CMake 格式 |
file(TO_NATIVE_PATH path result) |
转换路径为本地系统格式 |
2.7 宏与函数
命令 | 描述 |
---|---|
macro(<name> [arg1 [arg2 [...]]]) ... endmacro() |
定义宏 |
function(<name> [arg1 [arg2 [...]]]) ... endfunction() |
定义函数 |
2.8 安装与打包
命令 | 描述 |
---|---|
install(TARGETS targets... DESTINATION dir) |
安装目标(如可执行文件、库) |
install(FILES files... DESTINATION dir) |
安装普通文件 |
install(DIRECTORY dir... DESTINATION dir) |
安装整个目录 |
include(CPack) |
启用 CPack 打包功能 |
cpack_add_install(CPACK_<OPTION>) |
配置 CPack 打包参数 |
2.9 测试支持
命令 | 描述 |
---|---|
enable_testing() |
启用测试支持 |
add_test(NAME name COMMAND cmd [args...] [WORKING_DIRECTORY dir] [COMMENT comment] [DEPENDS dep1 dep2 ...]) |
添加测试用例 |
set_tests_properties(test1 test2 ... PROPERTIES prop1 value1 ...) |
设置测试属性 |
2.10 其他命令
命令 | 描述 |
---|---|
add_custom_target(name [ALL] [command1 [args...]] [DEPENDS depend1 ...] [WORKING_DIRECTORY dir]) |
添加自定义目标(如生成资源) |
add_custom_command(...) |
添加自定义构建命令 |
execute_process(COMMAND cmd [args...] [WORKING_DIRECTORY dir] [RESULT_VARIABLE var] [OUTPUT_VARIABLE out] [ERROR_VARIABLE err]) |
执行外部进程 |
list(APPEND|INSERT|REMOVE_AT|REMOVE_ITEM|SORT list_var ...) |
列表操作 |
string(FIND|REPLACE|TOLOWER|TOUPPER|SUBSTRING ...) |
字符串操作 |
configure_file(input output) |
替换模板文件中的变量并生成新文件 |
3. 使用示例
3.1 一般项目管理
以下是一个简单的Hello World项目示例,展示CMakeLists.txt的基本结构:
cmake_minimum_required(VERSION 3.10) # 最低CMake版本
project(HelloWorld LANGUAGES CXX) # 项目名及语言
# 添加可执行目标
add_executable(hello main.cpp)
# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
# 可选:添加头文件目录
target_include_directories(hello PUBLIC include)
# 可选:链接库
# target_link_libraries(hello PRIVATE mylib)
构建步骤:
- 创建
build
目录:mkdir build && cd build
- 生成构建文件:
cmake ..
- 编译:
make
(或等效命令)
3.2 Qt项目CMake完整示例
3.2.1 CMakeLists.txt文件示例
# 基础配置段
cmake_minimum_required(VERSION 3.14)
# 项目级变量预设
set(LIB_NAME "qtadvanced")
set(PROJECT_VERSION 1.2.0)
set(VCPKG_TARGET_TRIPLET "x64-windows" CACHE STRING "VCPKG目标平台三元组")
# 工具链配置
if(DEFINED ENV{VCPKG_ROOT})
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
CACHE STRING "VCPKG工具链文件路径")
endif()
# 自定义Qt路径支持
if(QT_CUSTOM_PATH)
set(Qt5_DIR "${QT_CUSTOM_PATH}/lib/cmake/Qt5")
set(QT_QMAKE_EXECUTABLE "${QT_CUSTOM_PATH}/bin/qmake")
endif()
# 项目定义
project(${LIB_NAME}
VERSION ${PROJECT_VERSION}
LANGUAGES CXX
DESCRIPTION "Advanced Qt Component Library"
)
## Qt模块配置段
# 自动处理Qt元对象系统
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# 查找Qt组件
find_package(Qt5 COMPONENTS
Core
Widgets
Qml
Quick
Gui
REQUIRED
)
# 编译器配置
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if(MSVC)
add_compile_definitions(
WIN32_LEAN_AND_MEAN
NOMINMAX
_CRT_SECURE_NO_WARNINGS
)
add_compile_options(/MP) # 启用多核编译
endif()
## 源文件收集段
file(GLOB_RECURSE LIB_SOURCES
"src/*.cpp"
"src/*.h"
)
file(GLOB_RECURSE UI_FILES
"ui/*.ui"
)
file(GLOB_RECURSE QML_FILES
"qml/*.qml"
)
file(GLOB_RECURSE RESOURCE_FILES
"resources/*.qrc"
)
# 翻译支持
set(TS_FILES
translations/${LIB_NAME}_en_US.ts
translations/${LIB_NAME}_zh_CN.ts
)
## 目标构建段
add_library(${LIB_NAME} SHARED
${LIB_SOURCES}
${UI_FILES}
${RESOURCE_FILES}
${TS_FILES}
)
# 目标属性配置
set_target_properties(${LIB_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION 1
OUTPUT_NAME "${LIB_NAME}$<$<CONFIG:Debug>:d>"
WINDOWS_EXPORT_ALL_SYMBOLS ON # Windows下自动导出符号
)
# 包含目录配置
target_include_directories(${LIB_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
# Qt模块链接
target_link_libraries(${LIB_NAME} PUBLIC
Qt5::Core
Qt5::Widgets
Qt5::Qml
Qt5::Quick
)
## 第三方依赖段
# VCPKG依赖查找
find_package(ZLIB REQUIRED)
find_package(OpenSSL REQUIRED)
# 自定义查找模块
include(cmake/FindAdvancedDeps.cmake)
target_link_libraries(${LIB_NAME} PRIVATE
ZLIB::ZLIB
OpenSSL::SSL
${ADVANCED_DEPS_LIBRARIES}
)
## 安装配置段
install(TARGETS ${LIB_NAME}
EXPORT ${LIB_NAME}Targets
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
install(DIRECTORY include/
DESTINATION include
FILES_MATCHING PATTERN "*.h"
)
install(FILES
${TS_FILES}
DESTINATION share/${LIB_NAME}/translations
)
# 导出配置
install(EXPORT ${LIB_NAME}Targets
FILE ${LIB_NAME}Targets.cmake
NAMESPACE ${LIB_NAME}::
DESTINATION lib/cmake/${LIB_NAME}
)
include(CMakePackageConfigHelpers)
configure_package_config_file(
cmake/${LIB_NAME}Config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}Config.cmake
INSTALL_DESTINATION lib/cmake/${LIB_NAME}
)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}ConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}ConfigVersion.cmake
DESTINATION lib/cmake/${LIB_NAME}
)
## 高级功能段
# 单元测试
if(BUILD_TESTING)
enable_testing()
add_subdirectory(tests)
endif()
# 文档生成
if(BUILD_DOCS)
find_package(Doxygen REQUIRED)
add_custom_target(docs
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs
COMMENT "Generating API documentation"
)
endif()
# 代码分析
if(ENABLE_CLANG_TIDY)
find_program(CLANG_TIDY_EXE "clang-tidy")
if(CLANG_TIDY_EXE)
set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXE}")
endif()
endif()
3.2.2 命令解析
1.Windows符号导出:
set_target_properties(${LIB_NAME} PROPERTIES
WINDOWS_EXPORT_ALL_SYMBOLS ON
)
- 解决Windows平台DLL导出问题
- 替代传统的
__declspec(dllexport)
手动标记
2.条件编译控制:
$<$<CONFIG:Debug>:d>
- 生成器表达式实现Debug/Release后缀自动添加
- 保持不同配置下的输出文件名区分
3.国际化支持:
qt5_add_translation(QM_FILES ${TS_FILES})
add_custom_target(translations ALL DEPENDS ${QM_FILES})
- 完整的翻译文件处理流程
- 集成Qt Linguist工具链
4.目标导出配置:
install(EXPORT ${LIB_NAME}Targets
FILE ${LIB_NAME}Targets.cmake
NAMESPACE ${LIB_NAME}::
DESTINATION lib/cmake/${LIB_NAME}
)
- 创建可导入的CMake配置
- 支持
find_package(${LIB_NAME})
的使用方式
5.版本兼容性控制:
write_basic_package_version_file(
${LIB_NAME}ConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
- 语义化版本控制
- 主版本号相同的版本自动兼容
6.VCPKG集成优化:
if(DEFINED ENV{VCPKG_ROOT})
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
endif()
- 自动检测环境变量配置
- 避免硬编码路径
7.自定义查找模块:
include(cmake/FindAdvancedDeps.cmake)
target_link_libraries(${LIB_NAME} PRIVATE ${ADVANCED_DEPS_LIBRARIES})
- 模块化组织复杂依赖
- 保持主CMakeLists.txt的简洁性