CMake中如何使用macro和file递归搜索指定目录下的所有C/C++源文件和头文件,避免手写所有文件?

目录

  1. 代码功能概述
  2. 关键命令解析
    • macro 命令详解
    • file 命令详解
  3. 代码逐行注释
  4. 如何发现和学习CMake命令
  5. 宏的实际应用场景
  6. 使用注意事项与替代方案

一、代码功能概述

代码示例:

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命令

  1. 官方文档
    CMake官方文档是最权威的参考:
    https://cmake.org/cmake/help/latest/

    • 使用左侧导航栏查找命令(如搜索"macro"或"file")
    • 每个命令页面包含详细语法和示例
  2. CMake模块示例
    CMake安装目录下的Modules文件夹包含大量实用模块,可学习其实现方式:

    # Linux/macOS查看CMake模块目录
    ls /usr/share/cmake-*/Modules/
    
  3. 社区资源

    • CMake官方Wiki:https://gitlab.kitware.com/cmake/community/wikis
    • Stack Overflow的CMake标签:https://stackoverflow.com/questions/tagged/cmake
    • GitHub上的优秀项目:搜索大型C++项目的CMakeLists.txt学习
  4. CMake命令自动补全

    • 多数IDE(如CLion、VS Code)支持CMake命令自动补全
    • 在终端中使用cmake --help-command <命令名>查看帮助

五、宏的实际应用场景

  1. 自动收集源文件

    glob_sources(ALL_SOURCES "src")
    add_executable(my_app ${ALL_SOURCES})
    
  2. 模块化项目结构

    # 在子目录的CMakeLists.txt中
    glob_sources(MODULE_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}")
    add_library(my_module ${MODULE_SOURCES})
    
  3. 条件编译

    if(ENABLE_TESTS)
        glob_sources(TEST_SOURCES "tests")
        add_executable(run_tests ${TEST_SOURCES})
    endif()
    

六、使用注意事项与替代方案

  1. GLOB_RECURSE的局限性

    • CMake只在第一次运行时执行GLOB,新增文件需重新运行cmake
    • 搜索顺序可能因平台而异,影响编译结果
  2. 替代方案:手动列出文件

    set(ALL_SOURCES
        src/main.cpp
        src/util/util.h
        src/util/util.cpp
        # 显式列出所有文件
    )
    
  3. 改进宏定义
    可添加错误检查和日志输出:

    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,大型项目建议手动管理源文件列表
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

行知SLAM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值