Как избежать повторения в MSBuild? - PullRequest
6 голосов
/ 27 января 2011

Я не против случайного повторения чего-либо, когда это необходимо, но в MSBuild я действительно не знаю, как когда-либо избежать повторения. Он не предлагает «функции» в обычном смысле; цель может быть вызвана только один раз, даже через CallTarget, а <Import> работает только на уровне Project.

Вот конкретный пример, который я пытаюсь де- «повторить»:

<Target Name="Tgt1">
  <PropertyGroup><Conf1>Twiddle</Conf1><Conf2>Thing</Conf2></PropertyGroup>

  <PropertyGroup><xxxxxxxxxxExePath>$(xxxxxxxBuildRoot)\$(Conf1)Console-xxxxxxxxed</xxxxxxxxorExePath></PropertyGroup>
  <MSBuild Projects="$(BuildSingleProj)" Targets="Build;Merge"
           Properties="Configuration=$(Conf1)$(Conf2);Platform=$(Platform);CompiledFileName=$(CompiledFileName);ProjectName=$(ProjectName);SolutionFile=$(SolutionFile);Root=$(Root);Caller=$(MSBuildProjectFullPath)"/>
  <MakeDir Directories="$(xxxxxxxxorExePath)" />
  <WriteLinesToFile File="$(xxxxxxxxorExePath)\xxxxxxx.IsPortable.txt" />
  <WriteLinesToFile File="$(xxxxxxxxorExePath)\xxxxxxx.Global.Settings.xml" Lines="@(xxxxxxxLicense)" Overwrite="true" />
  <Exec Command='$(xxxxxxxxorExePath)\xxxxxxx.exe -a "$(xxxxxxxBuildRoot)\$(Conf1)$(Conf2)-Merged\xxxxxxx.exe" "$(xxxxxxxBuildRoot)\$(Conf1)$(Conf2)-xxxxxxxxed\xxxxxxx.exe"'/>
</Target>

У меня есть четыре таких цели, Tgt1, Tgt2, Tgt3, Tgt4. Отличительной чертой * между этими четырьмя целями является первая строка, определяющая Conf1 и Conf2.

Единственная более или менее работоспособная идея дедупликации, о которой я знаю, это перемещение общего кода в новую цель и вызов его через задачу MSBuild. К сожалению, для этого требуется вручную передать строку свойств loooooong , и в этой задаче используется довольно мало (я насчитал 11 свойств и 1 группу элементов).

Дополнительным требованием является то, что я могу вызвать сценарий с произвольным подмножеством этих целей, например, \t:Tgt2,Tgt3.

Есть ли разумная альтернатива просто копировать / вставлять этот кусок кода - вместо этого вместо копирования огромных списков свойств?

Ответы [ 2 ]

8 голосов
/ 27 января 2011

Это идеальный сценарий для использования Batching .

Вам нужно будет создать пользовательские Предметы с соответствующими метаданными, а затем создать одну цель для ссылки на новые предметы.

Вы можете обернуть каждый предмет в его собственныйцель вот так:

<Target Name="Tgt1">
  <ItemGroup>
    <BuildConfig Include="Tgt1">
      <Conf1>Twiddle</Conf1>
      <Conf2>Thing</Conf2>
    </BuildConfig>
  </ItemGroup>
</Target>

<Target Name="Tgt2">
  <ItemGroup>
    <BuildConfig Include="Tgt2">
      <Conf1>Twaddle</Conf1>
      <Conf2>Thing 1</Conf2>
    </BuildConfig>
  </ItemGroup>
</Target>

<Target Name="Tgt3">
  <ItemGroup>
    <BuildConfig Include="Tgt3">
      <Conf1>Tulip</Conf1>
      <Conf2>Thing 2</Conf2>
    </BuildConfig>
  </ItemGroup>
</Target>

Затем вам понадобится основная цель для вызова, которая будет выполнять всю работу следующим образом:

<Target Name="CoreBuild" Outputs="%(BuildConfig.Identity)">
  <Message Text="Name  : %(BuildConfig.Identity)" />
  <Message Text="Conf1 : %(BuildConfig.Conf1)" />
  <Message Text="Conf2 : %(BuildConfig.Conf2)" />
</Target>

Добавление Outputs="%(BuildConfig.Identity)" к цели будетубедитесь, что вы выполняете пакет на уровне цели, а не на уровне задач.

Вы можете выполнить это из msbuild с передачей произвольных комбинаций целей, пока последняя цель является вашей основной целью.Например, выполнение этой команды MSBuild.exe test.msbulid /t:Tgt1,Tgt3,CoreBuild даст следующий вывод:

Name  : Tgt1
Conf1 : Twiddle
Conf2 : Thing

Name  : Tgt3
Conf1 : Tulip
Conf2 : Thing 2
5 голосов
/ 30 января 2011

DRY не является принципом MSBuild. С учетом вышесказанного не стоит повторяться в любом случае, когда этого можно разумно избежать. Ответ, который дал Аарон относительно дозирования, является хорошим. Это одно из средств предотвращения дублирования.

Одна вещь, на которую я хотел бы обратить внимание, заключается в том, что на более высоком уровне кажется, что вы думаете о MSBuild как о процедурном языке (т. Е. Имеете функции, которые вы можете вызывать, а что нет). MSBuild гораздо более декларативный, чем процедурный. Если вы создаете сценарии MSBuild и у вас есть мышление «Создайте функцию X, чтобы я мог вызвать ее в точке Y», то вы попадаете в мир боли. Вместо этого вы должны думать о MSBuild как о фазах. Например; собирать файлы, компилировать, публиковать и т. д. Когда вы думаете об этом таким образом, то имеет смысл понять, почему цели пропускаются после того, как они были выполнены один раз (, что вы, очевидно, наблюдали во время ваших испытаний ).

Кроме того, после того, как я так долго работал с MSBuild, я понял, что это действительно может быть PITA, чтобы делать вещи универсальным / универсальным способом повторного использования. Это можно сделать, но я бы зарезервировал этот тип усилий для файлов .targets, которые, как вы знаете, наверняка будут использованы повторно много раз. Теперь дни, вместо того, чтобы проходить через это, я гораздо более прагматичен, и я оказываюсь где-то между полностью хакерскими сценариями и действиями, которые я делал раньше. У меня есть набор сценариев, которые я использую повторно, но помимо них я стараюсь сделать все проще. Одна из главных причин этого заключается в том, что многие люди знакомы с основами MSBuild, но очень немногие знают об этом очень глубоко. Создание хороших общих сценариев требует глубоких знаний о MSBuild, поэтому, когда вы покидаете проект, человек, который приходит за вами, не будет знать, что вы делаете ( возможно, хорошо, если вы являетесь подрядчиком? Lol ).

В любом случае у меня есть куча ресурсов для пакетирования по адресу: http://sedotech.com/Resources#Batching.

...