MSBuild:并行构建和 .Net 项目

10

我编写了一个MSBuild项目文件,尝试并行构建我的VS2010解决方案中的所有配置:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
  <ItemGroup>
    <BuildFile Include="$(SourceRoot)MyProject.sln" />
    <Config Include="Debug">
      <Configuration>Debug</Configuration>
    </Config>
    <Config Include="Release">
      <Configuration>Release</Configuration>
    </Config>
  </ItemGroup>

  <Target Name="BuildAll" Outputs="%(Config.Configuration)">
    <Message Text="Start building for configuration: %(Config.Configuration)" />
    <MSBuild Projects="@(BuildFile)"
             Properties="Configuration=%(Config.Configuration)"
             Targets="Build" />
  </Target>  
</Project> 

我用以下方式启动msbuild:

msbuild /m /p:BuildInParallel=true /t:BuildAll buildall.proj 

问题在于我的解决方案有许多 .Net 项目,它们都有相同的输出文件夹。这些项目也使用相同的外部程序集。
因此很常见,同时生成两个输出可执行文件,并同时复制它们的依赖项。这会导致错误,例如:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(3001,9): 
error MSB3021: 
Unable to copy file "xxx\NLog.dll" to "D:\src\Blackbird\shared\bin\debug\NLog.xml". The process 
cannot access the file 'xxx\NLog.dll because it is being used by another process. 

我认为这意味着:“2个不同的项目同时使用NLog并尝试将其程序集复制到输出文件夹中”...

有没有办法解决这个问题?我真的很想避免修改解决方案中的所有项目。

查看任务源代码“C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(3001,9)”,我发现可以让msbuild重试复制:

<Copy
    SourceFiles="@(ReferenceCopyLocalPaths)"
    DestinationFiles="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')"
    SkipUnchangedFiles="$(SkipCopyUnchangedFiles)"
    OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)"
    Retries="$(CopyRetryCount)"
    RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
    UseHardlinksIfPossible="$(CreateHardLinksForCopyLocalIfPossible)"
    Condition="'$(UseCommonOutputDirectory)' != 'true'"
    > 

我尝试设置变量CopyRetryCount、CopyRetryDelayMilliseconds等,希望如果复制失败,几毫秒后进行另一次复制可以成功。但是我无法设置这些参数。我该如何更改它们?

是否有其他解决方案?


你是将 NLog 作为产品的一部分构建,还是只是将其检入源代码控制中?如果你正在构建它,是否有可能你的某些项目引用了二进制位置而不是项目本身? - seva titov
3个回答

3
我已找到解决方案。
<MSBuild Projects="@(BuildFile)"
  Properties="Configuration=%(Config.Configuration);Retries=10;RetryDelayMilliseconds=50"
  Targets="Build" />

它能够按照预期工作,但现在在重试复制之前会生成一个警告。

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(3001,9): 
warning MSB3026: Could not copy 
"D:\src\xxx\System.Data.SQLite.pdb" to "..\Debug\System.Data.SQLite.pdb". 
Beginning retry 1 in 50ms. The process cannot access the file 
'..\Debug\System.Data.SQLite.pdb' because it is being used by another process. 

在我的最后一次测试中,它生成了36次此警告!有没有方法可以抑制 MSB0326 警告?


0

我遇到了同样的问题。我需要在我的反病毒软件中添加适当的异常以避免扫描 MsBuild 生成的 DLL 文件。


0
通常,在构建期间运行的任何内容都不得对其输入获取独占锁定 - 只能共享读取锁定。看起来您的构建过程中有些东西(可能是NLog,不知道是什么)违反了这一点 - 它对输入"xxx\NLog.dll"进行了独占锁定,因此当另一个msbuild节点尝试复制相同的输入时会失败。
对于您具体的症状,重试是一个合理的解决方法 - 尽管它并不能保证始终成功。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接