我的组织拥有一些运行在构建服务器上的巨大构建,构建大量以及大量与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项目的目标,并使用相同的工作目录开始构建,这将失败。
您确定需要并行创建多个项目吗? “Msbuild”已经并行编译并同时编译多个源文件。尝试并行执行多个版本可能会导致硬盘访问瓶颈导致性能下降。 – SomeWittyUsername 2013-04-06 16:30:18