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

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.

Related

Eliminate repetition in msbuild Targets? (especially repetition of item identifiers, which can't expand Property's in Exec Command attributes)

I would like to minimize repetition in my msbuild xml, particularly inside my Target's Exec Command attribute.
1) Most importantly, in the following Target I would like to un-duplicate the pair of "%(ShaderVertex.Identity)" constructs in the Exec Command attribute (for example, the Property VertexTargetName is defined to be "ShaderVertex", but %($(VertexTargetName).Identity) will not expand $(VertexTargetName)):
<Target Name="ShaderVertexBuild"
Inputs="#($(VertexTargetName))"
Outputs="#($(VertexTargetName)$(OutputRelPathAndFileName))">
<Exec Command="$(FxcPathFull)v$(ShaderArgNoFirstLetter) %(ShaderVertex.Identity)$(ShaderOutputFlagAndRelPath)%(ShaderVertex.Identity)$(OutputFileExtLetterToAppend)">
</Exec>
</Target>
2) It would also be nice not to duplicate the "ShaderVertex" identifier in the ItemGroup that precedes my Target, but again I can't expand a $(VertexTargetName) in the context of an ItemGroup.
<ItemGroup>
<ShaderPixel Include="p*.fx"/>
<ShaderVertex Include="v*.fx"/>
</ItemGroup>
3) Less importantly, it would be nice to be able to further reduce duplicate constructs between my Target's. Using the above example, I'd like to simply pass $(VertexTargetName) and the letter "v" (which tells the HLSL compiler to compile a vertex shader) to a magical Target generator that fills in all the data identical to all Targets -- or even better, just pass $(VertexTargetName) and allow the Target generator to infer from this argument that a "v" needs to be passed (instead of, say, a "p" for PixelShader, which could be inferred from $(PixelTargetName)).
Any ideas?
Caveats: I know that msbuild is not a functional programming language, and therefore may not be able to accommodate my desires here. I also know that VS2012 handles HLSL compilation automatically, but I'm on VS2010 for now, and would like to know enough about msbuild to accomplish this sort of task.
Here is the complete xml listing:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- TODO NTF: does not take into account *.inc dependency -->
<Target Name="Main">
<CallTarget Targets="ShaderPixelBuild"/>
<CallTarget Targets="ShaderVertexBuild"/>
</Target>
<ItemGroup>
<ShaderPixel Include="p*.fx"/>
<ShaderVertex Include="v*.fx"/>
</ItemGroup>
<PropertyGroup>
<ShaderModelNum>4</ShaderModelNum><!-- Radeon 8600 GTS doesn't support shader model 5 -->
<ShaderArgNoFirstLetter>s_$(ShaderModelNum)_0</ShaderArgNoFirstLetter><!-- first letter defines shader type; v=vertex, p=pixel-->
<FxcPathFull>"%DXSDK_DIR%\Utilities\bin\x64\fxc.exe" /T </FxcPathFull>
<ShaderOutputRelPath>..\..\x64\shadersCompiled\</ShaderOutputRelPath>
<ShaderOutputFlagAndRelPath> /Fo $(ShaderOutputRelPath)</ShaderOutputFlagAndRelPath>
<OutputFileExtLetterToAppend>o</OutputFileExtLetterToAppend>
<OutputRelPathAndFileName>->'$(ShaderOutputRelPath)%(identity)$(OutputFileExtLetterToAppend)'</OutputRelPathAndFileName>
<!-- Note that the content of each of these properties must be duplicated in the Exec Command twice, since %($(PropertyName)) will not expand there -->
<PixelTargetName>ShaderPixel</PixelTargetName>
<VertexTargetName>ShaderVertex</VertexTargetName>
</PropertyGroup>
<Target Name="ShaderPixelBuild"
Inputs="#($(PixelTargetName))"
Outputs="#($(PixelTargetName)$(OutputRelPathAndFileName))">
<Exec Command="$(FxcPathFull)p$(ShaderArgNoFirstLetter) %(ShaderPixel.Identity)$(ShaderOutputFlagAndRelPath)%(ShaderPixel.Identity)$(OutputFileExtLetterToAppend)">
</Exec>
</Target>
<Target Name="ShaderVertexBuild"
Inputs="#($(VertexTargetName))"
Outputs="#($(VertexTargetName)$(OutputRelPathAndFileName))">
<Exec Command="$(FxcPathFull)v$(ShaderArgNoFirstLetter) %(ShaderVertex.Identity)$(ShaderOutputFlagAndRelPath)%(ShaderVertex.Identity)$(OutputFileExtLetterToAppend)">
</Exec>
</Target>
</Project>

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

Is it possible to refer to metadata of the target from within the target implementation in MSBuild?

