并行MSBUILD - 关键部分?

时间:2013-04-05 02:43:40

标签: msbuild

我的组织有一些在构建服务器上运行的大型构建,构建批次以及许多与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)的同时,并用开建相同的工作目录,将失败。

1 个答案:

答案 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视为相同,则它将在多进程构建中随机失败。

首先检查解决方案配置对话框。确保所有项目都具有一致的平台/配置参数集。如果您需要在不同的配置中构建相同的项目,请确保将输出放在不同的位置。