MSBuild /m:4 fails because it builds the same project twice - msbuild

My team has a large solution (~500 csproj's). We use VS2012, and build using TFS Build, which uses MSBuild 4. Currently we build serially, but we want to build in parallel (using msbuild /maxcpucount:4). However, when I try it on my 4-proc machine, I get a weird failure:
11:2>CSC : fatal error CS0042: Unexpected error creating debug information file 'C:\Common\obj\Debug\Common.PDB' -- 'C:\Common\obj\Debug\Common.pdb: The process cannot access the file because it is being used by another process. [C:\Common\Common.csproj]
Looking at the log, 2 msbuild nodes were trying to build that same csproj, and thus colliding on writing some output:
10>Project "C:\Utils\Utils.csproj" (10) is building "C:\Common\Common.csproj" (11) on node 4 (default targets).
46:2>Project "C:\Objects\Objects.csproj" (46:2) is building "C:\Common\Common.csproj" (11:2) on node 1 (default targets).
Why would MSBuild try to build the same project twice?

Cause: Someone was calling <MSBuild Projects="Common.csproj" Properties="..." />. Then, MSBuild thinks that it should build Common.csproj again with those different properties, and it happened to occur at the same time with the regular compilation of Common.csproj.
Fix: Call <MSBuild ... /> without those unneeded properties.
Test:
Common.targets
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<Message Importance="high" Text="Build in $(MSBuildThisFile)" />
</Target>
<Target Name="After" DependsOnTargets="Build">
<Message Importance="high" Text="After in $(MSBuildThisFile)" />
</Target>
</Project>
Other.targets
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Build">
<Message Importance="high" Text="Build in $(MSBuildThisFile)" />
<MSBuild Projects="common.targets" Targets="Build" /> <!-- regular builds -->
<MSBuild Projects="common.targets" <!-- custom invocation with properties -->
Targets="After"
Properties="myprop=myvalue"
/>
</Target>
</Project>
Run:
> msbuild other.targets /clp:verbosity=minimal
Build in other.targets
Build in common.targets
Build in common.targets <<<< Common.targets Build is invoked again
After in common.targets
And indeed, removing Properties="myprop=myvalue" solves the issue.

I found someone had added two project references (from the same project) and that apparently caused msbuild to build twice also.. something to watch out for

Related

MSBuild target in csproj do a clean before every build

I have a C# project (vs2013) and for this project, i want to do always a clean solution before the build. Now i can (again and again) choose clean project before building, but this should be possible using a Target tag in the .csproj file. I started looking on the internet and came up with a solution that did not work:
<Target Name="Clean"
BeforeTargets="Build">
<Message Text="### Start Clean before build"
Importance="high" />
<Exec Command="CALL "$(MSBuildBinPath)\msbuild.exe" "$(MSBuildProjectFullPath)" /t:Clean" />
<Message Text="### Finished Clean before build"
Importance="high" />
</Target>
But this results in an infinite loop, starting msbuild over and over again.
You've defined the target recursively. Don't name it "Clean", name it "PreBuildClean" or something similar.
Also you don't have to call out to msbuild externally using Exec. You can use the CallTarget task to invoke a target directly.
<Target Name="PreBuildClean"
BeforeTargets="Build">
<Message Text="### Start Clean before build"
Importance="high" />
<CallTarget Targets="Clean" / >
<Message Text="### Finished Clean before build"
Importance="high" />
</Target>
The Rebuild target is just Clean followed by Build, so I'm not sure why you'd need this, unless it is only for one specific project in the solution.

TeamCity MSBuild refer to build counter

I have a property group which includes a property for the build_number which is being passed in from TeamCity as solely the Build Counter. The build number format being set in TeamCity as simply {0} for the counter.
<PropertyGroup>
<Major>10</Major>
<Minor>1</Minor>
<Build>$(BUILD_NUMBER)</Build>
<Release>0</Release>
...
</PropertyGroup>
The Major, Minor and Release properties are then updated from values in a file in source control.
So that TeamCity logs the build as the full 4 part build reference (not just the counter), I set it thus:
<TeamCitySetBuildNumber BuildNumber="$(Major).$(Minor).$(Build).$(Release)" />
However, now when I reference my $(Build) property, it's now set to the 4 part build reference, and any property I have made which makes reference to $(BUILD_NUMBER) prior to setting using TeamCitySetBuildNumber also gets overwritten with the 4 part reference.
NB I've also changed it with a system message:
<Message Text="##teamcity[buildNumber '$(Major).$(Minor).$(Build).$(Release)']" />
but the overall effect is the same.
How Can I refer to the build counter (only) AFTER I have set the BuildNumber above?
If you're using a project file, you could try calling the TeamCitySetBuildNumber command in the AfterBuild section of the *.vbproj or *.csproj file:
<Target Name="AfterBuild">
<TeamCitySetBuildNumber BuildNumber="$(Major).$(Minor).$(Build).$(Release)" />
</Target>
If you're using a solution file, I'd create a *.proj file that calls your solution file and then after that call the TeamCitySetBuildNumber command (not sure if you can call the TeamCitySetBuildNumber command within the target like this though...):
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="SetBuildNumber">
<PropertyGroup>
<Major>10</Major>
<Minor>1</Minor>
<Build>$(BUILD_NUMBER)</Build>
<Release>0</Release>
</PropertyGroup>
<Target Name="Build">
<Message Text="Build task called... " Importance="high"/>
<MSBuild Projects="$(teamcity_build_checkoutDir)\your_solution.sln" Properties="Configuration=Release"/>
</Target>
<Target Name="SetBuildNumber" DependsOnTargets="Build">
<Message Text="Setting build number back to TeamCity... " Importance="high"/>
<TeamCitySetBuildNumber BuildNumber="$(Major).$(Minor).$(Build).$(Release)" />
</Target>
</Project>

MSBuild hangs after NUnit is finished

I'm trying to set up a MSBuild with NUnit as unit test driver but the script keeps hanging after NUnit is done. It doesn't seem to finalize its work and let MSBuild get on with its job.
I'm working in .NET 4.0 and using NUnit 2.5.8.
If I run the test manually or using the gui (either VS2010 or NUnit) it works fine but not when called by MSBuild.
I'd appreciate any help with error finding or just a heads up on where to looks for answers.
The manual command looks like this:
C:\....>nunit\nunit-console.exe buildbinaries\YYYY.XXXX.Extractor.Test.IntegrationTest.dll /xml=nunit.xml
and the abbreviated MSBuild:
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- define folders for build output and reports -->
<PropertyGroup>
<BuildPath>buildbinaries\</BuildPath>
<ReportPath>buildreports\</ReportPath>
<ReleaseFolder>release_artefacts\</ReleaseFolder>
<PublishFolder>c:\ZZZ Applications\published builds\</PublishFolder>
<DeploymentFolder>\\seldclq99\ZZZ_Costanza_Dev$\</DeploymentFolder>
</PropertyGroup>
<PropertyGroup>
<!-- specify assemblies that should be included in coverage report -->
<NCoverAssemblyList>YYYY.XXXX.Extractor.Business.dll; YYYY.XXXX.Extractor.Common.dll YYYY.XXXX.Extractor.Configuration.dll YYYY.XXXX.Extractor.DAL.Access.dll YYYY.XXXX.Extractor.DAL.Facade.dll YYYY.XXXX.Extractor.Service.Contracts.dll YYYY.XXXX.Extractor.Service.dll YYYY.XXXX.Extractor.Service.Host.WebHost.dll YYYY.XXXX.Extractor.ServiceGateway.dll</NCoverAssemblyList>
</PropertyGroup>
<!-- define item group for deliverables -->
<ItemGroup>
<Binaries Include="$(BuildPath)/**/*.*" Exclude="$(BuildPath)nunit*" />
</ItemGroup>
<!--
This is the default target that will be executed if MSBuild is not started
with a specific target (this is decided by the DefaultTargets attribute in
the root element of this XML document)
-->
<Target Name="BuildAndTest">
<CallTarget Targets="SetupDirs" />
<CallTarget Targets="Build" />
<CallTarget Targets="UnitAndIntegrationTest" />
<CallTarget Targets="FxCop" />
<CallTarget Targets="CopyToReleaseFolder" />
</Target>
<!-- Setup folders used during the build -->
<Target Name="SetupDirs">
<RemoveDir Directories="$(ReportPath);$(BuildPath);$(ReleaseFolder)" ContinueOnError="true"/>
<MakeDir Directories="$(ReportPath);$(BuildPath);$(ReleaseFolder);$(AssemblyVersionFolder)" ContinueOnError="true"/>
</Target>
<Target Name="Build">
<!-- build the software using msbuild -->
<!-- Build error in the Install build-->
<MSBuild ContinueOnError="true" RebaseOutputs="false" Targets="Clean;Rebuild" Projects="YYYYXXXXExtractor.sln" Properties="Configuration=Release;OutDir=..\$(BuildPath)" />
</Target>
<!--Run the coverage stats-->
<Target Name="UnitAndIntegrationTest">
<Exec Command="nunit\nunit-console.exe buildbinaries\YYYY.XXXX.Extractor.Test.IntegrationTest.dll /xml=$(ReportPath)nunit.xml "/>
<CallTarget Targets="UnitTest" />
</Target>
<Target Name="UnitTest">
<Exec Command="nunit\nunit-console.exe buildbinaries\YYYY.XXXX.Extractor.Test.UnitTest.dll /xml=$(ReportPath)nunit.xml"/>
</Target>
<!-- Run FxCop -->
<!-- The ForceError.bat fires if the xml file is not found... aka an error was found -->
<!-- The quiet command forces an Xml file ONLY if warnings or Errors are found -->
<Target Name="FxCop">
<Exec Command="..\tools\fxcop\FxCopCmd.exe /p:..\FxCopSettings.FxCop /o:$(ReportPath)fxcop.xml" />
<Exec Condition="Exists('$(ReportPath)fxcop.xml')" Command="..\tools\fxcop\FX_Cop_Failed_Rule_Checks.bat" />
<!--STATS: Run again but don't fail and this time run for all rules.-->
<Exec Command="..\tools\fxcop\FxCopCmd.exe /p:..\FxCopSettingsALLRULES.FxCop /o:$(ReportPath)fxCopAllRules.xml" />
</Target >
I had the same problem with NUnit 2.5.8. There is some discussion of this at the nunit site about the test process hanging. I switched to NUnit 2.5.7 and the problem went away.
It looks like this was fixed a couple of weeks ago in 2.5.9.
I have noticed similar behaviour on out build server since upgrading to .NET 4. MsBuild seems to intermittently hang on either NUnit, FxCop or Dotcover EXEC commands. If you check task manager the process for externally executed command (e.g. Nunit.exe) is still hanging around. If you manually kill the process MsBuild continues on it's merry way - which is far from ideal!
Could this be a bug in the latest version of MsBuild? Our build server was running quite happily until the .NET 4 upgrade.
If you run ProcessExplorer on your server you will notice that an out of band process called nunit-agent is spawned which ends up blocking the nunit runner.
I have not validated that this is fixed in 2.5.9, but it might be some info that could be helpful.

Teamcity build loops on successful build

I have set up a build with Teamcity. See my build file below.
When the build is succesful and the tests pass, the build process just runs again and again indefinitely in a loop.
When the build fails, this does not happen.
I have tried to first set 60 second pause on buildtriggering, and finally disabled build triggering altogether. No difference.
What else could be the cause of this?
My MSBuild file looks like this:
<Project DefaultTargets="Build;Test" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<DeployDirectory>$(MSBuildProjectDirectory)\..\bin</DeployDirectory>
<DependencyDirectory>$(MSBuildProjectDirectory)\Dependencies</DependencyDirectory>
<LinqToSqlMapFolder>$(DeployDirectory)\LinqToSql</LinqToSqlMapFolder>
<NCoverVersionForMSI>$(BUILD_NUMBER)</NCoverVersionForMSI>
<NCoverVersionPeriod>$(BUILD_NUMBER)</NCoverVersionPeriod>
</PropertyGroup>
<ItemGroup>
<ProjectFiles Include="**\*.vbproj"/>
<ConfigFiles Include="**\*.config"/>
<MapFiles Include="**\*.linqtosql.config"/>
<TestAssemblies Include="$(DeployDirectory)\*.Test.dll"/>
<Dependencies Include="$(DependencyDirectory)\**\*" />
</ItemGroup>
<Target Name="Clean">
<MSBuild Projects="#(ProjectFiles)" Targets="Clean"/>
</Target>
<Target Name="Build">
<MSBuild Projects="#(ProjectFiles)" Targets="Rebuild">
<Output TaskParameter="TargetOutputs" ItemName="BuildOutput"/>
</MSBuild>
<Copy SourceFiles="#(BuildOutput)" DestinationFolder="$(DeployDirectory)" />
<Copy SourceFiles="#(Dependencies)" DestinationFolder="$(DeployDirectory)" SkipUnchangedFiles="true" />
<Copy SourceFiles="#(ConfigFiles)" DestinationFolder="$(DeployDirectory)" SkipUnchangedFiles="true" />
<Copy SourceFiles="#(MapFiles)" DestinationFolder="$(LinqToSqlMapFolder)" SkipUnchangedFiles="true" />
</Target>
<UsingTask AssemblyFile="$(DependencyDirectory)\Gallio\Gallio.MsBuildTasks.dll" TaskName="Gallio" />
<Target Name="Test">
<Gallio IgnoreFailures="true" Files="#(TestAssemblies)">
<Output TaskParameter="ExitCode" PropertyName="ExitCode"/>
</Gallio>
</Target>
</Project>
While it appears that this wasn't your issue, I ran into a similar looping problem of my own. I had enabled labeling in the project configuration. I was also using a check for modifications every 60 seconds rule to trigger the build. As a result, upon successful build, TeamCity would tag the build in the VCS and then 60 seconds later, it would see (it's own) modification and trigger another build.
To fix our problem, we just disabled labeling because we didn't want it anyways, but you can also configure a rule to ignore particular authors such that it won't trigger on modifications it made.
It appears there were some problems with the install of teamcity, and a backup of configuration following a reinstall solved the problem with exactly same configuration and buildscript.

