相当于 Visual Studio C++ "filters" 的 CLion

CLion equivalent of Visual Studio C++ "filters"

上下文

在 Visual Studio IDE 中,对于 C++ 解决方案,您可以使用所谓的“过滤器”来模拟源文件 tree/directories,同时通常在每个项目中保留每个项目的所有源代码项目的根。主要优点是能够直接 #include "foo.h"

我一直在尝试将一些解决方案“切换”到 CLion,因为它专注于多平台,并试图将对 CMake+GCC 的支持添加到现有的 VS 解决方案中,因为没有跨平台 IDE本机支持 .sln/.vcxproj 个文件

现在 - 我知道一些较大的 CMake 项目(如 solution/group 的子项目)经常使用普通文件系统子目录来进一步分解每个子项目中的代码,但由于一些“解决方案”我'我正在尝试添加 CMake 支持,考虑到几百个源文件,我真的无法手动重构所有内容并将每个文件中的 #include "service_foo.h" 更改为 #include service/service_foo.h

还要考虑的另一件事是,我没有迁移解决方案以使用 CMake - 我正在添加对 CMake builds/CLion IDE 的支持以及 MSBuild toolchain/VS IDE 支持,所以我不想引入任何重大更改。

我对 JetBrains IDE 生态系统还是很陌生,所以我想知道是否有什么东西可以开箱即用地提供这种功能,或者可能带有插件。

问题

是否有任何方法可以在不对文件系统进行更改的情况下将源文件分组,即在 CLion 的项目视图工具箱中 IDE?

到目前为止在文档中找不到任何内容,但它与 Code Hierarchy 类似,但用于 .h/.cpp 个文件。

例子

文件系统结构(在磁盘上可见)
$REPO_ROOT*.vcxproj, .idea/ 等提供的存储库

Main CMakeList.txt: $REPO_ROOT/CmakeList.txt
Example subprojects: $REPO_ROOT/foo_slib/ $REPO_ROOT/program/
Example Source files: $REPO_ROOT/program/main.cpp $REPO_ROOT/program/gui_init.h $REPO_ROOT/program/VulkanDelegate.h 

Project/solution 根级结构(如 IDE 中的项目工具箱视图所示)
$VIEW_ROOT 是为 CLion 打开的主项目或为 MSVS 打开的 .sln,如每个 IDE

的项目视图中所示
Main CmakeList.txt: $VIEW_ROOT/CMAKE/CmakeList.txt
Example subprojects: $VIEW_ROOT/foo_slib/ $VIEW_ROOT/program/
Example Source files: $VIEW_ROOT/program/main.cpp $VIEW_ROOT/program/GUI/gui_init.h $VIEW_ROOT/program/Delegates/VulkanDelegate.h

您肯定不需要编辑源文件和更改包含路径。没有什么能阻止您使用编译器 include path option, -I<path>. In CLion, it's controlled through CMake's target_include_directories 指令实现相同的 #include 路径。您可能还需要弄清楚项目是如何链接的。

您可以将文件和文件夹添加到 CLion 的 favorites。您可以拥有多组收藏夹,因此可以模拟项目中的任意虚拟文件夹。

对于更详细的查询语言,有 Scopes. You can set them up, and then they will appear in the Views dropdown of the Project view,每个作为一个单独的视图。

如果其他人需要此功能,这就是我最终做的事情

解决方案

假设您所有的 MSVS 项目(目标)都存储在 ./src/ 的根目录中(./ 是 repo root),基于每个项目的目录

  1. 在 repo 根目录创建同级目录,比如 ./src_cmake/
  2. 为存储在 ./src/ 中的每个项目创建目录 ./src_cmake/,假设我们已将 ./src_cmake/libproj/ 对应于 ./src/libproj/
  3. libproj为例,将./src_cmake/libproj/中的子目录对应到Visual Studio[=110]中那个项目的filter树结构=]
  4. 在每个 filter 子目录 中,创建文件 symlinks 到与过滤器内每个文件对应的源文件,假设 Solution>libproj>Debugonly> in [=149] =] 包含 debmeta.h debmeta.cpp debutil.h,需要在 ./src_cmake/libproj/Debugonly/ 创建 3 个新的 symlink 文件,我们以 debmeta.h 为例
  5. 您可以使用 ln -s ORIGINALFILE LINKTARGET 创建 symlinks,因此在 shell 打开 ./src_cmake/libproj/Debugonly/ 时使用命令
