How can I evaluate MS Build Variables? - msbuild

For example, if I wanted to output the value of
$(SolutionRoot)
How can I do it?

In a Target, use Task 'Message'
<Target Name="PrintCurrentSettings">
<Message Text=" $SolutionRoot : $(SolutionRoot)"/>
</Target>

Related

Parse key/value pairs from MSBuild property

Say I have a property like:
<MyProp>Foo=Bar;Hello=World</MyProp>
This seems like a reasonably common property pattern in MSBuild. How would I go about fetching the value "World"? In an ideal world this might look something like:
$(MyProp).(Hello)
Edit: To be clear, the property is not of my own creation, it is the output from another target that is out of my control, so I cannot change the way the property is declared.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MyProp>Foo=Bar;Hello=World</MyProp>
</PropertyGroup>
<Target Name="Foo">
<CreateItem Include="MyProp" AdditionalMetadata="$(MyProp)">
<Output TaskParameter="Include" ItemName="MyProp" />
</CreateItem>
<Message Text="Foo %(MyProp.Foo)" />
<Message Text="Hello %(MyProp.Hello)" />
</Target>
</Project>
You have two routes to follow as far as I am concerned
Declare a Property Group just like the following:
<PropertyGroup>
<Foo>Bar</Foo>
<Hello>World</Hello>
</PropertyGroup>
and then use the following method to access your properties
<Target Name="DoSomething">
<Message Text="Print this : $(Foo)" />
</Target>
or you might want to take ItemGroup Element approach like the following
<ItemGroup>
<MySolutionFiles Include="..\mySolution.sln" />
</ItemGroup>
<Target Name="PrintItems">
<Message Text="My Files: #(MySolutionFiles)" />
</Target>
You can have the following as well
<ItemGroup>
<MyProp
Include="Foo;Hello" />
</ItemGroup>
<Target Name="PrintMyItems">
<Message Text="MyProp: #(MyProp)" />
</Target>
If there is no choice over the input then one possible solution is parsing the input into an array and then taking it from there like the following:
<PropertyGroup>
<MyProp>Foo=Bar;Hello=World</MyProp>
<Split>$(MyProp.Split(';'))</Split>
</PropertyGroup>
and then play with the array items like the following:
<Target Name="DoPrint">
<Message text="$(Split[0])" />
</Target>
Split[0] item contains your Foo=Bar which can be split into two more strings just like above. This should keep you going for now.
You don't need a property group, it's just nice to have default values in case the user doesn't pass them.
For each property you pass, the syntax to access that property is $(PropertyName).
So if you pass:
msbuild.exe /p:P1=V1 /p:P2=V2;P3=V3
You would use the property name $(P1), $(P2), $(P3).
More on MsBuild properties here.

Can I be sure that i receive correct item if I defined item in one msbuild target and get it in other one?

I have two different targets which are invoked with one collection of properties via msbuild task. In one target I define ItemGroup and in other one I recieve it. I invoke targets in the next way:
<MsBuild Projects="deploypkg.project" Properties="CurrentSite=%(SitesName.Identity)" Targets="TargetA"/>
<MsBuild Projects="deploypkg.project" Properties="CurrentSite=%(SitesName.Identity)" Targets="TargetB"/>
When in TargetB I refer defined in TargetA ItemGroup i get items defined only for current site(input property). It's exactly what i need but I'm not sure I can rely on it, because I found nothing about this possibility.
You are not sure, you can create test.project to test it. Something like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Target Name="TargetA">
<Message Text="TargetA: CurrentSite = $(CurrentSite)"/>
</Target>
<Target Name="TargetB">
<Message Text="TargetB: CurrentSite = $(CurrentSite)"/>
</Target>
</Project>
Use test.project in your script:
<MsBuild Projects="test.project" Properties="CurrentSite=%(SitesName.Identity)" Targets="TargetA"/>
<MsBuild Projects="test.project" Properties="CurrentSite=%(SitesName.Identity)" Targets="TargetB"/>

Can't get MSBuild Community Task RegexReplace to work

