2011-01-26 4 views
6

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

Вот конкретный пример, который я пытаюсь Де- "repetize":

<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. Это, к сожалению, требует строку свойств свойств, которые должны быть вручную переданы, и эта задача использует несколько (я посчитал 11 свойств и 1 группу элементов).

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

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

ответ

8

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

Вам необходимо создать пользовательский Items с соответствующими метаданными, а затем создать единую цель для ссылки на новые элементы.

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

<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 
+0

Но это означает, что я больше не могу строить только один или два из них, правильно? Любой способ сохранить эту способность? –

+0

Вы можете установить условия на предметы. Я отвечу на пример. –

+0

Спасибо, хотя я вижу, что условия становятся довольно сложными, если я хочу включить любые _two_ сборки. В настоящее время я склоняюсь к сохранению повторения, потому что я хочу сохранить возможность указывать '/ t: Tgt1, Tgt2' - у реального скрипта действительно есть еще несколько целей, и мы полагаемся на способность выбирать произвольные подмножества как это. –

5

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

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

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

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

+0

Спасибо за это понимание; надеюсь, спаси меня, я слишком стараюсь. Я пытался видеть MSBuild как декларативный, но, безусловно, даже декларативным языкам нужен механизм для создания абстракций. Простите меня за предложение имени «функции», это, безусловно, неправильный термин. –

+0

Я тайно надеялся, что есть какой-то классный механизм, который был мне неизвестен. Может быть, какой-то способ облегчить боль при передаче _same_ набора из 10+ свойств нескольким задачам MSBuild? Я почти добрался туда, только свойства получили оценку слишком рано, и я не смог найти ничего подобного «eval», чтобы оценить их так же, как они переданы в MSBuild ... –

+0

Если вы хотите «eval», то вы необходимо разместить ItemGroup внутри цели, которую вы будете выполнять. Элементные элементы ItemGroup за пределами целевых объектов оцениваются до любых целевых объектов, но элементы ItemGroup внутри целей оцениваются во время выполнения цели. –

Смежные вопросы