Gotcha: MSBuild nested loops (double batching)
I admit I didn’t get it on my first, quick, reading of “Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build” that MSBuild batching is somewhat counter-intuitive.
I needed to have a nested loop in my script, like this pseudo code:
foreach (solution in solutionItemGroup) {
foreach (configuration in solution.Configurations) {
build solution's package using configuration
}
}
It turned out that a naive solution doesn’t work: two different ItemGroup in the same Task are interpreted by MSBuild, like the following pseudo code:
foreach (solution in solutionItemGroup) {
build solution's package using configuration
}
foreach (configuration in solution.Configurations) {
build solution's package using configuration
}
The solution I found is to work at the target level using a local property, an MSBuild 3.5 feature. MSBuild creates a first batch for the property, the outer loop, the a second, nested batch for the task at hand; some real code may better explain this.
<Target Name="DeployToLocalServer" DependsOnTargets="MyResolveSolutionPaths">
<PropertyGroup>
<CurrentConfiguration>%(ConfigurationToBuild.FlavorToBuild)</CurrentConfiguration>
</PropertyGroup>
<MSBuild Projects="%(LocalSolutionToBuild.RootDir)%(LocalSolutionToBuild.Directory)%(LocalSolutionToBuild.Filename).Deployment.proj"
Targets="Deploy"
Properties="Configuration=$(CurrentConfiguration);OutDir=$(OutDir)"
StopOnFirstFailure="$(StopOnFirstFailure)"
ContinueOnError="false"
Condition="'%(LocalSolutionToBuild.Deploy)'=='true'"
/>
</Target>
The CurrentConfiguration property batches (loops) on the ConfigurationToBuild; this property is used in the MSBuild task as a simple value ($ sign), and the interpreter over all its possible values before evaluating the batches in the task.
Happy Building!