I'm trying to copy a bunch of files whose names begin with the prefix DR__, but the copies must have that prefix removed. That is, DR__foo must be copied as foo. I'm trying this, which is based in the example provided in the documentation (the .chm):
<Target Name="CopyAuxiliaryFiles">
<MakeDir Directories="$(TargetDir)Parameters" Condition="!Exists('$(TargetDir)Parameters')" />
<ItemGroup>
<ContextVisionParameterFiles Include="$(SolutionDir)CVParameters\DR__*" />
</ItemGroup>
<Message Text="Files to copy and rename: #(ContextVisionParameterFiles)"/>
<RegexReplace Input="#(ContextVisionParametersFiles)" Expression="DR__" Replacement="">
<Output ItemName ="DestinationFullPath" TaskParameter="Output" />
</RegexReplace>
<Message Text="Renamed Files: #(DestinationFullPath)"/>
<Copy SourceFiles="#(ContextVisionParameterFiles)" DestinationFiles="#(DestinationFullPath)" />
</Target>
DestinationFullPath comes out empty (or that's what I see when I display it with Message). Thus, Copy fails because no DestinationFiles are specified. What's wrong here?
Edit: ContextVisionParameterFiles is not empty, it contains this:
D:\SVN.DRA.WorkingCopy\CVParameters\DR__big_bone.alut;D:\SVN.DRA.WorkingCopy\CVParameters\DR__big_medium.gop
They're actually 40 files, but I trimmed it for the sake of clarity
Got it! It seems to have been the combination of a stupid error and a seemingly compulsory parameter. As for the first one, there were two Targets called CopyAuxiliaryFiles. As for the second one, it seems the Count parameter is needed.
The final, working version:
<Target Name="CopyCvParameters">
<ItemGroup>
<CvParamFiles Include="$(SolutionDir)CVParameters\DR__*" />
</ItemGroup>
<Message Text="Input:
#(CvParamFiles, '
')"/>
<!-- Replaces first occurance of "foo." with empty string-->
<RegexReplace Input="#(CvParamFiles)" Expression="^.*DR__" Replacement="$(TargetDir)Parameters\" Count="1">
<Output ItemName ="RenamedCvParamFiles" TaskParameter="Output" />
</RegexReplace>
<Message Text="
Output RenamedCvParamFiles:
#(RenamedCvParamFiles, '
')" />
<Copy SourceFiles="#(CvParamFiles)" DestinationFiles="#(RenamedCvParamFiles)" SkipUnchangedFiles="True" />
</Target>
Notice that:
I renamed the Target to solve the name collision (Why doesn't Visual Studio detect this as an error?)
I pretty-printed the ItemGroups with the #(CvParamFiles, '
') syntax, which seems to replace ; with line breaks
My regex replaces the absolute path and the prefix
Count="1" is now passed to RegexReplace

What is the difference between 'DependsOnTargets' and 'AfterTargets'?

What is the difference between DependsOnTargets and AfterTargets?
I can not distinguish these two.
DependsOnTargets
Defines the targets that must be executed before the target can be executed.
<Target Name="DependsOn" DependsOnTargets="DependencyTarget1;DependencyTarget2">
<Message Text="Target : DependsOn"/>
</Target>
<Target Name="DependencyTarget2">
<Message Text="Target : DependencyTarget2"/>
</Target>
<Target Name="DependencyTarget1">
<Message Text="Target : DependencyTarget1"/>
</Target>
Output
> Target : DependencyTarget1
> Target : DependencyTarget2
> Target : DependsOn
BeforeTargets and AfterTargets (Only available in MSBuild 4)
Indicates that the target should run before or after the specified target or targets.
<Target Name="BeforeAndAfter">
<Message Text="Target : BeforeAndAfter"/>
</Target>
<!-- BeforeTarget1 will run BEFORE target "BeforeAndAfter" -->
<Target Name="BeforeTarget" BeforeTargets="BeforeAndAfter">
<Message Text="BeforeTarget run before : BeforeAndAfter"/>
</Target>
<!-- BeforeTarget1 will run AFTER target "BeforeAndAfter" -->
<Target Name="AfterTarget" AfterTargets="BeforeAndAfter">
<Message Text="AfterTarget run after : BeforeAndAfter"/>
</Target>
Output
> BeforeTarget run before : BeforeAndAfter
> Target : BeforeAndAfter
> AfterTarget run after : BeforeAndAfter
If you have multiples targets that should run before or after the same specified target, they will be executed in declaration order :
<Target Name="BeforeAndAfter">
<Message Text="Target : BeforeAndAfter"/>
</Target>
<!--
BOTH BeforeTarget1 and BeforeTarget2 should run before target "BeforeAndAfter"
-->
<Target Name="BeforeTarget1" BeforeTargets="BeforeAndAfter">
<Message Text="BeforeTarget1 run before : BeforeAndAfter"/>
</Target>
<Target Name="BeforeTarget2" BeforeTargets="BeforeAndAfter">
<Message Text="BeforeTarget2 run before : BeforeAndAfter"/>
</Target>
BeforeTargets and AfterTargets could be use to extend existing build process.
For example, with this attributes you can easily execute a target before CoreCompile (defines in Microsoft.CSharp.targets). Without that you'll have to override the property CoreCompileDependsOn.
Without AfterTargets you have no way to easily execute a target after another one if no extension point is defined (CallTarget at the end of the target with a property that you can override)
DependsOnTargets, BeforeTargets and AfterTargets execution order?
When DependsOnTargets, BeforeTargets and AfterTargets are used on the same target, the order of execution is :
DependsOnTargets
BeforeTargets
The target
AfterTargets
<Target Name="MainTarget" DependsOnTargets="DefaultDependsOn">
<Message Text="Target : MainTarget"/>
</Target>
<Target Name="DefaultDependsOn">
<Message Text="Target : DefaultDependsOn"/>
</Target>
<Target Name="DefaultBeforeTarget" BeforeTargets="MainTarget">
<Message Text="Target : DefaultBeforeTarget"/>
</Target>
<Target Name="DefaultAfterTarget" AfterTargets="MainTarget">
<Message Text="Target : DefaultAfterTarget"/>
</Target>
Output
> Target : DefaultDependsOn
> Target : DefaultBeforeTarget
> Target : MainTarget
> Target : DefaultAfterTarget
More succinctly from this GitHub issue on Microsoft Docs:
<Target Name="x" DependsOnTargets="y" /> means:
If something wants to run x, y must run first.
<Target Name="a" AfterTargets="b" /> means:
If something runs b, then run a after it.
While the other answers previously provided are correct, I think they failed to mention what I think is the primary benefit of AfterTargets over DependsOnTargets.
DependsOnTargets has been around from the beginning of MSBuild. The problem with DependsOnTargets, is that it requires a target author to explicitly allow for extensibility. This is done by defining a property that is used as the DependsOnTargets value, as follows:
<PropertyGroup>
<SomeTargetDependsOnTargets>
Dependency1;Dependency2
</SomeTargetDependsOnTargets>
</PropertyGroup>
<Target Name="SomeTarget" DependsOnTargets="$(SomeTargetDependsOnTargets)">
...
</Target>
You could then add a dependency by modifying the SomeTargetDependsOnTargets property as follows:
<SomeTargetDependsOnTargets>
$(SomeTargetDependsOnTargets);Dependency3
</SomeTargetDependsOnTargets>
The problem with this design, is that if the author had simply inlined Dependency1;Dependency2 rather than extracting it into a property, there would be no way to externally modify it to allow for customization.
AfterTargets, on the other hand, doesn't require the original target author to have explicitly extracted the DependsOnTargets value into a property to allow for extensibility.
I think the answer is much simpler. The effect of DependsOnTargets and AfterTargets is essentially the same. The reason for BeforeTargets & AfterTargets (from the Microsoft Documentation):
This lets the project author extend an existing set of targets without
modifying them directly.
So if you have an existing target B and you want to add a new target A that must execute first, you have two choices:
Modify target B to read: DependsOnTargets="A".
Modify target A to read: BeforeTargets="B".
If you can't modify B (e.g. it's an existing Microsoft target), that's when you need BeforeTargets.
One more difference, that is mentioned in another answer is that
BeforeTargets and AfterTargets are run regardless of the Condition whereas DependsOnTargets (and target itself) are skipped when Condition evaluates to false"
In below code second target is executed even though first target is not executed:
<Target Name="FirstTarget" AfterTargets="PostBuildEvent" Condition="'False'">
<Message Text="This target is never executed" />
</Target>
<Target Name="SecondTarget" AfterTargets="FirstTarget">
<Message Text="SecondTarget is executed" />
</Target>
In below code second target is not executed:
<Target Name="FirstTarget" AfterTargets="PostBuildEvent" Condition="'False'">
<Message Text="This target is never executed" />
</Target>
<Target Name="SecondTarget" DependsOnTargets="FirstTarget">
<Message Text="SecondTarget is executed" />
</Target>
DependsOnTarget
Let's assume that you have two tasks:
Build Project
Copy all content.
You can start your build by executing task 2 and then in the task declaration define its dependencies. So if you define that task 2 depends on task 1, the build process will start and execute task 1 and then 2.
AfterTargets
Much simpler: it means only tasks which are execute after other targets. So taking the example from above - after Task 1 - build project execute task 2.
I hope this helps
One more difference between AfterTargets and DependsOnTargets.
When you have a target dependency chain/graph, be aware that putting 1+ targets into BeforeTargets or AfterTargets works like "any", and not like "all".
It works like saying "if any of them has run...", and not "if all of them has run..."
Let's say you want to achive this target dependency chain: A1 -> A2 -> A3.
The following will not work:
<Target Name="A1" BeforeTargets="Compile">
<Message Text="A1" />
</Target>
<Target Name="A3" AfterTargets="A1;A2">
<Message Text="A3" />
</Target>
<Target Name="A2" AfterTargets="A1">
<Message Text="A2" />
</Target>
Output will be:
A1
A3
A2
Because, as already mentioned here, the above only means:
 
<Target Name="A1" BeforeTargets="Compile">
If Compile wants to run, run A1 before it.
 
<Target Name="A3" AfterTargets="A1;A2">
If A1 run, run A3 after it.
If A2 run, run A3 after it.
 
<Target Name="A2" AfterTargets="A1">
If A1 run, run A2 after it.
 
Thus, running A1 will trigger running A3.
Note, that the declaration order matters!
We wanted to say A3 depends on A1 and A2, but the above did not mean that.
Viewing from another aspect, declaring this:
<Target Name="A3" AfterTargets="A1;A2">
Works like "if any of the AfterTargets has run, run me."
If A1 or A2 run, run A3
 
To safely achive target dependency chain A1 -> A2 -> A3, I would use DependsOnTargets this way:
<Target Name="B1" BeforeTargets="Compile">
<Message Text="B1" />
</Target>
<Target Name="B3" DependsOnTargets="B1;B2" BeforeTargets="Compile">
<Message Text="B3" />
</Target>
<Target Name="B2" DependsOnTargets="B1" BeforeTargets="Compile">
<Message Text="B2" />
</Target>
Declaring all the dependencies of a Target in DependsOnTargets creates the graph/chain we wanted.
Note, that we need to hook in all the targets into the build here in a plus step, because DependsOnTargets does not do that (unlike AfterTargets). (The above code uses BeforeTargets="Compile" in all Targets to achive this)
However, since we declared the dependencies between our Targets, the declaration order (and thus the hook-in order) does not matter.
There are two mainly differences:
First: Targets specified in the dependsOnTargets attribute are
executed before those in AfterTargets.
Second: If one of the targets specified in AfterTargets attribute got executed
this target get also executed after(I mean the target
where you specify the AfterTargets attribute), which is not true for
those in DependsOnTargets.

How to set 'condition' using a condition stored in a property?

I have a condition such as 'a==1' stored in property $(c) and I wanna used it as the condition for task Message like below code:
<PropertyGroup>
<aa>1>2</aa>
</PropertyGroup>
<Target Name="t">
<Message Text="122333" Condition="$(aa)" />
</Target>
Error was raised!
So, how can I do it? Please help!
You can easily use property values for evaluating conditions. Here is an example:
<PropertyGroup>
<aa>1</aa>
</PropertyGroup>
<Target Name="Build">
<Message Text="Some text" Condition=" $(aa) < 2 " />
</Target>
Note that:
Property values are strings, you must evaluate the condition in the Condition attribute. See MSDN Docs on evaluating conditions.
You must escape XML characters (replace < with < )