Использование MSBuild для создания нескольких конфигураций
Я пытаюсь изменить файл проекта, чтобы у меня появился проект, который собирает сразу несколько конфигураций сборки. Я сделал это, используя метод пакетной обработки и используя задачу MSBuild (см. Ниже).
Если я запустил script, я получаю эту ошибку:
Ошибка 103 Свойством OutputPath является не установлен для проекта "ThisMSBuildProjectFile.csproj". Пожалуйста, проверьте, чтобы вы указали действительную комбинацию Конфигурация и платформа для этого проект. Конфигурация = "отладка" Платформа = 'AnyCPU'.
Я получаю это, если я добавляю или опускаю OutputPath из задачи MSBuild. Если используется отладчик VS2010 для перехода через script и вызывается задача MSBuild - отладчик снова переходит в файл, а затем переходит в OutputPath, поэтому afaik, он должен выбрать это значение, нет?
Любая помощь для этого будет принята с благодарностью - это сводит меня с ума. Спасибо, Пол.
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>
Ответы
Ответ 1
Важно понимать, что при использовании задачи "MSBuild" будет запущен новый процесс MSBuild. Следствием этого является то, что любые элементы и свойства, которые вы определяете в родительском процессе MSBuild, будут не автоматически передаваться/видны из дочернего процесса MSBuild , если вы явно пропускаете их через Properties
в элементе MSBuild
(как в <MSbuild Properties="..." />
).
Чтобы ответить на ваш вопрос, я написал следующий автономный пример, который запускает дочерний проект MSBuild для всех указанных конфигураций:
-
Сначала создайте каталог для вашего эксперимента MSBuild (например, я использовал C:\temp\msbuildtest
)
-
В этом каталоге создайте первый файл 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>
-
В том же каталоге создайте второй файл child.proj
(в вашем случае это будет фактический проект С#, который вы пытаетесь построить, но поскольку я пытаюсь проиллюстрировать свою точку зрения, я используя простой дочерний проект, который вместо запуска компилятора С# просто печатает значения свойств:-))
<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>
-
Теперь вы можете запустить пример. Сначала по умолчанию, если вы явно не задаете конфигурации для сборки:
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
Вы должны уметь адаптировать этот метод к своей ситуации.
Ответ 2
В вашем файле проекта что-то не так. Рассмотрим этот XML:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == '' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>C:\Folder\Etc\Output\$(Configuration)\</OutputPath>
...
</PropertyGroup>
Эти свойства никогда не могут быть установлены, поскольку даже если $(Конфигурация) и $(Платформа) пустые, они никогда не смогут сопоставить пустую строку при конкатенации с символом штриха; минимальное значение для этого условия равно '|' и не ''. Даже если скорректировать это условие, сравнив его с '|', вы затем попытаетесь использовать $(Конфигурация) в OutputPath в этой PropertyGroup, но $(Конфигурация) никогда не будет иметь значения в той точке, в которой оно используется. Точно так же, когда вы пытаетесь установить $(Платформа) на "AnyCPU", оно уже должно иметь это значение. Вероятно, вы, вероятно, хотели полностью исключить условие в первой PropertyGroup, и вам может потребоваться указать значения по умолчанию для $(Конфигурация) и $(Платформа) в ранней PropertyGroup без каких-либо условий. Разверните весь проект против нового проекта и посмотрите, есть ли какие-либо другие странности, подобные этому.
Также обратите внимание, что при переопределении цели "Создать" у вас есть избыточное условие для задачи MSBuild; с тем же условием, что вы не нуждаетесь в этом ни в одной из задач.
Ответ 3
Я не совсем уверен, хочу ли я пройти такую сложную конфигурацию самого проекта csproj. Я предпочел бы установить отдельный файл MSBuild "BuildBoth.proj", который имеет конкретную цель под названием "Both", которая строит решение в обеих конфигурациях.
<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>
Затем я запустил команду (набор слов, минимальный), чтобы настроить Both
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