My msbuild targets file contains the following section:
<ItemGroup>
<Targets Include="T1">
<Project>A\B.sln"</Project>
<DependsOnTargets>The targets T1 depends on</DependsOnTargets>
</Targets>
<Targets Include="T2">
<Project>C\D.csproj"</Project>
<DependsOnTargets>The targets T2 depends on</DependsOnTargets>
</Targets>
...
</ItemGroup>
<Target Name="T1" DependsOnTargets="The targets T1 depends on">
<MSBuild Projects="A\B.sln" Properties="Configuration=$(Configuration)" />
</Target>
<Target Name="T2" DependsOnTargets="The targets T2 depends on">
<MSBuild Projects="C\D.csproj" Properties="Configuration=$(Configuration)" />
</Target>
As you can see, A\B.sln appears twice:
As Project metadata of T1 in the ItemGroup section.
In the Target statement itself passed to the MSBuild task.
I am wondering whether I can remove the second instance and replace it with the reference to the Project metadata of the target, which name is given to the Target task?
Exactly the same question is asked for the (Targets.DependsOnTargets) metadata. It is mentioned twice much like the %(Targets.Project) metadata.
Thanks.
EDIT:
I should probably describe the constraints, which must be satisfied by the solution:
I want to be able to build individual projects with ease. Today I can simply execute msbuild file.proj /t:T1 to build the T1 target and I wish to keep this ability.
I wish to emphasize, that some projects depend on others, so the DependsOnTargets attribute is really necessary for them.
Target names must be fixed values, so what you have here wouldn't work.
Also I would recommend not using Batching Expressions inside of the DependsOnTargets expression as well. This could lead to strange behavior if you do not fully understand what is happening.
In your case you may be able to just create a "driver" target which uses those items to perform the build. The only difficult part would be the DependsOnTargets that you are trying to perform. I'm not sure about the details on what you are trying to do with that so cannot make any suggestions but as for the other take a look at creating a target similar to.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Targets Include="T1">
<Project>A\B.sln"</Project>
<DependsOnTargets>The targets T1 depends on</DependsOnTargets>
</Targets> <Targets Include="T2">
<Project>C\D.csproj"</Project>
<DependsOnTargets>The targets T2 depends on</DependsOnTargets>
</Targets> ...
</ItemGroup>
<Target Name="Build">
<!--
This will be executed once for every unique value of Project in the
Target item group
-->
<MSBuild Projects="%(Targets.Project)"
Properties="Configuration=$(Configuration)"
</Target>
</Project>

MSBuild: how to create a global property?

When running MSBuild, anything passed in on the command line using /p:MyProp=value is accessible from every MSBuild script invoked (via the MSBuild task) from the main script. How can I define a property that is similarly accessible from every script, in a task?
For example:
Script1.proj:
[...]
<Target Name="Test">
<MSBuild Projects="Script2.proj"/>
<Message Text="Script1, GlobalProp1=$(GlobalProp1)"/>
<Message Text="Script1, GlobalProp2=$(GlobalProp2)"/>
</Target>
Script2.proj:
[...]
<Target Name="Test">
<!-- ??? Set GlobalProp2 = VALUE2 ??? -->
<Message Text="Script2, GlobalProp1=$(GlobalProp1)"/>
<Message Text="Script2, GlobalProp2=$(GlobalProp2)"/>
</Target>
If run like this: msbuild Script1.proj /p:GlobalProp1=VALUE1 the above scripts produce the following output:
Script2, GlobalProp1=VALUE1
Script2, GlobalProp2=
Script1, GlobalProp1=VALUE1
Script1, GlobalProp2=
I'd like Script2.proj to set GlobalProp2 somehow to produce the following output:
Script2, GlobalProp1=VALUE1
Script2, GlobalProp2=VALUE2
Script1, GlobalProp1=VALUE1
Script1, GlobalProp2=VALUE2
Is this possible, and if so, how?
I've seen suggestions to use environment variables, but it seems that the only situation in which that helps is when the variable is set in the parent script, and the child script is invoked using the Exec task (otherwise the env.variable change has no effect).
Since you are using the MSBuild task you have to pass the desired properties into the call using the Properties attribute so you should change you example to.
<Target Name="Test">
<MSBuild Projects="Script2.proj"
Properties="GlobalProp1=$(GlobalProp1);GlobalProp2=$(GlobalProp2)"
/>
<Message Text="Script1, GlobalProp1=$(GlobalProp1)"/>
<Message Text="Script1, GlobalProp2=$(GlobalProp2)"/>
</Target>
The properties must be explicitly passed, this is by design.
If you want a tighter integration then instead of using the MSBuild task you should just import the file(s) which will create 1 logical script.
You may use rsp file to define global properties. These properties are visible to child projects.

