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,...我希望如果复制失败,几毫秒后完成的另一个复制会成功。但是我一直无法设置这些参数。我怎样才能改变它们?

还有其他解决方案吗?

4

3 回答 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?

于 2012-09-14T00:08:43.170 回答
0

一般来说,在构建期间运行的任何东西都不能在其输入上获得排他锁——只有共享读锁。似乎您的构建过程中的某些内容(可能是 NLog,无论是什么)违反了这一点 - 它对输入进行了排他锁定"xxx\NLog.dll",因此当另一个 msbuild 节点尝试复制相同的输入时,它会失败。

重试是针对您的特定症状的合理解决方法 - 尽管不能保证总是成功。

于 2013-07-01T08:28:49.330 回答
0

我有同样的问题。我需要在我的 AntiVirus 中添加适当的例外,以避免扫描 MsBuild 生成的 DLL。

于 2014-08-01T19:14:47.810 回答