Visual Studio C++ 多项目解决方案设置

Adr*_*vry 10 c++ architecture project solution visual-studio

0. 免责声明

这个问题仅涉及Visual Studio C++ 项目/解决方案配置,可能涉及主观性。

然而,这篇文章背后的想法是分享我们配置大型 Visual Studio 解决方案的方法。

我不考虑任何像CMake/Premake这里 的工具。

1. 问题

  • 如何使用 Visual Studio 处理大规模 C++ 应用程序体系结构和配置?
  • 对于您来说,设置由多个项目组成的新 Visual Studio 解决方案的最佳方法是什么?
  • 您试图避免哪些 Visual Studio 项目/解决方案配置功能?(例如:过滤器而不是文件夹

2. 个人方法

2.1. 语境

我是一家视频游戏公司的软件开发人员,所以我将用一个非常简化的游戏引擎架构来说明我的话:

在此输入图像描述

2.2. 文件结构

我的 Visual Studio 解决方案可能如下所示:

在此输入图像描述

其中Application可执行文件,其他所有项目都是(动态链接)。

我的方法是将每个项目分成两个文件夹:includesrc

在此输入图像描述

内部结构将分为我的命名空间后面的文件夹:

在此输入图像描述

2.3. 项目配置

以下行将假设只有一个$(Configuration)可用$(Platform)(例如:Release-x64),并且为每个项目完成了对 .lib 文件的引用Linker/Input/Additional Dependencies

我将在这里定义一个Bin(输出)、Bin-Int(中间输出)和Build(组织输出)文件夹,假设它们位于$(SolutionDir)

  • $(SolutionDir)Bin\
  • $(SolutionDir)Bin-Int\
  • $(SolutionDir)Build\

和文件夹是编译器的游乐场,而该文件夹由每个项目构建后事件填充BinBin-IntBuild

  • $(SolutionDir)Build\$(ProjectName)\include\(项目包括)
  • $(SolutionDir)Build\$(ProjectName)\lib\(.lib 文件)
  • $(SolutionDir)Build\$(ProjectName)\bin\(.dll 文件)

这样,每个都$(SolutionDir)Build\$(ProjectName)\可以作为独立的库进行共享。

注意:以下说明可能会跳过$(SolutionDir)文件Build夹路径以简化阅读。

如果B依赖于ABuild\B\include\则将包含BA包括。同样的方式,Build\B\bin\将包含BA二进制文件,Build\B\lib\并将包含BA.lib 文件(当且仅当B可以A向用户公开时,否则,仅B将 .lib 文件添加到Build\B\lib\)。

项目相对于Build\文件夹引用自身。因此,如果B依赖于AB则 include 路径将引用$(SolutionDir)Build\A\include\(而不是$(SolutionDir)A\include\),因此 所使用的任何包含都A将可用B,而无需明确指定。(但结果取决于章节2.6.2.和技术2.6.3.限制2.6.4.)。

之后,我确保我的解决方案具有正确的Project Dependencies配置,以便Build Order在构建整个解决方案时,将考虑并尊重我的项目依赖项。

2.4. 用户项目配置

我们的EngineSDK用户(正在处理Application)只需进行Application如下设置:

  • 包括目录$(SolutionDir)Build\Engine\include\
  • 图书馆目录$(SolutionDir)Build\Engine\lib\
  • 构建后:复制$(SolutionDir)Build\Engine\bin\*$(OutDir)
  • 其他依赖项:依赖项层次结构中上游的任何 .lib 文件均在此处列出

这是很多C++库的典型Visual Studio配置流程。

我尝试保留的通用库文件夹架构:

lib\
include\
bin\
Run Code Online (Sandbox Code Playgroud)

以下是使用此文件夹架构模型的库的一些示例(请注意,这bin专门用于动态链接库,因为静态链接库不关心 DLL):

2.5. 优点

  • 清晰的文件夹架构
  • 能够通过复制粘贴或压缩子文件夹直接导出库$(SolutionDir)Build\

2.6。技术限制

我在这里写的方法有一些缺点。这些限制是这篇文章的原因,因为我想提高自己:

2.6.1. 繁琐的配置

处理 10 个或更少的项目没问题,但是,处理更大的解决方案(15 个以上项目)时,它很快就会变得一团糟。项目配置非常严格,项目架构的微小变化可能会导致项目配置和调试花费数小时。

2.6.2. 构建后限制

让我们考虑一个简单的依赖情况:

  • C依赖于BB依赖于A
  • C是可执行文件, 和BA
  • BA构建后事件更新其Build\$(ProjectName)\目录

当更改 的源代码A,然后编译它时,Build\A\就会更新。但是,正如B之前编译的那样(A更改之前),其Build\B\文件夹包含以前的二进制文件的副本A并包含。因此,执行C(仅作为依赖B项)将使用旧的A二进制文件/包含文件。我发现这个问题的解决方法是在执行之前手动触发B构建后事件C。然而,忘记在构建后触发中间项目可能会导致调试过程中的麻烦(未加载符号、错误行为......)。

2.6.3. 多次单标头引用

这种方法的另一个限制是“多次单个标头引用”。

这个问题可以通过考虑 2.1 节中的项目依赖关系图像来解释。考虑到GraphicsPhysics都包含Maths标头,即Engine包含Build\Graphics\include\Build\Physics\include\,输入标头名称将显示多个相同的结果:

在此输入图像描述

2.6.4. 不同步的符号引用

如果B依赖A并且任何标头发生更改A(例如,我们添加一个新函数),则需要Rescan File/才能从 访问新符号。Rescan SolutionB

此外,导航到文件或符号可能会使我们移动到错误的标题(复制的标题而不是原始的标题)。

3. 询问和学习观点

3.1. 项目参考

在我的 Visual Studio 软件开发之旅中,我经历了项目Reference概念,但我找不到它如何解决我当前方法的技术限制,也找不到它如何帮助我重新思考它。

3.2. 属性表

由于我的解决方案的每个项目配置都遵循相同的原则,但每个项目的内容(包括目录、库目录...)都不同,我不确定如何充分利用属性表。

3.3. 探索 GitHub

目前我正在努力寻找一些好的项目架构参考。我很高兴在 GitHub 或任何代码共享平台上找到一些 Visual Studio 配置的解决方案。(我知道这一点CMake,并且Premake在大多数情况下共享代码时更喜欢,但是,了解有关 Visual Studio 项目配置的更多信息是我的实际目标)。

感谢您阅读我的文字,我希望您也有兴趣讨论这个主题,也许我们可以分享我们的方法。