2013-04-05 93 views
2

我的组织拥有一些运行在构建服务器上的巨大构建,构建大量以及大量与ProjectReferences链接的MSBUILD项目。我们需要能够与msbuild /m并行构建项目和配置。并行MSBUILD - 关键部分?

我的问题是我有一个项目引用了大量的其他项目,但项目本身是而不是可重入。如果多于两个或更多节点试图并行构建该项目,则会失败。

如何将这一个项目或它的目标包裹在临界区域内?

我真正需要做的是这样的:

<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项目的编写方式,第二,第三和第四个版本可能什么也不做,因为输出是最新的,或者它可能会做一些重复的工作,但最终结果是正确的,并且构建会成功。

但是,只要你开始使用并行MSBuild,这个构建是打破了!现在有一个竞争条件,多个线程可以同时进入XYZ项目的目标,并使用相同的工作目录开始构建,这将失败。

+0

您确定需要并行创建多个项目吗? “Msbuild”已经并行编译并同时编译多个源文件。尝试并行执行多个版本可能会导致硬盘访问瓶颈导致性能下降。 – SomeWittyUsername 2013-04-06 16:30:18

回答

3

无论您如何执行MSBuild,使用多处理器选项/ m或不使用,保证为构建请求的每个配置执行一次项目。以下是来自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视为相同,它将在多进程构建中随机失败。

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

+0

我确定你是对的,Seva,并且每一次都在使用不同的配置参数构建有问题的项目,但这有什么帮助?该项目正在使用自己的构建脚本构建第三方库。我想理论上我可以完全重写他们的构建命令,以便始终将中间文件放在不同的位置,但这似乎不是一个实际的解决方案。 – 2013-04-05 15:44:10

+0

我认为真正的问题是你想如何构建第三方项目 - 你想多次构建它(以不同的配置),或者你只希望它构建一次。在我的答案中,我暗示只想一次性构建它。 – 2013-04-06 01:50:39

+0

如果只建造一次,它是否可重入并不重要,我不会有这个问题。 – 2013-04-06 14:30:06