What is the difference between DependsOnTargets
and AfterTargets
?
I can not开发者_StackOverflow中文版 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
andAfterTargets
are run regardless of the Condition whereasDependsOnTargets
(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.
精彩评论