CMake进阶: CMake Modules---简化CMake配置的利器
目录
1.简介
2.为什么需要 CMake Modules?
3.内置模块:开箱即用的工具
3.1.依赖查找模块(FindXXX.cmake)
3.2.功能检测模块(CheckXXX.cmake)
3.3.通用工具模块(如 FetchContent.cmake、CTest.cmake)
4.自定义模块:封装项目特有逻辑
5.注意事项
6.总结
相关链接
1.简介
CMake Modules(CMake 模块)是一系列预定义或自定义的 .cmake
脚本文件,用于封装可重用的 CMake 逻辑(如依赖查找、功能检测、自定义命令等)。它们是简化 CMake 配置、实现代码复用和跨项目一致性的核心工具,尤其在大型项目或多项目管理中能显著提升配置效率。
CMake 模块是扩展名为 .cmake
的文本文件,包含 CMake 命令、函数、宏或变量定义,用于封装特定功能(如 “查找 OpenSSL 库”“设置通用编译选项”“生成版本文件” 等)。
- 内置模块:CMake 自带大量预定义模块(如
FindZLIB.cmake
、FetchContent.cmake
),位于 CMake 安装目录的Modules
文件夹下(可通过cmake --help-module-list
查看所有内置模块)。
文件夹如下面的目录:
- 自定义模块:用户可根据项目需求编写自己的模块,放在项目目录中(如
cmake/Modules/
),供多个子项目或目标复用。
2.为什么需要 CMake Modules?
1.代码复用:将重复的配置逻辑(如依赖查找、编译选项设置)封装到模块中,避免在多个 CMakeLists.txt
中重复编写。
2.简化主配置:主 CMakeLists.txt
只需通过 include(ModuleName)
调用模块,聚焦项目核心逻辑,减少冗余代码。
3.跨项目一致性:同一团队或生态的多个项目可共享模块,确保依赖管理、编译标准等配置统一。
4.隐藏复杂性:将复杂逻辑(如跨平台适配、条件检测)封装在模块中,主配置文件更简洁易懂。
3.内置模块:开箱即用的工具
CMake 内置了数百个模块,覆盖常见依赖查找、功能检测、平台适配等场景,无需手动编写复杂逻辑。
3.1.依赖查找模块(FindXXX.cmake
)
最常用的一类模块,用于查找系统中的第三方库(如 ZLIB、OpenSSL、Python 等),内部通过 find_path
、find_library
等命令实现查找,并暴露统一的接口变量(如 XXX_INCLUDE_DIRS
、XXX_LIBRARIES
)。
CMake指令:find_package_cmake find package-CSDN博客
示例:使用 FindZLIB.cmake
查找 zlib 库
# 主 CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(MyProject)# 加载内置的 FindZLIB.cmake 模块(无需手动 include,find_package 自动查找)
find_package(ZLIB REQUIRED) # 内部调用 FindZLIB.cmake# 使用模块提供的变量
add_executable(myapp main.cpp)
target_include_directories(myapp PRIVATE ${ZLIB_INCLUDE_DIRS})
target_link_libraries(myapp PRIVATE ${ZLIB_LIBRARIES})
FindZLIB.cmake
模块已封装了所有查找逻辑(如适配不同平台的库名、路径),用户无需关心底层细节,直接使用即可。
3.2.功能检测模块(CheckXXX.cmake
)
用于检测编译器特性、函数 / 头文件是否存在等,辅助条件编译。
CMake进阶: 检查函数/符号存在性、检查类型/关键字/表达式有效性和检查编译器特性-CSDN博客
CMake进阶:检查头文件存在性(check_include_file 和 check_include_fileCXX)_cmake编译头文件的查找-CSDN博客
示例:使用 CheckFunctionExists.cmake
检测函数是否存在
include(CheckFunctionExists) # 加载内置模块# 检测系统是否有 posix_memalign 函数
check_function_exists(posix_memalign HAVE_POSIX_MEMALIGN)# 根据检测结果设置宏,供代码中使用
if(HAVE_POSIX_MEMALIGN)add_definitions(-DHAVE_POSIX_MEMALIGN=1)
endif()
代码中可通过宏判断是否使用该函数:
#ifdef HAVE_POSIX_MEMALIGN// 使用 posix_memalign
#else// 备选实现
#endif
3.3.通用工具模块(如 FetchContent.cmake
、CTest.cmake
)
提供通用功能,如下载依赖、集成测试等。
CMake进阶: 使用FetchContent方法基于gTest的C++单元测试_cmake fetchcontent-CSDN博客
示例:使用 FetchContent.cmake
下载外部依赖
include(FetchContent) # 加载内置模块# 下载并集成 googletest
FetchContent_Declare(googletestGIT_REPOSITORY https://github.com/google/googletest.gitGIT_TAG v1.15.0
)
FetchContent_MakeAvailable(googletest) # 自动下载、配置、构建
4.自定义模块:封装项目特有逻辑
CMake基础:宏(macro)和函数(function)_cmake macro-CSDN博客
当内置模块无法满足需求(如项目特有依赖、自定义工具链)时,可编写自定义模块,实现逻辑复用。
1.自定义模块的创建步骤
步骤 1:创建模块文件(.cmake
)
在项目中新建 cmake/Modules
目录,创建模块文件(如 AddMyTest.cmake
),封装自定义逻辑(如简化测试用例添加):
# cmake/Modules/AddMyTest.cmake
# 自定义函数:简化测试用例添加,自动链接 gtest 并设置属性
function(add_my_test test_name test_src)add_executable(${test_name} ${test_src})target_link_libraries(${test_name} PRIVATE gtest_main)set_target_properties(${test_name} PROPERTIESCXX_STANDARD 17CXX_STANDARD_REQUIRED ON)add_test(NAME ${test_name} COMMAND ${test_name})
endfunction()
步骤 2:指定模块路径
在主 CMakeLists.txt
中通过 CMAKE_MODULE_PATH
告诉 CMake 去哪里查找自定义模块:
# 主 CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(MyProject)# 添加自定义模块路径(${CMAKE_CURRENT_SOURCE_DIR} 是当前 CMakeLists.txt 所在目录)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")
步骤 3:使用自定义模块
# 加载自定义模块
include(AddMyTest)# 调用模块中的 add_my_test 函数(无需重复编写测试配置)
add_my_test(test1 tests/test1.cpp)
add_my_test(test2 tests/test2.cpp)
2.自定义模块的典型场景
- 封装项目通用编译选项:如
SetCompilerFlags.cmake
,统一设置-Wall
、-O2
等编译 flags。 - 处理项目特有依赖:如
FindMySDK.cmake
,查找团队内部 SDK 的头文件和库。 - 生成自定义文件:如
GenerateVersion.cmake
,封装configure_file
逻辑生成版本头文件。
5.注意事项
1.命名规范
- 内置模块通常遵循
FindXXX.cmake
(查找依赖)、CheckXXX.cmake
(功能检测)等命名。 - 自定义模块建议使用项目相关前缀(如
MyProjectUtils.cmake
),避免与内置模块重名。
2.路径管理
- 自定义模块统一放在项目的
cmake/Modules
目录,便于维护。 - 通过
CMAKE_MODULE_PATH
动态添加路径(而非硬编码),确保模块可被正确找到。
3.接口设计
- 模块中定义的函数 / 宏应清晰易懂,参数明确(如
add_my_test(test_name src_files)
)。 - 暴露的变量建议添加前缀(如
MY_MODULE_XXX
),避免与其他模块冲突。
4.文档说明
在模块开头添加注释,说明模块功能、使用方法、依赖项(如 # AddMyTest.cmake: 简化 GTest 测试用例添加,依赖 googletest
)。
6.总结
CMake Modules 是简化配置的 “瑞士军刀”:
- 内置模块提供开箱即用的功能(依赖查找、特性检测等),避免重复造轮子;
- 自定义模块封装项目特有逻辑,提升配置复用性和一致性。
通过合理使用模块,可将复杂的 CMake 配置简化为 “引入模块 + 调用接口” 的简洁形式,尤其适合大型项目或多项目管理,显著降低维护成本。
相关链接
- CMake 官网 CMake - Upgrade Your Software Build System
- CMake 官方文档:CMake Tutorial — CMake 4.1.0 Documentation
- CMake 源码:https://github.com/Kitware/CMake
- CMake 源码:CMake · GitLab
- 中文版基础介绍: CMake 入门实战 | HaHack
- wiki: Home · Wiki · CMake / Community · GitLab
- Modern CMake 简体中文版: Introduction · Modern CMake