MSBuild: asterisks and strange ItemGroup Exclude behaviour

I have a script that attempts to construct an ItemGroup out of all files in a certain directory while excluding files with certain names (regardless of extension).
The list of files to be excluded initially contains file extensions, and I am using Community Tasks' RegexReplace to replace the extensions with an asterisk. I then use this list in the item's Exclude attribute. For some reason the files do not get excluded properly, even though the list appears to be correct.
To try and find the cause I created a test script (below) which has two tasks: first one initialises two properties with the list of file patterns in two different ways. The second task prints both properties and the files resulting from using both these properties in the Exclude attribute.
The properties' values appear to be identical, however the resulting groups are different. How is this possible?
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="Init;Test" ToolsVersion="3.5">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<Target Name="Init">
<ItemGroup>
<OriginalFilenames Include="TestDir\SampleProj.exe"/>
<OriginalFilenames Include="TestDir\SampleLib1.dll"/>
</ItemGroup>
<RegexReplace Input="#(OriginalFilenames)" Expression="\.\w+$" Replacement=".*">
<Output TaskParameter="Output" ItemName="PatternedFilenames"/>
</RegexReplace>
<PropertyGroup>
<ExcludeFilesA>TestDir\SampleProj.*;TestDir\SampleLib1.*</ExcludeFilesA>
<ExcludeFilesB>#(PatternedFilenames)</ExcludeFilesB>
</PropertyGroup>
</Target>
<Target Name="Test">
<Message Text='ExcludeFilesA: $(ExcludeFilesA)' />
<Message Text='ExcludeFilesB: $(ExcludeFilesB)' />
<ItemGroup>
<AllFiles Include="TestDir\**"/>
<RemainingFilesA Include="TestDir\**" Exclude="$(ExcludeFilesA)"/>
<RemainingFilesB Include="TestDir\**" Exclude="$(ExcludeFilesB)"/>
</ItemGroup>
<Message Text="
**AllFiles**
#(AllFiles, '
')" />
<Message Text="
**PatternedFilenames**
#(PatternedFilenames, '
')" />
<Message Text="
**RemainingFilesA**
#(RemainingFilesA, '
')" />
<Message Text="
**RemainingFilesB**
#(RemainingFilesB, '
')" />
</Target>
</Project>
Output (reformatted somewhat for clarity):
ExcludeFilesA: TestDir\SampleProj.*;TestDir\SampleLib1.*
ExcludeFilesB: TestDir\SampleProj.*;TestDir\SampleLib1.*
AllFiles:
TestDir\SampleLib1.dll
TestDir\SampleLib1.pdb
TestDir\SampleLib2.dll
TestDir\SampleLib2.pdb
TestDir\SampleProj.exe
TestDir\SampleProj.pdb
PatternedFilenames:
TestDir\SampleProj.*
TestDir\SampleLib1.*
RemainingFilesA:
TestDir\SampleLib2.dll
TestDir\SampleLib2.pdb
RemainingFilesB:
TestDir\SampleLib1.dll
TestDir\SampleLib1.pdb
TestDir\SampleLib2.dll
TestDir\SampleLib2.pdb
TestDir\SampleProj.exe
TestDir\SampleProj.pdb
Observe that both ExcludeFilesA and ExcludeFilesB look identical, but the resulting groups RemainingFilesA and RemainingFilesB differ.
Ultimately I want to obtain the list RemainingFilesA using the pattern generated the same way ExcludeFilesB is generated. Can you suggest a way, or do I have to completely rethink my approach?
The true cause of this was revealed accidentally when a custom task threw an exception.
The actual value of ExcludeFilesA is TestDir\SampleProj.*;TestDir\SampleLib1.* like one might expect. However the actual value of ExcludeFilesB is TestDir\SampleProj.%2a;TestDir\SampleLib1.%2a.
Presumably Message unescapes the string before using it, but Include and Exclude do not. That would explain why the strings look the same but behave differently.
Incidentally, the execution order doesn't seem to have anything to do with this, and I'm pretty sure (following extensive experimentation) that everything gets executed and evaluated exactly in the order in which it appears in this script.
ItemGroups need to be evaluated before targets execution, and the PatternedFilenames ItemGroup is being created on the fly within its target container.
You could workaround this using the CreateItem task, which will ensure the PatternedFilenames scope throughout the execution:
<RegexReplace Input="#(OriginalFilenames)" Expression="\.\w+$" Replacement=".*">
<Output TaskParameter="Output" ItemName="PatternedFilenames_tmp"/>
</RegexReplace>
<CreateItem Include="#(PatternedFilenames_tmp)">
<Output TaskParameter="Include" ItemName="PatternedFilenames"/>
</CreateItem>