CMake指令:source_group

目录

1.简介

2.核心功能与用法

2.1. 按文件类型分组(如头文件、源文件)

2.2.按目录结构分组(自动映射文件夹层级)

2.3.与 target_sources 结合使用

3. TREE 参数

4.高级用法

5.总结


1.简介

        在 CMake 中,source_group 命令用于在集成开发环境(IDE,如 Visual Studio、Xcode、CLion 等)中组织源代码的逻辑分组显示,使项目结构在 IDE 的文件视图中更清晰易读,类似Visual Studio提供的filter机制来分类显示源文件。它不会影响编译逻辑,仅用于调整 IDE 中源文件的分组展示方式。

        该命令相当于VS里面给编译需要的文件归类,把一些相同性质的文件放一个类里面,这些“类”,可以在VS 图形界面下左边(一般情况下),看到header文件夹下面的H文件,source文件夹下的C/C++源文件,resource文件夹下的res资源脚本文件。

        基本语法:

source_group(<group_name> FILES <file1> <file2> ...)
  • <group_name>:指定 IDE 中显示的分组名称(支持嵌套路径,如 Headers/Utils)。
  • <file1> <file2>...:需要归入该分组的源文件路径(相对当前 CMake 目录)。

2.核心功能与用法

2.1. 按文件类型分组(如头文件、源文件)

