Ух ты, это загруженный вопрос для поста на форуме. Я написал около 20 страниц о создании многократно используемых файлов .targets в моей книге , но я начну с основ здесь. Я считаю, что ключ к созданию повторно используемых скриптов сборки (т.е. файлов .targets) состоит из трех элементов:
- Поместить поведение (, т.е. цели ) в отдельные файлы
- Поместите данные (, т.е. свойства и элементы, они называются .proj файлами ) в свои собственные файлы
- Расширяемость
- .targets файлы должны проверять предположения
Идея состоит в том, что вы хотите поместить все свои цели в отдельные файлы, и затем эти файлы будут импортированы файлами, которые будут управлять процессом сборки. Это файлы, которые содержат данные. Поскольку вы импортируете файлы .targets, вы получаете все цели, как если бы они были определены внутри строки. Между файлами .proj и .targets будет заключен молчаливый договор. Этот контракт определен в свойствах и предметах, которые оба используют. Это то, что должно быть проверено.
Идея здесь не нова. За этим шаблоном следует .csproj (и другие проекты, созданные Visual Studio). Если вы посмотрите свой файл .csproj, вы не найдете ни одной цели, только свойства и элементы. Затем в конец файла импортируется файл Microsoft.csharp.targets ( может отличаться в зависимости от типа проекта ). Этот файл проекта ( вместе с другими импортируемыми ) содержит все цели, которые фактически выполняют сборку.
Итак, это выложено так:
- SharedBuild.targets
- MyProduct.proj
Где MyProdcut.proj может выглядеть так:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- This uses a .targets file to off load performing the build -->
<PropertyGroup>
<Configuration Condition=" '$(Configuration)'=='' ">Release</Configuration>
<OutputPath Condition=" '$(OutputPath)'=='' ">$(MSBuildProjectDirectory)\BuildArtifacts\bin\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Projects Include="$(MSBuildProjectDirectory)\..\ClassLibrary1\ClassLibrary1.csproj"/>
<Projects Include="$(MSBuildProjectDirectory)\..\ClassLibrary2\ClassLibrary2.csproj"/>
<Projects Include="$(MSBuildProjectDirectory)\..\ClassLibrary3\ClassLibrary3.csproj"/>
<Projects Include="$(MSBuildProjectDirectory)\..\WindowsFormsApplication1\WindowsFormsApplication1.csproj"/>
</ItemGroup>
<Import Project="SharedBuild.targets"/>
</Project>
И SharedBuild.targets может выглядеть так:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- This represents a re-usable build file -->
<Target Name="SharedBuild_Validate">
<!-- See http://sedodream.com/2009/06/30/ElementsOfReusableMSBuildScriptsValidation.aspx for more info
about this validation pattern
-->
<ItemGroup>
<_RequiredProperties Include ="Configuration">
<Value>$(Configuration)</Value>
</_RequiredProperties>
<_RequiredProperties Include ="OutputPath">
<Value>$(OutputPath)</Value>
</_RequiredProperties>
<_RequiredItems Include="Projects">
<RequiredValue>%(Projects.Identity)</RequiredValue>
<RequiredFilePath>%(Projects.Identity)</RequiredFilePath>
</_RequiredItems>
</ItemGroup>
<!-- Raise an error if any value in _RequiredProperties is missing -->
<Error Condition="'%(_RequiredProperties.Value)'==''"
Text="Missing required property [%(_RequiredProperties.Identity)]"/>
<!-- Raise an error if any value in _RequiredItems is empty -->
<Error Condition="'%(_RequiredItems.RequiredValue)'==''"
Text="Missing required item value [%(_RequiredItems.Identity)]" />
<!-- Validate any file/directory that should exist -->
<Error Condition="'%(_RequiredItems.RequiredFilePath)' != '' and !Exists('%(_RequiredItems.RequiredFilePath)')"
Text="Unable to find expeceted path [%(_RequiredItems.RequiredFilePath)] on item [%(_RequiredItems.Identity)]" />
</Target>
<PropertyGroup>
<BuildDependsOn>
SharedBuild_Validate;
BeforeBuild;
CoreBuild;
AfterBuild;
</BuildDependsOn>
</PropertyGroup>
<Target Name="Build" DependsOnTargets="$(BuildDependsOn)"/>
<Target Name="BeforeBuild"/>
<Target Name="AfterBuild"/>
<Target Name="CoreBuild">
<!-- Make sure output folder exists -->
<PropertyGroup>
<_FullOutputPath>$(OutputPath)$(Configuration)\</_FullOutputPath>
</PropertyGroup>
<MakeDir Directories="$(_FullOutputPath)"/>
<MSBuild Projects="@(Projects)"
BuildInParallel="true"
Properties="OutputPath=$(_FullOutputPath)"/>
</Target>
</Project>
Не смотрите слишком много на цель SharedBuild_Validate
. Я добавил это для полноты, но не зацикливался на этом. Вы можете найти больше информации об этом в моем блоге на http://sedodream.com/2009/06/30/ElementsOfReusableMSBuildScriptsValidation.aspx.
Важными частями, на которые следует обратить внимание, являются точки расширяемости. Несмотря на то, что это очень простой файл, он содержит все компоненты многократно используемого файла .targets. Вы можете настроить его поведение, передавая различные свойства и элементы для сборки. Вы можете расширить его поведение, переопределив цель (BeforeBuild
, AfterBuild
или даже CoreBuild
), и вы можете добавить свои собственные цели в сборку с помощью:
<Project ...>
...
<Import Project="SharedBuild.targets"/>
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
CustomAfterBuild
</BuildDependsOn>
</PropertyGroup>
<Target Name="CustomAfterBuild">
<!-- Insert stuff here -->
</Target>
</Project>
В вашем случае я бы создал файл SvnExport.targets, который использует необходимые свойства:
- SvnExportRoot
- SvnUrl
- SvnWorkingDirectory
Вы будете использовать эти свойства для экспорта.
Затем создайте еще один для сборки и развертывания Biztalk. Вы можете разделить это на 2, если это необходимо.
Затем внутри вашего .proj-файла вы просто импортируете оба и настраиваете цели для построения в правильном порядке, а затем выключаете.
Это только начало создания многократно используемых элементов сборки, но это должно заставить колеса вращаться в вашей голове. Я собираюсь опубликовать все это в моем блоге , а также ссылки для загрузки всех файлов.
UPDATE:
Опубликовано в блог на http://sedodream.com/2010/03/19/ReplacingSolutionFilesWithMSBuildFiles.aspx