Проблема с использованием MSBuild для сборки и копирования всех выходных данных в общую папку


Мы пытаемся написать сценарий msbuild, который построит решение и скопирует все скомпилированные двоичные файлы и зависимости в определенную выходную папку. В то время как сценарий сборки, который у нас есть, создает и копирует двоичные файлы в общую папку, но мы не копируем зависимости. Это, вероятно, связано с тем, как мы использовали задачу msbuild для построения решения, и мы принимаем targetoutputs задачи в itemgroup и перебираем элемент группы копировать все скомпилированные библиотеки DLL и исполняемые файлы в общей папке. Но это не включает в себя библиотеки DLL зависимостей, которые помещаются в отдельную папку bin каждого проекта.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
    <ParentSolutionFile />
</PropertyGroup>
<ItemGroup>
    <Assemblies Include="*.dll, *.exe" />
</ItemGroup>
<Target Name="BuildAll">
    <CombinePath BasePath="$(MSBuildProjectDirectory)" Paths="SourceSolutionsxxx.sln">
        <Output TaskParameter="CombinedPaths" PropertyName="ParentSolutionFile" />
    </CombinePath>
    <Message Text="$(ParentSolutionFile)" />
    <MSBuild Projects="$(ParentSolutionFile)">
        <Output TaskParameter="TargetOutputs" ItemName="Assemblies" />
    </MSBuild>
    <Message Text="%(Assemblies.Identity)" />
    <Copy SourceFiles="%(Assemblies.Identity)" DestinationFolder="$(MSBuildProjectDirectory)Binary" OverwriteReadOnlyFiles="True" SkipUnchangedFiles="True" />
</Target>

Каким будет предпочтительный способ копирования всех двоичных файлов вместе с необходимыми зависимостями в общую выходную папку?

2 2

2 ответа:

Разве переопределение OutputPath не делает трюк в одиночку?

<MSBuild Projects="$(ParentSolutionFile)" Properties="OutputPath=$(MSBuildProjectDirectory)\Binary">
  <Output TaskParameter="TargetOutputs" ItemName="Assemblies" />
</MSBuild>

И оставить задачу копирования все вместе?

Процесс сборки поместит конечный результат в каталог, представленный OutputPath - по крайней мере, если вы создаете проекты c#. Для C/C++ внутренняя структура и имена переменных совершенно разные.

Таким образом, теоретически можно передать путь вывода в MsBuild-задаче, которая строит решение.
<MsBuild Projects="$(ParentSolutionFile)"
    Properties="OutputPath=$(MSBuildProjectDirectory)\Binary"/>

Однако csproj-файлы безоговорочно перезапишут это значение следующим кодом:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\Debug\</OutputPath>

Я решил эту проблему, введя свою собственную сборку система в каждом csproj-файле.

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\..\build\buildsystem.targets" />

Путь находится относительно csproj-файла. Абсолютный путь тоже хорош, или переменная. Фокус в том, чтобы заставить его работать на всех машинах разработки, а также на агентах сборки.

Теперь в buildsystem.цели, просто переопределите OutputPath так, как вам нравится. Опять же, хитрость заключается в том, чтобы гарантировать, что вы получите то же самое - или, по крайней мере, хорошо определенное - местоположение независимо от того, кто его строит (dev, build agent) и независимо от того, как сборка была инициирована (VS, command линия).

Простой способ обработки различий состоит в том, чтобы импортировать условно.

<Import Project="..\..\..\build\buildsystem.targets"
    Condition="'$(BuildingInsideVisualStudio)'!='true'"/>

Это не даст вам никаких изменений, если вы инициируете сборку из VS и любые изменения, которые вы кодируете, если вы строите из командной строки.

-- Йеспер