web-dev-qa-db-fra.com

Utilisation de MSBuild pour créer plusieurs configurations

J'essaie d'éditer mon fichier de projet pour me permettre d'avoir un projet qui construit plusieurs configurations de construction à la fois. J'ai fait cela en utilisant une approche par lots et en utilisant la tâche MSBuild (voir ci-dessous).

Si j'exécute le script, j'obtiens cette erreur:

Erreur 103 La propriété OutputPath n'est pas définie pour le projet "ThisMSBuildProjectFile.csproj". Veuillez vérifier que vous avez spécifié une combinaison valide de configuration et de plate-forme pour ce projet. Configuration = 'Debug' Platform = 'AnyCPU'.

J'obtiens ceci si j'ajoute ou omet le OutputPath de la tâche MSBuild. Si vous utilisez le débogueur VS2010 pour parcourir le script et que la tâche MSBuild est appelée - le débogueur pénètre à nouveau dans le fichier, puis dans OutputPath, alors afaik, il devrait choisir cette valeur, non?

Toute aide pour cela serait grandement appréciée - cela me rend fou. Merci, Paul.

ThisMSBuildProjectFile.csproj (trucs en surplus retirés):

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.Microsoft.com/developer/msbuild/2003" DefaultTargets="Build">

  <!-- Only Import normal targets if not building multiple projects -->
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" Condition="'$(Configuration)|$(Platform)' != 'AllBuild|AnyCPU' "/>

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == '' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>C:\Folder\Etc\Output\$(Configuration)\</OutputPath>
    <OutDir>C:\Folder\Etc\Output\$(Configuration)\</OutDir>
    <BaseOutputPath>C:\Folder\Etc\Output\$(Configuration)\</BaseOutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>Prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>

  <!-- Common -->
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <Platform>AnyCPU</Platform>
    <!-- Repeated properties from above here (including, of course, OutputPath) -->  
   </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <!-- Repeated properties from above here (including, of course, OutputPath) --> 
  </PropertyGroup>

  <ItemGroup>
    <Projects Include="C:\Folder\Etc\ThisMSBuildProjectFile.csproj" />
  </ItemGroup>

   <!-- Call this project file again, but with a different configuration - if this was working, this would call multiple  build configs -->
  <Target Name="Build" Condition="'$(Configuration)|$(Platform)' == 'AllBuild|AnyCPU' ">
    <Message Text="hm!"/>
    <!-- Tried thiswith and without the OutputPath property - makes no difference. -->
   <MSBuild  Projects="@(Projects)" Properties="Configuration=Debug;OutputPath=C:\Folder\Etc\Output\" ToolsVersion="4.0" Condition="'$(Configuration)|$(Platform)' == 'AllBuild|AnyCPU' "/>
 </Target>

   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AllBuild|AnyCPU' ">
    <!-- Repeated properties from above here (including, of course, OutputPath) --> 
  </PropertyGroup>

  <!-- Project files -->
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Core" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="Blah\Blah.cs" />
  </ItemGroup>
23
p.q

Il est important de réaliser que lorsque vous utilisez une tâche "MSBuild", un nouveau processus MSBuild enfant sera démarré. L'implication de ceci est que tous les éléments et propriétés que vous définissez dans le processus MSBuild parent pas seront automatiquement transmis/visibles depuis le processus MSBuild enfant à moins que vous les passiez explicitement via Properties attribut sur MSBuild élément (comme dans <MSbuild Properties="..." />).

