Build für mehrere Konfigurationen ausführen

Es gibt diverse Szenarien wo es nützlich sein kann, mit einem MSBuild Aufruf mehrere Konfigurationen eines Projektes zu builden. So z.B. wenn ein NuGet-Package erstellt werden soll welches DLLs für mehrere .NET Versionen enthält. Im folgenden Post zeige ich auf wie sich das bewerkstelligen lässt.

Im folgenden Szenario soll ein Projekt gegen .NET 4.0 und .NET 4.5 gebuildet werden.

1. Konfigurationen in der Solution erstellen

Im “Configuration Manager” des Visual Studios werden die neuen Konfigurationen eingefügt respektive die vorhandenen umbenannt. So wird “Release” zu “Release-45”, “Debug” zu “Debug-45” und die Konfigurationen “Debug-40” und “Release-45” werden neu erstellt. Die neu erstellten Konfigurationen können kopiert werden (“Debug” von “Debug” und “Release-40” von “Release”).

2. Konfigurationen im “*.csproj” anpassen
Im folgenden wird als Beispiel die “Releas” Konfiguration gezeigt. Dasselbe muss auch für die “Debug” Konfiguration gemacht werden.

In der obersten “PropertyGroup” des .csproj Files müssen die Tags “TargetFrameworkVersion” und “OutputPath” entfernt werden.

<PropertyGroup>
  <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>

Als zweites werden die Konfigurationen festgelegt welche unabhängig von der .NET Framework Version gültig sind.

<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release-40|AnyCPU' OR '$(Configuration)|$(Platform)' == 'Release-45|AnyCPU'">
  <PlatformTarget>AnyCPU</PlatformTarget>
  <DefineConstants>TRACE</DefineConstants>
  <Optimize>true</Optimize>
  <DebugType>pdbonly</DebugType>
  <ErrorReport>prompt</ErrorReport>
  <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>

Danach kommen die .NET Framework Version spezifischen Konfigurationen. In diesem Beispiel variiert nur die .NET Framework Version selbst und der Output Path.
Einmal für die Version 4.0:

<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release-40|AnyCPU'">
  <OutputPath>bin\Release\net40</OutputPath>
  <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
</PropertyGroup>

Und für die Version 4.5:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release-45|AnyCPU' ">
  <OutputPath>bin\Release\net45</OutputPath>
  <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>

3. .NET Framework abhängige Referenzen konfigurieren
Gibt es nun Referenzen welche ebenfalls von der .NET Version abhängen, so kann der Reference Include in eine ItemGroup mit einer Condition verpackt werden. Natürlich muss der ursprüngliche Include gelöscht bzw. durch die neuen Includes ersetzt werden. Hier zu sehen am Beispiel des Entity Frameworks.

<ItemGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-40|AnyCPU' OR '$(Configuration)|$(Platform)' == 'Release-40|AnyCPU'">
 <Reference Include="EntityFramework">
  <HintPath>..\packages\EntityFramework.6.1.2\lib\net40\EntityFramework.dll</HintPath>
 </Reference>
</ItemGroup>
<ItemGroup Condition="'$(Configuration)|$(Platform)' == 'Debug-45|AnyCPU' OR '$(Configuration)|$(Platform)' == 'Release-45|AnyCPU'">
 <Reference Include="EntityFramework">
  <HintPath>..\packages\EntityFramework.6.1.2\lib\net45\EntityFramework.dll</HintPath>
 </Reference>
</ItemGroup>

4. Neue “BuildAllConfigurations.proj” Datei erstellen

Auf der Solution ebene wird eine neue Datei “BuildAllConfigurations.proj” erstellt.
Der Name kann frei gewählt werden.

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Rebuild" ToolsVersion="4.0">
  <ItemGroup>
    <ConfigurationList Include="Debug-40" />
    <ConfigurationList Include="Debug-45" />
    <ConfigurationList Include="Release-40" />
    <ConfigurationList Include="Release-45" />
    <PlatformList Include="Any CPU" />
    <ProjectList Include="$(MSBuildProjectDirectory)\MySolutionName.sln" />
  </ItemGroup>

  <Target Name="Rebuild" Outputs="%(PlatformList.Identity)">
    <PropertyGroup>
      <CurrentPlatform>
        %(PlatformList.Identity)
      </CurrentPlatform>
    </PropertyGroup>
    <MSBuild Projects="@(ProjectList)"
               Properties="Configuration=%(ConfigurationList.Identity);Platform=$(CurrentPlatform);"
               Targets="Rebuild"
               SkipNonexistentProjects="true" />
  </Target>
</Project>

Mit den “ConfigurationList”-Items auf der Linie 4 – 7 wird angegeben, welche Konfigurationen es zu builden gilt.
Auf Linie 10 wird die Solution angeben, die gebuildet werden soll.
Der Aufruf von MSBuild ist auf Linie 18 – 21 zu sehen. Dabei wird für jedes Projekt in der Solution das “Rebuild”-Target aufgerufen.

5. Aufruf von MSBuild
“MSBuild.exe BuildAllConfigurations.proj”
(Wo versteckt sich MSBuild.exe? “reg.exe query “HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0″ /v MSBuildToolsPath”)

Leave a Reply

Your email address will not be published. Required fields are marked *