How to avoid repetition in MSBuild?

I am not against accidentally repeating something when necessary, but in MSBuild I really don't know how to avoid repeating. He does not offer "functions" in the usual sense; the target can be called only once, even through CallTarget , and <Import> only works at the Project level.

Here is a specific example that I am trying to de-repeat:

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

I have four such goals: Tgt1 , Tgt2 , Tgt3 , Tgt4 . only thing that differs from these four goals is the first line that defines Conf1 and Conf1 .

The only more or less effective idea of ​​eliminating duplication that I know of is to move common code to a new target and invoke it using the MSBuild task. This, unfortunately, requires the loooooong property string to be passed manually, and this task uses several (I counted 11 properties and 1 group of elements).

An additional requirement is that I can invoke a script with an arbitrary subset of these goals, for example. \t:Tgt2,Tgt3 .

Is there any reasonable alternative to just copy / paste this piece of code - is this not about copying around huge property lists?

+6
dry msbuild
source share
2 answers

This is the perfect scenario to use batching .

You will need to create custom Elements with the appropriate metadata, and then create a single goal to link to new elements.

You can wrap each element in your own goal as follows:

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

Then you need the main goal for the call, which will do all the work as follows:

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

Adding Outputs="%(BuildConfig.Identity)" to the target will ensure that you perform a batch installation at the target level and not at the task level.

You can accomplish this from msbuild with passing arbitrary combinations of goals, as long as the last goal is your main goal. For example, running this command MSBuild.exe test.msbulid /t:Tgt1,Tgt3,CoreBuild will give you the following result:

 Name : Tgt1 Conf1 : Twiddle Conf2 : Thing Name : Tgt3 Conf1 : Tulip Conf2 : Thing 2 
+8
source share

DRY is not an MSBuild principle. With that said, it’s not good to repeat yourself anyway when you can reasonably avoid it. The answer Aaron gave regarding dosing is good. This is one way to prevent duplication.

One thing that I would like to point out is that at a higher level, it seems that you think of MSBuild as a procedural language (i.e., you have functions that you can name and which cannot). MSBuild is much more declarative than procedural. If you are creating MSBuild scripts and you have the mindset “Create function X so that I can name it at point Y” then you enter the world of pain. Instead, you should think of MSBuild as phases. For example; collect files, compile, publish, etc. When you think of it this way, it makes sense to understand why goals were missed after they were completed once (which you obviously observed during your trials).

Also, after working with MSBuild, as long as I have it, I realized that it can really be PITA to do something in universal / uber-reusable mode. This can be done, but I would reserve this type of effort for .targets files, which, as you know, will be reused many times. Now days, instead of going through it, I'm much more pragmatic, and I land somewhere between completely hacked scripts and do what I did. I have a set of scripts that I reuse, but other than the ones I try and make easier. One of the main reasons for this is that there are many people who know the basics of MSBuild, but very few who have very deep knowledge about it. Creating good general scripts requires deep knowledge of MSBuild, so when you leave the project, the person who comes for you will not know what you are doing (perhaps it is good if you are a contractor? Lol).

In any case, I have a bunch of resources in batch processing: http://sedotech.com/Resources#Batching .

+5
source share

All Articles