MSBuild Batching on Three Independent Variables
Asked Answered
U

2

5

I have been writing a build system based on MSBuild, and am to the end of the project where I need to essentially run the one msbuild file 88 times by batching over three variables:

Configuration = Debug; Beta; Release; Evaluation
Platform = x86; x64
Language = CN; CS; DE; EN; ES; FR; IT; JP; KO; PL; TW

I want to build:
"Debug x86 CN", "Debug x86 CS", ... "Debug x86 TW"
"Debug x64 CN", ...

I can, of course, define 88 of these:

<ItemGroup>
  <ToBuild Include="Debug_x86_CN">
    <Configuration>Debug</Configuration>
    <Platform>x86</Platform>
    <Language>EN</Language>
  </ToBuild>
<ItemGroup>

And then batch based on metadata. But what a drag! Can I create the 88 permutations in code, so adding a language is as easy as adding three characters to an ItemGroup:

<ItemGroup>
  <AllConfigurations Include="Beta; Release; Evaluation;"/>
  <AllPlatforms Include="x86; x64" />
  <AllLanguages Include="CN; CS; DE; EN; ES; FR; IT; JP; KO; PL; TW" />
</ItemGroup>
Unreserve answered 8/10, 2010 at 18:52 Comment(0)
U
8

Thanks to Anders Ljusberg for posting an answer to this years ago. The solution is to use the CreateItem task to combine the individual ItemGroups into one ItemGroup. The cross product of each item needs to be done one at a time into a new ItemGroup (in this case _Config_X_Language and _Config_X_Language_X_Platform) to prevent empty metadata from leaking in (if you try to reuse _Config_X_Language, you'll get items with empty Platform, n addition to the platforms in $(Platform).

<ItemGroup>
  <Configuration Include="Beta; Release; Evaluation;"/>
  <Platform Include="x86; x64" />
  <Language Include="CN; CS; DE; EN; ES; FR; IT; JP; KO; PL; TW" />
</ItemGroup>

<!-- Create an ItemGroup that is the cross product of Configuration and Language: -->
<CreateItem Include="@(Configuration)" AdditionalMetadata="Language=%(Language.Identity);" >
  <Output ItemName="_Config_X_Language" TaskParameter="Include"/>
</CreateItem>
<!-- Create another ItemGroup that is the cross product of _Configuration_X_Language and Platform: -->
<CreateItem Include="@(_Config_X_Language)" AdditionalMetadata="Platform=%(Platform.Identity);" >
  <Output ItemName="_Config_X_Language_X_Platform" TaskParameter="Include"/>
</CreateItem>

<!-- Task batch over each unique set of metadata on AllBuilds -->
<MSBuild Projects="myproject.msbuild"
          Properties="Configuration=%(_Config_X_Language_X_Platform.Identity);
                      Platform=%(_Config_X_Language_X_Platform.Platform);
                      Language=%(_Config_X_Language_X_Platform.Language);"
          Targets="MyTarget"
          BuildInParallel="true" />
Unreserve answered 8/10, 2010 at 20:0 Comment(0)
M
0

It is a good idea to combine the individual ItemGroups into one ItemGroup. However, when using this method MSBuild builds projects ignoring attribute BuildInParallel (all projects building consistently). So you need something to supplement script:

<ItemGroup>
  <Configuration Include="Beta; Release; Evaluation;"/>
  <Platform Include="x86; x64" />
  <Language Include="CN; CS; DE; EN; ES; FR; IT; JP; KO; PL; TW" />
</ItemGroup>

<!-- Create an ItemGroup that is the cross product of Configuration and Language: -->
<CreateItem Include="@(Configuration)" AdditionalMetadata="Language=%(Language.Identity);" >
  <Output ItemName="_Config_X_Language" TaskParameter="Include"/>
</CreateItem>
<!-- Create another ItemGroup that is the cross product of _Configuration_X_Language and Platform: -->
<CreateItem Include="@(_Config_X_Language)" AdditionalMetadata="Platform=%(Platform.Identity);" >
  <Output ItemName="_Config_X_Language_X_Platform" TaskParameter="Include"/>
</CreateItem>

<!--Creating groups for projects to build-->
<!--In the attribute AdditionalMetadata sign '=' is changed to '%3D', and the sign ';'' changed to '%3B'-->
<CreateItem Include="myproject.msbuild" AdditionalMetadata="Properties=
                                                            Configuration%3D%(_Config_X_Language_X_Platform.Identity)%3B
                                                            Platform%3D%(_Config_X_Language_X_Platform.Platform)%3B
                                                            Language%3D%(_Config_X_Language_X_Platform.Language)" >
  <Output ItemName="ProjectToBuild" TaskParameter="Include"/>
</CreateItem>

<!--Task batch build all projects parallel -->
<MSBuild Projects="@(ProjectToBuild)"
         Targets="MyTarget"
         BuildInParallel="true"
         StopOnFirstFailure="true" />
Maxie answered 25/9, 2015 at 13:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.