Since Visual studio 2010 we started using TFS and TFS build. The custom MSBUILD project to produce the boost binaries had the following structure
<ItemGroup>
<BoostLib Include="regex"/>
<BoostLib Include="thread"/>
<BoostLib Include="filesystem"/>
<BoostLib Include="date_time"/>
<BoostLib Include="random"/>
</ItemGroup>
<ItemGroup>
 <BuildPlatform Include="Win32">
<AddressModel>32</AddressModel>
</BuildPlatform>
<BuildPlatform Include="x64">
<AddressModel>64</AddressModel>
</BuildPlatform>
</ItemGroup>
<ItemGroup>
<BuildVariant Include="Debug">
<CxxFlag>\D_SECURE_SCL=1</CxxFlag>
<Variant>debug</Variant>
</BuildVariant>
<BuildVariant Include="Release">
 <CxxFlag>\D_SECURE_SCL=1</CxxFlag>
<Variant>release</Variant>
</BuildVariant>
<BuildVariant Include="ReleaseSecure0">
<CxxFlag>\D_SECURE_SCL=0</CxxFlag>
<Variant>release</Variant>
</BuildVariant>
</ItemGroup>
<PropertyGroup>
<_CommonCmdLine>$(ProjectDir)..\bjam.exe toolset=msvc-10.0 link=static threading=multi runtime-link=static --cxxflags=/MP</_CommonCmdLine>
</PropertyGroup>
This gave me maximum flexibility: I can add or remove libraries, build variants or address models. But now I had to call bjam for each combination. And this is not trivial in MSBUILD.<BoostLib Include="regex"/>
<BoostLib Include="thread"/>
<BoostLib Include="filesystem"/>
<BoostLib Include="date_time"/>
<BoostLib Include="random"/>
</ItemGroup>
<ItemGroup>
 <BuildPlatform Include="Win32">
<AddressModel>32</AddressModel>
</BuildPlatform>
<BuildPlatform Include="x64">
<AddressModel>64</AddressModel>
</BuildPlatform>
</ItemGroup>
<ItemGroup>
<BuildVariant Include="Debug">
<CxxFlag>\D_SECURE_SCL=1</CxxFlag>
<Variant>debug</Variant>
</BuildVariant>
<BuildVariant Include="Release">
 <CxxFlag>\D_SECURE_SCL=1</CxxFlag>