// This will navigate 3 directories down to repo root and from there to debmeta relative path
ln -s ../../../src/libproj/debmeta.h debmeta.h
  1. 这很容易出错(例如将来重命名项目),并且可能需要恢复数百个 symlinks。至少要否定它,你可以这样做
// Shell open at ./src_cmake/libproj/ instead
ln -s ../../src/libproj .link
cd Debugonly

// Now use the .link folder so all links will be routed through it instead
ln -s ../.link/debmeta.h debmeta.h

// From now on use .link folder instead to navigate to original project directory, in case of breaking changes like new name of this subproject (at ./src_cmake/libproj/)
rm .link
ln -s ../../renamedsrc/renamedproj .link

// This way you shouldn't have to worry about cmake tree breakage
  1. 如果你做了所有的事情,你最终应该得到 ./src_cmake/ 树看起来像你的 Visual Studio 项目视图树
  2. 现在在 ./CMakeList.txt 中添加子项目,您应该单独调用 add_subdirectory() 到每个项目,以便 Clion 像示例中那样正确选择目标
add_subdirectory(src_cmake/libproj)
add_subdirectory(src_cmake/exeproj)
  1. 对于 ./src_cmake/ 中的每个子项目,您应该添加新的 CMakeList 以某种方式对应于 ./src/ 中的 .vcxproj,例如 - ./src_cmake/libproj/CMakeList.txt
  2. 在每个这样的 CMakeList 中添加 target_include_directories() 并包括该项目的所有过滤器子目录,以示例为例
target_include_directories(libproj
    PRIVATE Debugonly
)
  1. 现在,由于您很可能没有手动执行任何操作(如下所述),您可能会提供脚本来生成过滤器结构和 symlinks 对于 ./src_cmake/ 而不是按原样运送文件夹,这意味着您不想跟踪 CMakeList.txt 之外的任何内容对于 ./src_cmake/ 并且想要忽略 symlinks 污染您的版本控制(VSC ) 因为这些会导致代码更改重复
    为防止在 ./src_cmake/ 处创建额外的 .gitignore
# Choose which one better fits your needs, but first one should be prefered

# Ignore everything other than CMakeList.txt
*
!*/
!CMakeList.txt

# Or only ignore source code (in case of C/++
*.c
*.cpp
*.h
  1. 这样你应该设置所有文件系统端,现在在 Clion IDE Project Toolbox 中你将设置范围(相当于解决方案过滤器 .slnf 来自 Visual Studio)
  2. 现在 Edit scopes>Add(+)>Shared>递归包含 这些路径 ./src_cmake/ ./CMakeList.txt(当然你可以 include/exclude 其他你喜欢的东西,比如 .gitignore )
  3. 现在切换到你的新范围,你最终应该得到一些可以通过 Visual Studio C++
  4. 的项目视图的东西

XX。想想 CMakeList 以某种方式在 .sln 文件的 repo root 和项目文件夹中的 CmakeList 作为每个 .vcxproj,这是不't pollution root CMakeList with project local configuration
这样保持 MSVS 和 CMake 同步,应该更容易

虽然没有人应该手动完成所有这些,因此您可以制作一个简单的脚本:

  1. 传递$SRCROOT(MSVS项目目录)所以./src$OUTROOT(CMake项目目录)所以./src_cmake
  2. 对于 $SRCROOT 的每个子目录,在 $OUTROOT 创建目录,名称取自 .vcxproj,并在每个主题中创建 symlink 像这样 $OUTROOT/$VCXPROJNAME/.link->$CD(最好是相对路径,如果你可以计算一个)
  3. 在每个 subfolder/project 中对 .vcxproj 使用 xml 解析器,获取每个 <ClInclude> 属性 和对应的 <Filter> 值 - 创建$OUTROOT/$VCXPROJNAME/$FilterVal
  4. 处不存在此类 if 的相对路径
  5. 对于这些 <ClInclude> 属性中的每一个,根据提供的值创建 symlink 文件,并作为 link 目标使用 .link 的相对路径,例如 $OUTROOT/$FilterVal/$ClIncludeVal->$(.link)/$ClIncludeVal
  6. 这应该在 $OUTROOT 处模拟过滤器结构,然后您可以从那里递归迭代它,为每个 subproject/target 生成基本的 CMakeList.txt,只有 target_include_directories() 和源文件路径