CMake 是一个跨平台的自动化构建系统 ,用于管理软件构建过程。它使用独立于编译器的配置文件 (CMakeLists.txt)来定义构建规则,然后生成对应平台的本地构建文件(如 Makefile、Visual Studio 项目等)。
核心特性
1. 跨平台支持
- Windows: 生成 Visual Studio 项目
- Linux/Unix: 生成 Makefile
- macOS: 生成 Xcode 项目
- 其他:Ninja、MinGW 等
2. 主要功能模块
- CMake: 核心配置和生成工具
- CTest: 测试驱动工具
- CPack: 打包工具
基本工作流程
text
编写 CMakeLists.txt
→ cmake 配置(生成构建系统文件)
→ 原生构建工具编译(如 make/ninja/msbuild)
简单示例
cmake
# CMakeLists.txt 最小示例
cmake_minimum_required(VERSION 3.10)
project(MyProject VERSION 1.0)
add_executable(myapp main.cpp)
关键概念
目标(Targets)
cmake
# 创建可执行文件
add_executable(myapp main.cpp)
# 创建库
add_library(mylib STATIC lib.cpp) # 静态库
add_library(mylib SHARED lib.cpp) # 动态库
add_library(mylib INTERFACE) # 接口库(仅头文件库)
变量
cmake
# 设置变量
set(MY_VARIABLE "value")
# 缓存变量(可在 GUI 中修改)
set(USE_FEATURE ON CACHE BOOL "启用特性")
# 环境变量
set(ENV{PATH} "/usr/local/bin:$ENV{PATH}")
# 预定义变量
message("项目源目录: ${CMAKE_SOURCE_DIR}")
message("构建目录: ${CMAKE_BINARY_DIR}")
条件判断
cmake
if(WIN32)
message("Windows 平台")
elseif(APPLE)
message("macOS 平台")
elseif(UNIX)
message("Linux/Unix 平台")
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(DEBUG_FLAGS "-g -O0")
endif()
循环
cmake
# foreach 循环
foreach(item IN ITEMS a b c)
message("项目: ${item}")
endforeach()
# 遍历文件列表
file(GLOB SOURCE_FILES "src/*.cpp")
foreach(src_file IN LISTS SOURCE_FILES)
message("源文件: ${src_file}")
endforeach()
现代 CMake 最佳实践
1. 使用目标属性而非全局设置
cmake
# 推荐做法(现代 CMake)
add_library(mylib src/lib.cpp)
target_include_directories(mylib
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_compile_features(mylib PUBLIC cxx_std_17)
target_link_libraries(mylib PUBLIC Threads::Threads)
# 避免使用(传统方式)
include_directories(include) # 不推荐
link_directories(lib) # 不推荐
2. 依赖管理
cmake
# 查找系统库
find_package(OpenCV REQUIRED COMPONENTS core imgproc)
# 使用 FetchContent 获取外部项目
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.11.0
)
FetchContent_MakeAvailable(googletest)
# 链接库
target_link_libraries(myapp PRIVATE OpenCV::opencv GTest::gtest)
常用命令速查
项目配置命令
cmake
cmake_minimum_required(VERSION 3.10) # 指定 CMake 最低版本
project(MyProject # 定义项目
VERSION 1.0.0
DESCRIPTION "我的项目"
LANGUAGES C CXX
)
# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
文件操作命令
cmake
# 收集源文件
file(GLOB SOURCES "src/*.cpp" "src/*.c")
file(GLOB_RECURSE ALL_SOURCES "src/**/*.cpp")
# 复制文件
configure_file(config.h.in config.h) # 配置头文件
file(COPY data/ DESTINATION ${CMAKE_BINARY_DIR}/data)
测试支持
cmake
enable_testing() # 启用测试
add_test(
NAME MyTest
COMMAND mytest_exe arg1 arg2
)
# 添加测试用例
include(CTest)
add_test(NAME FeatureTest COMMAND myapp --test-feature)
典型项目结构
text
myproject/
├── CMakeLists.txt # 根 CMake 文件
├── README.md
├── LICENSE
├── cmake/ # CMake 模块文件
│ ├── FindMyLib.cmake
│ └── Config.cmake.in
├── include/ # 公共头文件
│ └── myproject/
│ └── mylib.h
├── src/ # 源代码
│ ├── CMakeLists.txt
│ ├── main.cpp
│ └── mylib.cpp
├── tests/ # 测试代码
│ ├── CMakeLists.txt
│ └── test_mylib.cpp
├── examples/ # 示例代码
│ ├── CMakeLists.txt
│ └── example1.cpp
└── external/ # 外部依赖(可选)
└── CMakeLists.txt
构建步骤示例
bash
# 1. 创建构建目录并进入
mkdir build && cd build
# 2. 配置项目(生成构建文件)
cmake .. -DCMAKE_BUILD_TYPE=Release -DUSE_FEATURE=ON
# 3. 编译项目
cmake --build . --config Release
# 4. 运行测试
ctest -C Release --verbose
# 5. 安装(可选)
cmake --install . --prefix /usr/local
CMake 的优势
- 真正的跨平台:同一配置支持 Windows、Linux、macOS 等
- 构建系统生成器:不直接构建,而是生成 Makefile、.sln 等
- 依赖管理:强大的 find_package 和现代 FetchContent
- 模块化:支持大型项目的模块化组织
- IDE 集成:与 VS、CLion、VS Code 等完美集成
- 活跃社区:丰富的第三方模块和文档
学习路径建议
- 初级阶段:掌握基本语法,创建简单可执行文件
- 中级阶段:学习库的创建和链接,理解 PUBLIC/PRIVATE/INTERFACE
- 高级阶段:掌握安装和打包,编写 Find 模块,使用生成器表达式
- 专家阶段:深入理解 CMake 内部机制,编写复杂项目配置
常用生成器表达式
cmake
# 条件表达式
target_compile_definitions(mylib
PRIVATE
$<$<CONFIG:Debug>:DEBUG_MODE=1>
$<$<PLATFORM_ID:Windows>:WINDOWS_PLATFORM>
)
# 安装路径相关
$<INSTALL_INTERFACE:include> # 安装时的接口路径
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # 构建时的接口路径
调试 CMake
cmake
# 打印变量值
message(STATUS "CMAKE_VERSION: ${CMAKE_VERSION}")
message(DEBUG "调试信息")
# 变量追踪
variable_watch(CMAKE_PREFIX_PATH)
# 打印所有变量
get_cmake_property(vars VARIABLES)
foreach(var ${vars})
message("${var} = ${${var}}")
endforeach()
提示:CMake 3.0+ 版本引入了现代 CMake 概念,建议使用 CMake 3.10 或更高版本开始新项目,并遵循基于目标的编程模式。