# 将所有头文件归入 "Headers" 分组
source_group("Headers" FILES ${PROJECT_SOURCE_DIR}/include/*.h ${PROJECT_SOURCE_DIR}/include/*.hpp)

# 将所有源文件归入 "Sources" 分组
source_group("Sources" FILES ${PROJECT_SOURCE_DIR}/src/*.cpp ${PROJECT_SOURCE_DIR}/src/*.cxx)
  • 在 IDE 中会显示为独立的 Headers 和 Sources 文件夹分组。

2.2.按目录结构分组(自动映射文件夹层级)

若源代码目录结构为:

project/
├─ include/
│  ├─ utils/
│  │     └─ math.h
│  └─ main.h
└─ src/
   ├─ utils/
   │     └─ math.cpp
   └─ main.cpp

可通过以下方式在 IDE 中映射目录结构:

# 递归按目录结构分组(需结合 file(GLOB_RECURSE))
file(GLOB_RECURSE HEADERS "${PROJECT_SOURCE_DIR}/include/**/*.h" "${PROJECT_SOURCE_DIR}/include/**/*.hpp")
file(GLOB_RECURSE SOURCES "${PROJECT_SOURCE_DIR}/src/**/*.cpp" "${PROJECT_SOURCE_DIR}/src/**/*.cxx")

# 为头文件生成分组路径(如 "include/utils/math.h" 对应 IDE 中的 "include/utils" 分组)
foreach(HEADER ${HEADERS})
    get_filename_component(REL_PATH ${HEADER} RELATIVE_TO ${PROJECT_SOURCE_DIR}/include)
    string(REPLACE "\\" "/" GROUP_PATH "include/${REL_PATH}")
    string(REPLACE "/${REL_PATH}" "" GROUP_PATH ${GROUP_PATH})  # 提取目录部分作为分组名
    source_group(${GROUP_PATH} FILES ${HEADER})
endforeach()

# 同理处理源文件(分组名以 "src/" 开头)
foreach(SOURCE ${SOURCES})
    get_filename_component(REL_PATH ${SOURCE} RELATIVE_TO ${PROJECT_SOURCE_DIR}/src)
    string(REPLACE "\\" "/" GROUP_PATH "src/${REL_PATH}")
    string(REPLACE "/${REL_PATH}" "" GROUP_PATH ${GROUP_PATH})
    source_group(${GROUP_PATH} FILES ${SOURCE})
endforeach()
  • 最终在 IDE 中,文件会按实际目录层级显示在对应的分组下(如 include/utils 和 src/utils 分组)。

2.3.与 target_sources 结合使用

通常在使用 target_sources 向目标添加文件前,先用 source_group 定义分组:

add_executable(my_app)

# 定义分组
source_group("Headers" FILES ${HEADERS})
source_group("Sources" FILES ${SOURCES})

# 添加文件到目标(分组信息会传递给 IDE)
target_sources(my_app PRIVATE ${HEADERS} ${SOURCES})

3. TREE 参数

首先看条命令:

source_group(TREE "${PROJECT_SOURCE_DIR}/include/minidocx"
  PREFIX "Header Files" FILES ${headers})

source_group 命令是 CMake 中用于在 IDE 中组织源代码显示的高级用法,特别是使用了 TREE 参数 来自动映射目录结构。这条命令的作用是:将 include/minidocx 目录下的头文件按原目录层级映射到 IDE 的 "Header Files" 分组中。

命令解析

source_group(
    TREE "${PROJECT_SOURCE_DIR}/include/minidocx"  # 源目录(作为分组根)
    PREFIX "Header Files"                         # 分组前缀(IDE 中显示的顶级分组名)
    FILES ${headers}                              # 要分组的文件列表(通常是头文件集合)
)

核心参数说明

1.TREE <directory>

  • 指定源目录,CMake 会递归遍历该目录的结构,并以此为基础生成 IDE 中的分组。
  • 例如,若源目录为 include/minidocx/utils,则该目录下的文件会在 IDE 中显示为 Header Files/utils 分组。

2.PREFIX <prefix>

  • 指定 IDE 中显示的顶级分组名称。所有子分组都会嵌套在这个名称下。
  • 例如,设置为 "Header Files" 时,IDE 会显示为:
Header Files/
├─ core/
├─ utils/
└─ format/

3.FILES <files>

  • 列出要分组的文件(通常是通过 file(GLOB) 收集的头文件列表)。
  • 这些文件必须位于 TREE 指定的目录或其子目录中。

实际效果示例

假设目录结构如下:

project/
└─ include/
   └─ minidocx/
      ├─ core/
      │     └─ document.h
      ├─ utils/
      │     ├─ string_utils.h
      │     └─ file_utils.h
      └─ format/
            └─ xml_writer.h

使用上述命令后,在 Visual Studio 或 CLion 中会显示为:

Header Files/
├─ core/
│     └─ document.h
├─ utils/
│     ├─ string_utils.h
│     └─ file_utils.h
└─ format/
      └─ xml_writer.h

与传统 source_group 的对比

传统方式需要手动为每个子目录定义分组:

source_group("Header Files\\core" FILES ${headers_core})
source_group("Header Files\\utils" FILES ${headers_utils})
source_group("Header Files\\format" FILES ${headers_format})

而 TREE 参数可以自动处理嵌套结构,避免手动维护大量分组定义,特别适合大型项目。

注意事项:路径匹配要求

  • FILES 中的文件必须位于 TREE 指定的目录或其子目录中,否则会被忽略。
  • 例如,若 TREE 为 include/minidocx,但 FILES 包含 src/main.cpp,则该文件不会被分组。

4.高级用法

1.正则表达式与动态分组

若需按文件名模式(如测试文件、生成文件)分组,可结合 file(GLOB) 和正则表达式:

# 提取所有测试文件并归入 "Tests" 分组
file(GLOB TEST_SOURCES "${PROJECT_SOURCE_DIR}/tests/*.cpp")
string(REGEX REPLACE "${PROJECT_SOURCE_DIR}/" "" TEST_SOURCES "${TEST_SOURCES}")  # 转换为相对路径
source_group("Tests" FILES ${TEST_SOURCES})

2.同时处理头文件和源文件

# 头文件分组
source_group(
    TREE "${PROJECT_SOURCE_DIR}/include/minidocx"
    PREFIX "Header Files"
    FILES ${headers}
)

# 源文件分组
source_group(
    TREE "${PROJECT_SOURCE_DIR}/src"
    PREFIX "Source Files"
    FILES ${sources}
)

3.排除特定目录

若要排除 include/minidocx/internal 目录,可先过滤文件列表:

file(GLOB_RECURSE headers "${PROJECT_SOURCE_DIR}/include/minidocx/*.h")
list(FILTER headers EXCLUDE REGEX "${PROJECT_SOURCE_DIR}/include/minidocx/internal/")

source_group(
    TREE "${PROJECT_SOURCE_DIR}/include/minidocx"
    PREFIX "Header Files"
    FILES ${headers}
)

5.总结

  source_group适合需要多人协作或复杂目录结构的工程。source_group(TREE ...) 更是通过自动映射目录结构,避免了手动维护复杂分组的繁琐工作。提升了项目在 IDE 中的可读性和可维护性。

相关链接

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值