Использование MSBuild для создания нескольких конфигураций - PullRequest
21 голосов
/ 01 апреля 2011

Я пытаюсь отредактировать файл моего проекта, чтобы у меня был проект, который собирает несколько конфигураций одновременно.Я сделал это, используя пакетный подход и используя задачу MSBuild (см. Ниже).

Если я запускаю сценарий, я получаю эту ошибку:

Ошибка 103 Свойство OutputPath не установлено для проекта "ThisMSBuildProjectFile.csproj".Пожалуйста, убедитесь, что вы указали правильную комбинацию конфигурации и платформы для этого проекта.Configuration = 'Debug' Platform = 'AnyCPU'.

Я получаю это, если добавляю или опускаю OutputPath из задачи MSBuild.Если для отладки скрипта используется отладчик VS2010, и вызывается задача MSBuild - отладчик снова входит в файл, а затем в OutputPath, так что, аааа, он должен выбрать это значение, нет?

Любая помощь для этого будет принята с благодарностью - это сводит меня с ума.Спасибо, Пол.

ThisMSBuildProjectFile.csproj (лишние вещи удалены):

<?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>

Ответы [ 3 ]

20 голосов
/ 01 апреля 2011

Важно понимать, что при использовании задачи «MSBuild» будет запущен новый дочерний процесс MSBuild. Это означает, что любые элементы и свойства, определенные вами в родительском процессе MSBuild, будут не автоматически передаваться / отображаться из дочернего процесса MSBuild , если вы явно не передадите их через Properties атрибут MSBuild элемента (как в <MSbuild Properties="..." />).

Чтобы ответить на ваш вопрос, я написал следующий автономный пример, который запускает дочерний проект MSBuild для всех указанных конфигураций:

  1. Сначала создайте каталог для вашего эксперимента MSBuild (например, я использовал C:\temp\msbuildtest)

  2. В этом каталоге создайте первый файл, 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. В том же каталоге создайте второй файл, child.proj (в вашем случае это будет реальный проект C #, который вы пытаетесь построить, но, поскольку я пытаюсь проиллюстрировать свою точку зрения, я используя простой дочерний проект, который вместо запуска компилятора C # просто печатает значения свойств :-))

    <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. Теперь вы можете запустить пример. Сначала по умолчанию, если вы не указали явно конфигурации для сборки:

    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
    

    А потом явно указано несколько конфигураций:

    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
    

Вы должны быть в состоянии приспособить эту технику к вашей ситуации.

4 голосов
/ 01 апреля 2011

Я не совсем уверен, хочу ли я пройти через такую ​​запутанную конфигурацию самого файла csproj проекта. Я бы лучше настроил отдельный файл MSBuild «BuildBoth.proj», в котором есть конкретная цель «Оба», которая создает решение в обеих конфигурациях.

<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>

Тогда я бы запустил команду (многословие установлено Minimal) для цели Оба

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 голосов
/ 01 апреля 2011

Что-то не так в вашем файле проекта.Рассмотрим этот XML:

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

Эти свойства никогда не могут быть установлены, так как даже если $ (Configuration) и $ (Platform) пусты, они никогда не могут соответствовать пустой строке, когда соединяются с символом бара;минимальное значение для этого условия - «|»и не ''.Даже если это исправить, сравнив условие с '|', вы продолжаете пытаться использовать $ (Configuration) в OutputPath в этой PropertyGroup, но $ (Configuration) никогда не будет иметь значения в той точке, в которой оно используется.Аналогично, если вы пытаетесь установить для $ (Platform) значение «AnyCPU», оно уже должно иметь это значение.Вы, вероятно, намеревались вообще пропустить условие для первой группы PropertyGroup, и вам может потребоваться указать значения по умолчанию для $ (Configuration) и $ (Platform) в ранней группе PropertyGroup без условий.Отличите весь ваш проект от нового проекта и посмотрите, есть ли какие-либо другие странности, подобные этому.

Также обратите внимание, что при переопределении цели «Build» у вас есть избыточное условие для задачи MSBuild;с тем же условием, которое вам не нужно ни для одной из задач.

...