当前位置: 首页 > news >正文

CMake项目中如何按目录结构分离显示Header和Source文件

🚀 CMake项目中如何让VS2010按目录结构分离显示Header和Source文件(含注释详解)

🔧 适用版本:CMake ≥ 2.8,Visual Studio 2010及以上

💡 前言

我们在使用 CMake 为 Visual Studio 2010 生成工程文件时,默认所有源文件都会被“扁平化”放在项目里,这对大型项目来说非常不利 —— 阅读混乱、模块划分不清晰。

如何实现 按目录结构显示 + .cpp 和 .h 文件分离在“Source Files”和“Header Files”文件夹中 呢?答案就是 —— source_group()!

📁 示例目录结构(带子目录)

为了说明方便,我们使用如下项目结构:

MyProject/
├── CMakeLists.txt            # 顶层 CMake 文件
├── src/
│   ├── main.cpp
│   ├── app/
│   │   ├── logic.cpp
│   │   └── logic.h
│   └── util/
│       ├── helper.cpp
│       └── helper.h

我们的目标是在 Visual Studio 2010 工程中生成如下分组结构:

MyApp
├── Header Files
│   ├── app
│   │   └── logic.h
│   └── util
│       └── helper.h
├── Source Files
│   ├── app
│   │   └── logic.cpp
│   └── util
│       └── helper.cpp

添加 src 子目录下的 CMakeLists.txt

add_subdirectory(src)
🧠 关键语法解析 + src/CMakeLists.txt 完整代码

递归获取当前目录下所有头文件(.h 和 .hpp)

file(GLOB_RECURSE HEADER_FILES"${CMAKE_CURRENT_SOURCE_DIR}/*.h""${CMAKE_CURRENT_SOURCE_DIR}/*.hpp"
)

递归获取当前目录下所有源文件(.cpp 和 .c)

file(GLOB_RECURSE SOURCE_FILES"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp""${CMAKE_CURRENT_SOURCE_DIR}/*.c"
)

遍历头文件列表,为每个文件设置 source_group

foreach(file ${HEADER_FILES})# 获取该文件相对于当前目录的路径(如 app/logic.h)file(RELATIVE_PATH rel_path "${CMAKE_CURRENT_SOURCE_DIR}" "${file}")# 提取路径部分(如 app),用于后续分组get_filename_component(dir_path "${rel_path}" PATH)# 将路径中的斜杠 '/' 替换为 Windows 风格的 '\\'string(REPLACE "/" "\\" group_path "${dir_path}")# 设置 VS 工程中过滤器(即虚拟目录)为 "Header Files\app" 这类结构source_group("Header Files\\${group_path}" FILES "${file}")
endforeach()

同理,遍历源文件列表,为每个源文件设置 source_group

foreach(file ${SOURCE_FILES})file(RELATIVE_PATH rel_path "${CMAKE_CURRENT_SOURCE_DIR}" "${file}")get_filename_component(dir_path "${rel_path}" PATH)string(REPLACE "/" "\\" group_path "${dir_path}")source_group("Source Files\\${group_path}" FILES "${file}")
endforeach()

创建一个可执行程序 MyApp,并包含所有源文件和头文件

add_executable(MyApp ${SOURCE_FILES} ${HEADER_FILES})
🔍 各关键 CMake 命令解释
命令	含义
file(GLOB_RECURSE ...)	递归查找所有匹配的文件(如所有 .cpp, .h)
file(RELATIVE_PATH)	将文件路径转为相对路径(用于构造 VS 分组)
get_filename_component(... PATH)	获取路径中的目录部分(不含文件名)
string(REPLACE "/" "\\" ...)	把路径从 Linux 风格改为 Windows 风格,VS 识别 \\ 目录结构
source_group(...)	为 Visual Studio 指定工程结构的“过滤器”(类似于文件夹)
add_executable(...)	构建目标程序,并包含所有指定源文件

✅ 效果验证(Visual Studio 2010 中)
打开你生成的 .sln 工程,进入“解决方案资源管理器”,你会看到:

Header Files → 子目录 → 头文件

Source Files → 子目录 → 源文件

文件并不会混在一起,层级结构清晰明了!

🧩 常见问题排查
问题 解决方法
.cpp 和 .h 没分开 是否为它们分别调用了 source_group(),路径是否用双斜线
分组没生效 source_group 只影响已被 add_executable()/add_library() 引用的文件
分组只有顶层,不是多级 RELATIVE_PATH 的基准路径要选对;替换路径斜线时必须用 \
工程结构没更新 清理 CMake 缓存,重新 Configure & Generate 一遍

📦 进阶建议(支持多模块库、静态库)

