递归构建解决方案时构建过程挂起

Build process hangs when recursively building solution

在尝试回答 时遇到了一个我无法解释的问题,非常感谢您的意见。

设置:

  1. 有包含多个 C++ 项目的解决方案 (Test.sln),
  2. 向您的解决方案添加一个全新的项目 (BuildInstaller.vcxproj),
  3. 在文本编辑器中打开 BuildInstaller.vcxproj 并在关闭 </Project> 标签之前附加以下 xml 片段:
<Target Name="Build">
  <MSBuild Projects="..\Test.sln" Properties="Configuration=Release;Platform=Win32" />
  <MSBuild Projects="..\Test.sln" Properties="Configuration=Release;Platform=x64" />
</Target>
  1. 上面的代码覆盖了 BuildInstaller 项目的默认 Build 目标,并且每次构建项目时,它都会为 Win32 和 x64 平台构建具有发布配置的父解决方案,
  2. 为防止无限递归,在 Visual Studio 中打开 Configuration Manager 并取消选中 Debug/Release 和 Win32/x64、[=35= 的所有组合的 BuildInstaller 项目的 "Build" 复选框]
  3. 然后,仍然在配置管理器中,创建一个新配置,例如您应该取消选中所有其他项目的“构建”复选框并仅选中“BuildInstaller”的安装程序,
  4. 现在为安装程序配置构建解决方案。

我希望此构建能够成功完成,但它只是挂起,即使不应递归构建 BuildInstaller,因为我们递归构建 Test.sln 仅用于发布配置。

我不是在问这是否是一个好方法或如何解决它,我只是好奇构建挂起的原因。将输出 window verbosity 设置为 Diagnostic 对我没有帮助。

我正在使用 Visual Studio 2013 Ultimate。

MSBuild 对项目中的递归有内部保护。通常情况下,如果在构建图中发现任何类型的循环依赖,您的构建将失败并显示错误 MSB4006。也就是说,如果我要猜测可能导致挂起的原因,并且如果它与递归有关,我会倾向于 .sln 文件。原因是 MSBuild 处理 .sln 文件的方式非常特殊。每当遇到 .sln 文件时,它都会将其转换为实际 MSBuild 引擎可以理解的中间表示形式。该中间表示没有任何类似于项目文件的标识符,因此如果 .sln 在循环中,循环依赖检测逻辑可能无法正常工作。

要解决您的特定问题,有两种方法。最简单的方法是从 Test.sln 中删除 BuildInstaller.vcxproj。第二种是修改BuildInstaller.vcxproj如下:

首先,创建一个 ItemGroup,其中填充了解决方案中的所有项目:

<ItemGroup>
    <AllMyProjects Include="..\Proj1\Proj1.vcxproj" />
    <AllMyProjects Include="..\Proj2\Proj2.vcxproj" />
    ...
    <!-- DO NOT ADD BuildInstaller project to prevent recursion!!! -->
</ItemGroup>

然后为每个配置构建项目:

<Target Name="Build">
    <MSBuild Projects="@AllMyProjects" Properties="Configuration=Release;Platform=Win32" />
    <MSBuild Projects="@AllMyProjects" Properties="Configuration=Release;Platform=x64" />
</Target>

第二种方法的缺点是您必须记住在 .sln 和安装程序项目之间保持项目列表同步。