<Variant>release</Variant>
</BuildVariant>
<BuildVariant Include="ReleaseSecure0">
<CxxFlag>\D_SECURE_SCL=0</CxxFlag>
<Variant>release</Variant>
</BuildVariant>
</ItemGroup>
<PropertyGroup>
<_CommonCmdLine>$(ProjectDir)..\bjam.exe toolset=msvc-10.0 link=static threading=multi runtime-link=static --cxxflags=/MP</_CommonCmdLine>
</PropertyGroup>
I have found one reference to combining or nesting Items from ItemsGroups, but sadly this doesn't seem to work for me. If I attach the follwoning target, as suggested in the blog
<Target Name="Build">
<PropertyGroup>
<CurrentVariant>%(BuildVariant.CxxFlag)</CurrentVariant>
</PropertyGroup>
<Message Text="VariantPlatform $(CurrentVariant) : %(BuildPlatform.FileName)"/>
</Target>
<PropertyGroup>
<CurrentVariant>%(BuildVariant.CxxFlag)</CurrentVariant>
</PropertyGroup>
<Message Text="VariantPlatform $(CurrentVariant) : %(BuildPlatform.FileName)"/>
</Target>
The output I get reads
So the property CurrentVariant gets all the subsequent BuildVariant values and in my Message task I'm stuck with the last value.
I will not bother you with all the combinations and tricks I have tried but in the end I experimented with CreateItem and came up with the idea to batch over one type item while adding AddionalMetadata from another type. Something like this
<Target Name="Build">
<CreateItem
Include="@(BuildVariant)"
AdditionalMetadata="Platform=%(BuildPlatform.FileName);AddressModel=%(BuildPlatform.AddressModel)">
<Output
TaskParameter="Include"
ItemName="VariantPlatform"/>
</CreateItem>
<Message Text="VariantPlatform %(VariantPlatform.Platform), %(VariantPlatform.FileName), %(VariantPlatform.AddressModel)"/>
</Target>
<CreateItem
Include="@(BuildVariant)"
AdditionalMetadata="Platform=%(BuildPlatform.FileName);AddressModel=%(BuildPlatform.AddressModel)">
<Output
TaskParameter="Include"
ItemName="VariantPlatform"/>
</CreateItem>
<Message Text="VariantPlatform %(VariantPlatform.Platform), %(VariantPlatform.FileName), %(VariantPlatform.AddressModel)"/>
</Target>
This gave the following result
This was exactly what I was after: a combination of the two properties!
For completeness here is the rest of the MSBUILD projects which builds the boost binaries
<Target Name="ComposeItems" BeforeTargets="Build;Clean;Rebuild">
<CreateItem
Include="@(BuildVariant)"
AdditionalMetadata="Platform=%(BuildPlatform.FileName);AddressModel=%(BuildPlatform.AddressModel)">
<Output
TaskParameter="Include"
ItemName="VariantPlatform"/>
</CreateItem>
<Message Text="VariantPlatform %(VariantPlatform.Platform) : %(VariantPlatform.FileName) ? %(VariantPlatform.AddressModel)"/>
<CreateItem
Include="@(VariantPlatform)"
AdditionalMetadata="Lib=%(BoostLib.FileName)">
<Output
TaskParameter="Include"
ItemName="Tobuild2"/>
</CreateItem>
<CreateItem
Include="@(Tobuild2)"
AdditionalMetadata="IntermDir=$(INTERMEDIATEROOT)\Boost_$(Boostver)\%(Tobuild2.Platform)\%(Tobuild2.FileName); OutDir=$(OUTPUT)%(Tobuild2.Platform)\%(Tobuild2.FileName)">
<Output
TaskParameter="Include"
ItemName="Tobuild"/>
</CreateItem>
<Message Text="BUILD %(Tobuild.Lib) %(Tobuild.Platform) : %(Tobuild.FileName) ? %(Tobuild.AddressModel) %(ToBuild.StageDir)"/>
</Target>
<Target Name="Build">
<Exec WorkingDirectory="$(ProjectDir)boost_$(BOOSTVER)"
Command='$(_CommonCmdLine) variant=%(Tobuild.Variant) cxxflags=%(Tobuild.CxxFlag) "--stagedir=%(ToBuild.OutDir)" "--build-dir=%(ToBuild.IntermDir)" --with-%(ToBuild.Lib) stage'/>
</Target>
<Target Name="Clean">
<Exec WorkingDirectory="$(ProjectDir)boost_$(BOOSTVER)"
Command='$(_CommonCmdLine) --clean variant=%(Tobuild.Variant) cxxflags=%(Tobuild.CxxFlag) "--stagedir=%(ToBuild.OutDir)" "--build-dir=%(ToBuild.IntermDir)" --with-%(ToBuild.Lib) stage'/>
</Target>
<Target Name="Rebuild">
<Exec WorkingDirectory="$(ProjectDir)boost_$(BOOSTVER)"
Command='$(_CommonCmdLine) -a variant=%(Tobuild.Variant) cxxflags=%(Tobuild.CxxFlag) "--stagedir=%(ToBuild.OutDir)" "--build-dir=%(ToBuild.IntermDir)" --with-%(ToBuild.Lib) stage'/>
</Target>
Happy programming!
<CreateItem
Include="@(BuildVariant)"
AdditionalMetadata="Platform=%(BuildPlatform.FileName);AddressModel=%(BuildPlatform.AddressModel)">
<Output
TaskParameter="Include"
ItemName="VariantPlatform"/>
</CreateItem>
<Message Text="VariantPlatform %(VariantPlatform.Platform) : %(VariantPlatform.FileName) ? %(VariantPlatform.AddressModel)"/>
<CreateItem
Include="@(VariantPlatform)"
AdditionalMetadata="Lib=%(BoostLib.FileName)">
<Output
TaskParameter="Include"
ItemName="Tobuild2"/>
</CreateItem>
<CreateItem
Include="@(Tobuild2)"
AdditionalMetadata="IntermDir=$(INTERMEDIATEROOT)\Boost_$(Boostver)\%(Tobuild2.Platform)\%(Tobuild2.FileName); OutDir=$(OUTPUT)%(Tobuild2.Platform)\%(Tobuild2.FileName)">
<Output
TaskParameter="Include"
ItemName="Tobuild"/>
</CreateItem>
<Message Text="BUILD %(Tobuild.Lib) %(Tobuild.Platform) : %(Tobuild.FileName) ? %(Tobuild.AddressModel) %(ToBuild.StageDir)"/>
</Target>
<Target Name="Build">
<Exec WorkingDirectory="$(ProjectDir)boost_$(BOOSTVER)"
Command='$(_CommonCmdLine) variant=%(Tobuild.Variant) cxxflags=%(Tobuild.CxxFlag) "--stagedir=%(ToBuild.OutDir)" "--build-dir=%(ToBuild.IntermDir)" --with-%(ToBuild.Lib) stage'/>
</Target>
<Target Name="Clean">
<Exec WorkingDirectory="$(ProjectDir)boost_$(BOOSTVER)"
Command='$(_CommonCmdLine) --clean variant=%(Tobuild.Variant) cxxflags=%(Tobuild.CxxFlag) "--stagedir=%(ToBuild.OutDir)" "--build-dir=%(ToBuild.IntermDir)" --with-%(ToBuild.Lib) stage'/>
</Target>
<Target Name="Rebuild">
<Exec WorkingDirectory="$(ProjectDir)boost_$(BOOSTVER)"
Command='$(_CommonCmdLine) -a variant=%(Tobuild.Variant) cxxflags=%(Tobuild.CxxFlag) "--stagedir=%(ToBuild.OutDir)" "--build-dir=%(ToBuild.IntermDir)" --with-%(ToBuild.Lib) stage'/>
</Target>