Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSBuild: parallel builds and .Net projects

I've written a MSBuild project files which try to build in parallel all the configs of my VS2010 solution:

<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> 

And I launch msbuild with:

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

The problem is that my solution have many .Net projects which all have the same output folder. These projects use also the same external assemblies.

So very often, two output executables are generated at the same time and their dependencies copied at the same time. This leads to errors like:

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. 

which I think means: "2 different projects use NLog and try to copy its assembly in the output folder at the same time"...

Is there a way to get around that? I really would like to avoid to modify all the projects in the solution.

Looking at the task source code "C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(3001,9)", I've seen that it is possible to make msbuild retry the copy:

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

I've try to set the variables CopyRetryCount, CopyRetryDelayMilliseconds, ... I was hoping that if the copy fails, another copy done a few milliseconds later would succeed. But I've been unable to set these parameters. How can I change them?

Is there another solution?

like image 900
Serge Weinstock Avatar asked Sep 13 '12 19:09

Serge Weinstock


1 Answers

I've found the solution

<MSBuild Projects="@(BuildFile)"
  Properties="Configuration=%(Config.Configuration);Retries=10;RetryDelayMilliseconds=50"
  Targets="Build" />

It works as expected but now it generates a warning before retrying the copy

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. 

During my last test, it generated 36 times this warning! Is there a way for suppressing the warning MSB0326?

like image 135
Serge Weinstock Avatar answered Sep 23 '22 06:09

Serge Weinstock