我的组织有一些在构建服务器上运行的大型构建,构建批次以及许多与ProjectReferences链接的MSBUILD项目。我们需要能够与msbuild /m
并行构建项目和配置。
我的问题是我有一个从大量其他项目引用的项目,但项目本身不可重入。如果有两个或更多节点尝试并行构建该项目,则会失败。
如何在关键部分内包装这个项目,或者它的目标?
我真正需要做的是这样的事情:
<Target>
<EnterCriticalSection ID=$(ProjectGuid) />
<Exec something />
<LeaveCriticalSection ID=$(ProjectGuid) />
</Target>
这个想法是,如果多个MSBUILD节点试图建立并行这个项目中,只有节点可以做执行,和其余节点之一将不得不等待(或者去做些别的事情)。
我想我可以编写自定义MSBUILD任务来执行此操作,但是在MSBUILD系统中是否有某种方法可以执行此操作?
=== 编辑4/5/13 。为了澄清,该项目正在构建一个第三方库,其中提供了构建脚本。完全重写他们的构建脚本以使其可重入 - 通过确保每个构建使用不同的文件夹集合用于中间文件等 - 在理论上是可能的,但不是实际的解决方案。首先,所有这些工作都必须在该库的每个新版本上重做。
=== 编辑4/6/13 。经过进一步思考,我认为理论上不可能确保项目是可重入的。让我解释一下:
假设项目XYZ设置为使用不同的临时目录,具体取决于平台和配置,通常如下:
的 XYZ.proj :
<PropertyGroup>
<MyWorkingDir>tmp.$(Platform).$(Configuration)</MyWorkingDir>
</PropertyGroup>
现在假设一些其他项目GraphicsWindow通过ProjectReferences或MSBuild任务引用项目XYZ。并且假设可以构建GraphicsWindow项目以使用各种图形API。即,有OpenGL版本,DirectX 9版本,DirectX 10版本......
所以某处有一个.proj或.targets文件,其中包含构建所有四个版本的目标:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ProjectToBuild Include="GraphicsWindow.proj">
<Properties>GraphicsApi=OpenGL</Properties>
</ProjectToBuild>
<ProjectToBuild Include="GraphicsWindow.proj">
<Properties>GraphicsApi=D3D9</Properties>
</ProjectToBuild>
<ProjectToBuild Include="GraphicsWindow.proj">
<Properties>GraphicsApi=D3D10</Properties>
</ProjectToBuild>
<ProjectToBuild Include="GraphicsWindow.proj">
<Properties>GraphicsApi=D3D11</Properties>
</ProjectToBuild>
</ItemGroup>
<Target Name="All">
<MSBuild Projects="@(ProjectToBuild)" BuildInParallel="true" />
</Target>
</Project>
或使用批处理的等效文件。
现在,MSBuild将使用 相同的 平台|配置组合和相同的工作目录构建XYZ项目4次。
只要您在没有/ m选项的情况下构建并且MSBuild运行单个线程,这将正常工作。根据XYZ项目的编写方式,第2,第3和第4版本可能无效,因为输出是最新的,或者它可能会执行一些冗余工作,但最终结果将是正确的,构建将成功
但只要你开始使用并行的MSBuild,这个版本被打破!现在有一个竞争条件在多个线程可以进入XYZ项目的目标(S)的同时,并用开建相同的工作目录,将失败。
答案 0 :(得分:3)
无论您如何使用多进程选项/ m或不执行MSBuild,都可以保证为构建请求的每个配置执行一次项目。以下是MSDN的引用:
当Microsoft Build Engine在使用并行构建来构建项目时遇到项目到项目(P2P)引用时,它只构建一次引用。如果两个项目具有相同的P2P引用,则不会为每个项目重建引用。相反,构建引擎会向依赖它的两个项目返回相同的P2P引用。会话中针对相同目标的未来请求被提供相同的P2P参考。
如果您看到同一项目被多次构建,则意味着它在两个(或更多)不同配置中被引用。这里的配置是指传递给项目的一组参数,例如:项目平台(x86,x64,AnyCPU等),味道(调试/零售),本地化语言,您可能使用的任何其他参数。
这通常是项目平台混合的问题。例如,您有为x64构建的项目A,为AnyCPU构建的项目B,以及A和B的引用C.现在C必须构建两次 - 对于x64和AnyCPU。如果C通过将输出干净地分离到单独的目录中来正确处理两个平台,则没有问题。但是,如果C将x64和AnyCPU视为相同,则它将在多进程构建中随机失败。
首先检查解决方案配置对话框。确保所有项目都具有一致的平台/配置参数集。如果您需要在不同的配置中构建相同的项目,请确保将输出放在不同的位置。