Как вызвать одну и ту же цель msbuild дважды с разными параметрами из самого файла проекта msbuild

У меня есть следующий фрагмент кода msbuild:

  <PropertyGroup>
    <DirA>C:\DirA\</DirA>
    <DirB>C:\DirB\</DirB>
  </PropertyGroup>

  <Target Name="CopyToDirA"
          Condition="Exists('$(DirA)') AND '@(FilesToCopy)' != ''"
          Inputs="@(FilesToCopy)"
          Outputs="@(FilesToCopy -> '$(DirA)%(Filename)%(Extension)')">
    <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="$(DirA)" />
  </Target>

  <Target Name="CopyToDirB"
          Condition="Exists('$(DirB)') AND '@(FilesToCopy)' != ''"
          Inputs="@(FilesToCopy)"
          Outputs="@(FilesToCopy -> '$(DirB)%(Filename)%(Extension)')">
    <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="$(DirB)" />
  </Target>

  <Target Name="CopyFiles" DependsOnTargets="CopyToDirA;CopyToDirB"/>

Таким образом, вызов цели CopyFiles копирует соответствующие файлы в $(DirA) и $(DirB), при условии, что они еще не обновлены.

Но цели CopyToDirA и CopyToDirB выглядят одинаково, за исключением того, что одна копируется в $(DirA), а другая - в $(DirB). Можно ли объединить их в одну цель, сначала вызываемую с помощью $(DirA), а затем с помощью $(DirB)?

Спасибо.


person mark    schedule 18.08.2009    source источник


Ответы (3)


Вы должны иметь возможность генерировать ItemGroup, содержащую Dirs, а затем % на этом.

<ItemGroup>
    <Dirs Include="C:\DirA\;C:\DirB\">
</ItemGroup>
<Target Name="CopyFiles"
    Condition="Exists('%(Dirs)') AND '@(FilesToCopy)' != ''"
    Inputs="@(FilesToCopy)"
    Outputs="@(FilesToCopy -> '%(Dirs)%(Filename)%(Extension)')">
    <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="%(Dirs)" />
</Target>

Или вы можете сделать 2 явных вызова:

<Target Name="CopyFiles">
    <MsBuild Projects="$(MSBuildProjectFullPath)" Targets="CopyASetOfFiles" Properties="FilesToCopy=@(FilesToCopy);DestDir=$(DirA)" />
    <MsBuild Projects="$(MSBuildProjectFullPath)" Targets="CopyASetOfFiles" Properties="FilesToCopy=@(FilesToCopy);DestDir=$(DirB)" />
</Target>

<Target Name="CopyASetOfFiles"
    Condition="Exists('$(DestDir)') AND '@(FilesToCopy)' != ''"
    Inputs="@(FilesToCopy)"
    Outputs="@(FilesToCopy -> '$(DestDir)%(Filename)%(Extension)')">
    <Copy SourceFiles="@(FilesToCopy)" DestinationFolder="$(DestDir)" />
</Target>

Я не проверял ни один синтаксис, но относительно более уверен во втором.

(Ответ, если он есть, находится в моей книге Сайед Хашими на моем столе — вам придется подождать до первого из:

  1. Получить книгу
  2. мне скучно
  3. Сайед находит этот пост и предлагает блестящий проверенный ответ)
person Ruben Bartelink    schedule 18.08.2009
comment
Привет Рубен. Не могли бы вы расширить ... в своем ответе? Я не настолько знаком с параметризованными целями, чтобы понять, что вы имеете в виду. Спасибо. - person mark; 19.08.2009
comment
@марк: готово. Причина, по которой я не делал этого раньше, двоякая: 1. Не было под рукой хорошего редактора. 2. не уверен в синтаксисе первого примера. Надеюсь это поможет. Очень рекомендую книгу Inside MSBuild. - person Ruben Bartelink; 19.08.2009
comment
Я думаю, что есть проблема с решением №. 2. Если ваш скрипт сборки вызывается с определенными свойствами из командной строки, эти свойства не передаются при использовании задачи ‹MsBuild›. - person Pete; 04.10.2012
comment
Я заменил $(MSBuildProjectFile) на $(MSBuildProjectFullPath), чтобы было яснее, что цель CopyFiles разветвляет другую MSBuild для вызова Target непосредственно под и, следовательно (если в игре нет InitialTargets), единственная цель, которая когда-либо будет выполняться, это CopyASetOfFiles, которая требуются только два переданных Properties (а именно FilesToCopy и DestDir). Ключевой момент, который бросается в глаза при полировке ответа для меня, - это BuildInParallel="true" и %-пакетно над Dirs, чтобы сделать их распараллеливаемыми. Надеюсь, вы согласны с моими рассуждениями, и я ничего не упускаю! - person Ruben Bartelink; 04.10.2012
comment
@Pete: Основная проблема с решением № 2 заключается в том, что это бессмысленная легкомысленность, если единственной заботой является копирование файлов и / или выполнение всего, что может быть объединено в Target - случаи, когда нужно иметь копирование и вставка-и -slightly-modify Targets или форк другого MSBuild намного реже, чем можно подумать, т.е. № 1 более идиоматичен :D - person Ruben Bartelink; 04.10.2012


Да, то, что вы хотите, называется пакетной обработкой в ​​MSBuild. То

;%(Dirs.Identity)

Определенный в Outputs вызовет выполнение этой задачи для каждого элемента в Dirs ItemGroup.

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="CopyFiles"
   xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 
   ToolsVersion="3.5">

<ItemGroup>
    <Dirs Include="C:\DirA" />
    <Dirs Include="C:\DirB" />
</ItemGroup>

<Target Name="CopyFiles"
    Inputs="@(FilesToCopy);@(Dirs)"
    Outputs="@(FilesToCopy -> '%(Dirs.Identity)%(Filename)%(Extension)');%(Dirs.Identity)" >
    <Message Text="%(Dirs.Identity)" />
</Target>

</Project>

Выходы:

Build started 8/19/2009 10:11:57 PM.
Project "D:\temp\test.proj" on node 0 (default targets).
  C:\DirA
CopyFiles:
  C:\DirB
Done Building Project "D:\temp\test.proj" (default targets).

Измените задачу сообщения на задачу копирования со следующим условием, и все готово:

Condition="Exists('%(Dirs.Identity)') AND '@(FilesToCopy)' != ''"
person Todd    schedule 20.08.2009