Getting the Content item from a csproj using the MSBuild task

I have an MSBuild file and I am building C# projects like this:
<ItemGroup>
<ProjectsToBuild Include="./source/ProjectA/ProjectA.csproj"/>
<ProjectsToBuild Include="./source/ProjectB/ProjectB.csproj"/>
</ItemGroup>
<Target Name="Build">
<MSBuild Projects="#(ProjectsToBuild)" Targets="Build">
<Output ItemName="ProjectOutputs" TaskParameter="TargetOutputs"/>
</MSBuild>
<Message Text="#ProjectOutputs"/>
</Target>
I successfully get an Item containing all of the .dll files that were built:
Build:
c:\code\bin\ProjectA.dll;c:\code\bin\ProjectB.dll
I would also like to get the Content item from each project without modifying the .csproj files. After digging around in the Microsoft .targets files, I was almost able to get it working with this:
<MSBuild Projects="#(ProjectsToBuild)" Targets="ContentFilesProjectOutputGroup">
<Output ItemName="ContentFiles" TaskParameter="TargetOutputs"/>
</MSBuild>
<Message Text="#(ContentFiles->'%(RelativeDir)')"/>
The problem with this approach is the RelativeDir is not being set correctly. I am getting the full path instead of relative:
Build:
c:\ProjectA\MyFolder\MyControl.ascx;c:\ProjectB\MyOtherFolder\MyCSS.css;
instead of:
Build:
MyFolder\MyControl.ascx;MyOtherFolder\MyCSS.css;
Is there a property I can pass to the MSBuild task that will make RelativeDir behave correctly?
Or, even better, is there an easier way to get the Content item?
You can do this but it is not very intutive. I've discussed this type of technique a few times on my blog ( which is currently down :( ).
So create a new file, I named it GetContentFiles.proj which is shown here.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Projects Include="WindowsFormsApplication1\WindowsFormsApplication1.csproj"/>
</ItemGroup>
<!-- This target will be executed once for each file declared in the Project target -->
<Target Name="PrintFiles" Outputs="%(Projects.Identity)">
<Message Text="PrintFiles" Importance="high"/>
<MSBuild Projects="$(MSBuildProjectFile)"
Targets="GetContentFiles"
Properties="ProjectToGetFiles=%(Projects.Identity)">
<Output ItemName="projContent" TaskParameter="TargetOutputs"/>
</MSBuild>
<Message Text="ProjContent: #(projContent)" Importance="high"/>
<!-- Transform the projContent to have correct path -->
<!--
Get the relative path to the project itself, this serves as the base for
the Content files path
-->
<PropertyGroup>
<_ProjRelativeDir>%(Projects.RelativeDir)</_ProjRelativeDir>
</PropertyGroup>
<!-- This item will contain the item with the corrected path values -->
<ItemGroup>
<ProjContentFixed Include="#(projContent->'$(_ProjRelativeDir)%(RelativeDir)%(Filename)%(Extension)')"/>
</ItemGroup>
<!-- Create a new item with the correct relative dirs-->
<Error Condition="!Exists('%(ProjContentFixed.FullPath)')"
Text="File not found at [%(ProjContentFixed.FullPath)]"/>
</Target>
<Import Project="$(ProjectToGetFiles)" Condition="'$(ProjectToGetFiles)'!=''"/>
<Target Name="GetContentFiles" Condition="'$(ProjectToGetFiles)'!=''" Outputs="#(Content)">
<Message Text="Content : #(Content)" Importance="high"/>
<Message Text="Inside GetContentFiles" Importance="high"/>
</Target>
</Project>
I will try and explain this, but it may be tough to follow. Let me know if you need me to expand on it. This file has two targets PrintFiles and GetContentFiles. The entry point into this file is the PrintFiles target, in the sense that this is the target that you are going to call. So you call the PrintFiles target which it then uses the MSBuild task to call the GetContentFiles target on itself, also it passes a value for the ProjectToGetFiles property. Because of that the Import elemnent will be executed. So what you are really doing is taking the project defined in the ProjectToGetFiles property and extending it to include the target GetContentFiles (and whatever other content is inside the GetContentFiles.proj file). So we are effectively extending that file. I'm calling this technique "MSBuild Inheritance" because. So inside the GetContentFiles target we can access all properties and items that are declared inthe ProjectToGetFiles property. So I take advantage of that by simply putting the content of the Content item into the outputs for the target, which can be accessed by the original file using the TargetOutputs from the MSBuild task.
You mentioned in your post that you wanted to correct the path values to be the right ones. The problem here is that in the .csproj file all items are declared relative to the original project file. So if you "extend" the project file in this way from a file in a different directory you must correct the file path values manually. I've done this inside the PrintFiles target, check it out.
If you execute the command msbuild GetContentFile.proj /fl /t:PrintFiles the result would be:
Build started 7/3/2009 12:56:35 AM.
Project "C:\Data\Development\My Code\Community\MSBuild\FileWrites\GetContentFile.proj" on node 0 (PrintFiles target(s)).
PrintFiles
Project "C:\Data\Development\My Code\Community\MSBuild\FileWrites\GetContentFile.proj" (1) is building "C:\Data\Development\My Co
de\Community\MSBuild\FileWrites\GetContentFile.proj" (1:2) on node 0 (GetContentFiles target(s)).
Content : Configs\Config1.xml;Configs\Config2.xml
Inside GetContentFiles
Done Building Project "C:\Data\Development\My Code\Community\MSBuild\FileWrites\GetContentFile.proj" (GetContentFiles target(s)).
PrintFiles:
ProjContent: Configs\Config1.xml;Configs\Config2.xml
Done Building Project "C:\Data\Development\My Code\Community\MSBuild\FileWrites\GetContentFile.proj" (PrintFiles target(s)).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.03
Sayed Ibrahim Hashimi
My Book: Inside the Microsoft Build Engine : Using MSBuild and Team Foundation Build
In case this helps someone else - use TargetPath instead of RelativeDir:
<MSBuild Projects="#(ProjectsToBuild)" Targets="ContentFilesProjectOutputGroup">
<Output ItemName="ContentFiles" TaskParameter="TargetOutputs"/>
</MSBuild>
<Message Text="#(ContentFiles->'%(TargetPath)')"/>
This will give you the relative path for each item.