Pour répondre à votre question, j'ai écrit l'exemple autonome suivant qui exécute un projet MSBuild enfant pour toutes les configurations spécifiées:

  1. Créez d'abord un répertoire pour votre expérience MSBuild (par exemple, j'ai utilisé C:\temp\msbuildtest)

  2. Dans ce répertoire, créez le premier fichier, main.proj:

    <Project xmlns="http://schemas.Microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0">
        <ItemGroup>
            <ConfigList Condition=" '@(ConfigList)' == '' and $(Config) != '' " Include="$(Config.Split('+'))" /><!-- parse all requested configurations into a list -->
            <ConfigList Condition=" '@(ConfigList)' == '' " Include="Debug" /><!-- if no configurations were specified, default to Debug -->
        </ItemGroup>
        <!--
    
        Build the child project for each requested configuration. -->
        <Target Name="Build">
            <MSBuild Projects="$(MSBuildProjectDirectory)\child.proj" Properties="Configuration=%(ConfigList.Identity);OutputPath=$(MSBuildProjectDirectory)\bin\%(ConfigList.Identity)" Targets="Build" />
        </Target>
    </Project>
    
  3. Dans le même répertoire, créez le deuxième fichier, child.proj (dans votre cas, ce serait le projet C # réel que vous essayez de construire, mais parce que j'essaie d'illustrer mon propos, j'utilise un projet enfant simple qui, au lieu d'exécuter le compilateur C #, affiche simplement les valeurs des propriétés: -))

    <Project xmlns="http://schemas.Microsoft.com/developer/msbuild/2003" DefaultTargets="Build" ToolsVersion="4.0">
        <Target Name="Build">
            <Message Text="Building configuration $(Configuration) with output path $(OutputPath)" Importance="High" />
        </Target>
    </Project>
    
  4. Vous pouvez maintenant exécuter l'exemple. D'abord la valeur par défaut, si vous ne spécifiez pas explicitement les configurations à construire:

    C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild main.proj
    > (cut the noise)
    > Build:
    >   Building configuration Debug with output path C:\temp_c\d\bin\Debug
    

    Et puis explicitement spécifié plusieurs configurations:

    C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild main.proj /property:Config=Debug+Release+Staging+Production
    > (cut the noise)
    > Build:
    >   Building configuration Debug with output path C:\temp_c\d\bin\Debug
    > Build:
    >   Building configuration Release with output path C:\temp_c\d\bin\Release
    > Build:
    >   Building configuration Staging with output path C:\temp_c\d\bin\Staging
    > Build:
    >   Building configuration Production with output path C:\temp_c\d\bin\Production
    

Vous devriez pouvoir adapter cette technique à votre situation.

20
Milan Gardian

Quelque chose ne va pas dans votre dossier de projet. Considérez ce XML:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == '' ">
  <DebugType>pdbonly</DebugType>
  <Optimize>true</Optimize>
  <OutputPath>C:\Folder\Etc\Output\$(Configuration)\</OutputPath> 
  ...
</PropertyGroup>

Ces propriétés ne peuvent jamais être définies, car même si $ (Configuration) et $ (Platform) sont vides, elles ne peuvent jamais correspondre à la chaîne vide lorsqu'elles sont concaténées avec le caractère de barre; la valeur minimale pour cette condition est '|' et pas ''. Même si corrigé en comparant la condition avec '|', vous essayez ensuite d'utiliser $ (Configuration) dans OutputPath dans ce PropertyGroup, mais $ (Configuration) n'aura jamais de valeur au point où il est utilisé. De même, lorsque vous essayez de définir $ (Platform) sur 'AnyCPU', il doit déjà avoir cette valeur. Vous vouliez probablement omettre complètement la condition sur le premier PropertyGroup, et vous devrez peut-être fournir des valeurs par défaut pour $ (Configuration) et $ (Platform) dans un premier PropertyGroup sans conditions également. Différez votre projet entier contre un nouveau projet et voyez s'il y a d'autres bizarreries comme celle-ci.

Notez également que lors de votre remplacement de la cible "Build", vous avez une condition redondante sur la tâche MSBuild; avec la même condition est sur le vous n'en avez pas besoin sur aucune des tâches.

5
Brian Kretzler

Je ne suis pas sûr de vouloir passer par une telle configuration alambiquée du fichier csproj du projet lui-même. Je préfère configurer un fichier MSBuild "BuildBoth.proj" distinct qui a une cible spécifique appelée "Both" qui construit la solution dans les deux configurations.

<Project xmlns="http://schemas.Microsoft.com/developer/msbuild/2003" DefaultTargets="Both">

    <!-- Calls twice for both configs -->
    <Target Name="Both">
        <MSBuild Projects="buildboth.sln" Targets="Rebuild" Properties="Configuration=Debug"
                         StopOnFirstFailure="true">
        </MSBuild>

        <MSBuild Projects="buildboth.sln" Targets="Rebuild" Properties="Configuration=Release"
                         StopOnFirstFailure="true">
        </MSBuild>
    </Target>

    <!-- single config targets

    <Target Name="Debug">
        <MSBuild Projects="buildboth.sln" Targets="Rebuild" Properties="Configuration=Debug"
                         StopOnFirstFailure="true">
        </MSBuild>
    </Target>

    <Target Name="Release">
        <MSBuild Projects="buildboth.sln" Targets="Rebuild" Properties="Configuration=Release"
                         StopOnFirstFailure="true">
        </MSBuild>
    </Target>
    -->

</Project>

Ensuite, je lance la commande (verbosité définie sur Minimal) pour cibler les deux

C:\Projects\experiments\BuildBoth>msbuild /v:m /target:Both BuildBoth.proj
Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.225]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

  BothWpf -> C:\Projects\experiments\BuildBoth\BothWpf\bin\Debug\BothWpf.exe
  BothWpf -> C:\Projects\experiments\BuildBoth\BothWpf\bin\Release\BothWpf.exe
4
icelava