你也可以将此逻辑封装成函数,比如:

# 功能:自动将源文件和头文件按目录结构分组到 VS 的过滤器中
# 参数:
#   target_name:目标名称(用作变量前缀)
#   base_dir   :文件扫描根目录function(assign_source_filters target_name base_dir)# 扫描头文件和源文件file(GLOB_RECURSE HEADERS "${base_dir}/*.h" "${base_dir}/*.hpp")file(GLOB_RECURSE SOURCES "${base_dir}/*.cpp" "${base_dir}/*.c")# 分组头文件foreach(file IN LISTS HEADERS)file(RELATIVE_PATH rel "${base_dir}" "${file}")get_filename_component(path "${rel}" PATH)string(REPLACE "/" "\\" group "${path}")source_group("Header Files\\${group}" FILES "${file}")endforeach()# 分组源文件foreach(file IN LISTS SOURCES)file(RELATIVE_PATH rel "${base_dir}" "${file}")get_filename_component(path "${rel}" PATH)string(REPLACE "/" "\\" group "${path}")source_group("Source Files\\${group}" FILES "${file}")endforeach()# 导出变量以便 add_executable/add_library 使用set(${target_name}_HEADERS ${HEADERS} PARENT_SCOPE)set(${target_name}_SOURCES ${SOURCES} PARENT_SCOPE)
endfunction()

🎯 使用方式:

# 调用函数,传入目标名和源文件根目录
assign_source_filters(MyApp "${CMAKE_CURRENT_SOURCE_DIR}")

✅ 实现方式(只保留最后一级目录)

# 递归查找 src 下所有头文件
file(GLOB_RECURSE HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h")set(INCLUDE_DIRS "")
foreach(header IN LISTS HEADERS)# 获取头文件所在目录get_filename_component(full_dir "${header}" DIRECTORY)# 提取最后一级目录名get_filename_component(last_dir "${full_dir}" NAME)
if(NOT "${A}" STREQUAL "${B}")# 只添加 app / util,不含 srclist(APPEND INCLUDE_DIRS "${last_dir}")
endif()endforeach()# 去重
list(REMOVE_DUPLICATES INCLUDE_DIRS)# 添加为相对路径(相对于 ${CMAKE_CURRENT_SOURCE_DIR})
# 假设 app/util 都在 src 目录下
foreach(dir IN LISTS INCLUDE_DIRS)list(APPEND FINAL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src/${dir}")
endforeach()# 加入到 VS 工程 include path
target_include_directories(MyApp PRIVATE ${FINAL_INCLUDE_DIRS})

🏁 总结
在 VS2010 中想要实现“源文件”和“头文件”分组,并保留子目录结构,不是简单使用 GLOB_RECURSE 就能做到的,而是需要配合 source_group()、路径处理等一整套方法。通过本文,你可以轻松让 CMake 生成的 VS 项目结构清晰明了,提升开发效率!

http://www.dtcms.com/a/308050.html

相关文章:

  • LPC2132GPIO
  • Ubuntu 内网多台服务器时间同步方案(适用于临时能上外网的环境)
  • 电商作图:解锁“素材裂变”和“产品测款”新姿势
  • Zombie Process
  • Apache Camel 简介
  • STM32 USB 设备中间件 tinyusb
  • 开疆智能Profient转Modbus网关连接MAG8000电池流量计配置案例
  • 快速入门开源项目若依
  • FISCO BCOS Gin调用WeBASE-Front接口发请求
  • 【Kiro Code】Chat 聊天功能
  • React的介绍和特点
  • Linux的访问权限(保姆级别)
  • 深入浅出HTML5 CSS类扩展:getElementsByClassName和classList属性
  • Vercel 全面介绍与网站部署指南
  • CSS和XPATH选择器对比
  • AI与AGI:从狭义智能到通用智能
  • Opus音频编码器全解析:从技术原理到实战应用
  • C++_HELLO算法_哈希表的简单实现
  • Docker 实战 -- cloudbeaver
  • C语言---结构体(格式、用法、嵌套、初始化)、共用体、枚举类型、typedef类型
  • 【RAG Query Expansion论文解析】用 LLM 进行查询扩展 (Query Expansion)
  • 在MySQL中DECIMAL 类型的小数位数(Scale)如何影响分组查询?
  • 30天入门Python(基础篇)——第25天:标准库学习之OS模块
  • 一次 web 请求响应中,通常那个部分最耗时?
  • git ETAS包 使其可以本地编辑
  • 借助于llm将pdf转化为md文本
  • PDF源码解析
  • 数据结构第4问:什么是栈?
  • CUDA系列之CUDA安装与使用
  • freeRTOS 消息队列