Запутался в содержании MSBuild ItemGroup

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

Я делаю это с задачей копирования. Вот так:

<ItemGroup>
    <OutputFiles1 Include="Project1\bin\Release\*.*" />
    <OutputFiles2 Include="Project2\bin\Release\*.*" />
</ItemGroup>

<Target CopyOutput>
    <Copy SourceFiles="@(OutputFiles1)" DestinationFolder="DeployOutput" />
    <Copy SourceFiles="@(OutputFiles2)" DestinationFolder="DeployOutput" />
</Target>

Проблема, с которой я сталкиваюсь, заключается в следующем: два элемента ItemGroup содержат содержимое каталогов при запуске сценария сборки, а не содержимое каталогов после завершения сборки решения.

Так, например, если я добавлю ссылку в Project1 к новой сборке, а затем запусту сборку, каталог DeployOutput не будет содержать эту новую сборку, поскольку ее не было в выходном каталоге проекта на момент начала сборки. Но если я снова запускаю сборку, файл там и копируется.

Кажется, что это поведение разработано, но я не уверен, как выполнить мою задачу, не вызывая пакетный файл или что-то подобное, чтобы сделать копию.

1 ответ

Решение

Классическая проблема порядка оценки msbuild: элементы и свойства в корне проекта в основном оцениваются при разборе перед выполнением каких-либо целей. Поместите их в цель, однако, и они оцениваются, когда цель выполняется. Что лучше для вашего случая, так как вы также можете убедиться, что одна цель работает за другой, и, следовательно, сделать первые увидеть результаты, полученные последней. Иллюстрация:

<ItemGroup>
  <OutputFiles1 Include="Project1\bin\Release\*.*" />
</ItemGroup>

<Target Name="BuildIt">
  <Message Text="OutputFiles1=@(OutputFiles1 )" />
  <MSBuild Projects="Project1.vcxproj" Targets="Build" />
</Target>

<Target Name="Copy" DependsOnTargets="BuildIt">
  <ItemGroup>
    <ActualOutputFiles1 Include="Project1\bin\Release\*.*" />
  </ItemGroup>
  <Message Text="OutputFiles1=@(OutputFiles1)" />
  <Message Text="ActualOutputFiles1=@(ActualOutputFiles1 )" />
</Target>

При запуске цели копирования (а выходной каталог все еще пуст) вы получите вывод

OutputFiles1=
.... build output ....
OutputFiles1=
ActualOutputFiles1=Project1\bin\Release\a.dll;......

OutputFiles1 всегда пуст, поскольку во время оценки выходной каталог был пустым. Однако ActualOutputFiles1 был оценен после сборки, поэтому он содержит содержимое выходного каталога.

Другие вопросы по тегам