目录
- 代码功能概述
- 关键命令解析
macro
命令详解file
命令详解
- 代码逐行注释
- 如何发现和学习CMake命令
- 宏的实际应用场景
- 使用注意事项与替代方案
一、代码功能概述
代码示例:
macro(glob_sources sources_var sources_path)
file(GLOB_RECURSE ${sources_var} ${sources_path}/*.h ${sources_path}/*.c
${sources_path}/*.cc ${sources_path}/*.cpp ${sources_path}/*.cxx)
endmacro()
这段CMake代码定义了一个名为 glob_sources
的宏,用于递归搜索指定目录下的所有C/C++源文件和头文件,并将结果存储在指定变量中。其核心作用是自动收集项目源文件,避免在CMakeLists.txt中手动列出每个文件。
二、关键命令解析
1. macro
命令详解
功能:定义可重复使用的代码片段,类似于函数,但不支持返回值。
语法:
macro(<宏名称> <参数1> <参数2> ...)
# 宏体代码
# 使用 ${参数名} 引用传入的参数
endmacro()
关键点:
- 参数传递通过位置匹配,无需类型声明
- 宏内部可使用所有CMake命令
- 宏调用时参数会直接替换到宏体中(类似C语言的#define)
示例:
# 定义宏
macro(add_two_numbers a b)
math(EXPR result "${a} + ${b}")
message(STATUS "${a} + ${b} = ${result}")
endmacro()
# 调用宏
add_two_numbers(3 5) # 输出: 3 + 5 = 8
2. file
命令详解
功能:提供文件操作的各种功能,如文件搜索、读取、写入等。
常用模式:
GLOB
:搜索匹配的文件(非递归)GLOB_RECURSE
:递归搜索匹配的文件WRITE
:写入内容到文件READ
:读取文件内容COPY
/REMOVE
:复制/删除文件
GLOB_RECURSE
语法:
file(GLOB_RECURSE <变量名>
<路径1>/<模式1>
<路径2>/<模式2>
...
)
示例:
# 递归搜索src目录下的所有cpp文件
file(GLOB_RECURSE ALL_CPP_FILES "src/*.cpp")
# 打印结果
foreach(file ${ALL_CPP_FILES})
message(STATUS "找到文件: ${file}")
endforeach()
三、代码逐行注释
# 定义名为glob_sources的宏,接收两个参数:
# sources_var:用于存储搜索结果的变量名
# sources_path:要搜索的目录路径
macro(glob_sources sources_var sources_path)
# 使用file命令的GLOB_RECURSE模式递归搜索文件
# 搜索结果将存储在${sources_var}变量中
file(GLOB_RECURSE ${sources_var}
${sources_path}/*.h # 匹配所有.h头文件
${sources_path}/*.c # 匹配所有.c C源文件
${sources_path}/*.cc # 匹配所有.cc C++源文件
${sources_path}/*.cpp # 匹配所有.cpp C++源文件
${sources_path}/*.cxx # 匹配所有.cxx C++源文件
)
endmacro() # 宏定义结束
四、如何发现和学习CMake命令
-
官方文档
CMake官方文档是最权威的参考:
https://cmake.org/cmake/help/latest/- 使用左侧导航栏查找命令(如搜索"macro"或"file")
- 每个命令页面包含详细语法和示例
-
CMake模块示例
CMake安装目录下的Modules
文件夹包含大量实用模块,可学习其实现方式:# Linux/macOS查看CMake模块目录 ls /usr/share/cmake-*/Modules/
-
社区资源
- CMake官方Wiki:https://gitlab.kitware.com/cmake/community/wikis
- Stack Overflow的CMake标签:https://stackoverflow.com/questions/tagged/cmake
- GitHub上的优秀项目:搜索大型C++项目的CMakeLists.txt学习
-
CMake命令自动补全
- 多数IDE(如CLion、VS Code)支持CMake命令自动补全
- 在终端中使用
cmake --help-command <命令名>
查看帮助
五、宏的实际应用场景
-
自动收集源文件
glob_sources(ALL_SOURCES "src") add_executable(my_app ${ALL_SOURCES})
-
模块化项目结构
# 在子目录的CMakeLists.txt中 glob_sources(MODULE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}") add_library(my_module ${MODULE_SOURCES})
-
条件编译
if(ENABLE_TESTS) glob_sources(TEST_SOURCES "tests") add_executable(run_tests ${TEST_SOURCES}) endif()
六、使用注意事项与替代方案
-
GLOB_RECURSE的局限性
- CMake只在第一次运行时执行GLOB,新增文件需重新运行cmake
- 搜索顺序可能因平台而异,影响编译结果
-
替代方案:手动列出文件
set(ALL_SOURCES src/main.cpp src/util/util.h src/util/util.cpp # 显式列出所有文件 )
-
改进宏定义
可添加错误检查和日志输出:macro(glob_sources sources_var sources_path) if(NOT EXISTS ${sources_path}) message(WARNING "搜索路径不存在: ${sources_path}") set(${sources_var} "") return() endif() file(GLOB_RECURSE ${sources_var} ${sources_path}/*.h ${sources_path}/*.c ${sources_path}/*.cc ${sources_path}/*.cpp ${sources_path}/*.cxx ) message(STATUS "在${sources_path}中找到${${sources_var}_COUNT}个源文件") endmacro()
总结
- macro:用于创建可复用的CMake代码片段,通过参数传递增强灵活性
- file(GLOB_RECURSE):递归搜索文件的便捷方式,但需注意缓存问题
- 学习资源:官方文档、社区项目和IDE自动补全是掌握CMake的关键工具
- 最佳实践:小型项目可使用GLOB,大型项目建议手动管理源文件列表