“DependsOnTargets”和“AfterTargets”之间有什么区别?

73

DependsOnTargetsAfterTargets有什么区别呢?我分辨不清这两个参数。

9个回答

90

DependsOnTargets

该属性定义了在执行目标前必须被先执行的目标

<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 和 AfterTargets(仅适用于 MSBuild 4)

表示目标应该在指定的目标之前或之后运行

<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
  • 如果您有多个目标应该在同一个指定目标之前或之后运行,它们将按照声明顺序执行:

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

BeforeTargetsAfterTargets可以用于扩展现有的构建流程

例如,通过使用这些属性,您可以在CoreCompile定义在Microsoft.CSharp.targets中)之前轻松执行目标。如果没有这个属性,您将不得不重写属性CoreCompileDependsOn

如果没有AfterTargets,您就没有办法在另一个目标之后轻松地执行一个目标,除非定义了扩展点(在目标末尾使用CallTarget和一个可覆盖的属性)。

DependsOnTargets、BeforeTargets和AfterTargets的执行顺序?

当在同一个目标上使用DependsOnTargetsBeforeTargetsAfterTargets时,执行顺序为:

  • DependsOnTargets
  • BeforeTargets
  • 该目标
  • 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

4
我认为你执行顺序错了,应该是 AfterTargets -> 目标 -> BeforeTargets - Jez
10
我不明白为什么这个答案排名第一。它没有解释AfterTargets和DependsOnTargets之间的行为差异。实际上,aprelev的评论已经回答了这个问题。 - tgeng

23
更简洁地说,来自 Microsoft Docs 上的这个 GitHub 问题<Target Name="x" DependsOnTargets="y" /> 的意思是:
如果要运行 x,必须先运行 y<Target Name="a" AfterTargets="b" /> 的意思是:
如果运行了 b,则在其后运行 a

12

尽管之前提供的其他答案是正确的,但我认为它们没有提到我认为AfterTargets相对于DependsOnTargets的主要优点。

DependsOnTargets从MSBuild的开始就存在了。 DependsOnTargets的问题在于,它要求目标作者显式地允许可扩展性。这是通过定义一个属性作为DependsOnTargets值来完成的,如下所示:

<PropertyGroup>
   <SomeTargetDependsOnTargets>
     Dependency1;Dependency2
   </SomeTargetDependsOnTargets>
</PropertyGroup>

<Target Name="SomeTarget" DependsOnTargets="$(SomeTargetDependsOnTargets)">
 ...
</Target>

您可以通过修改SomeTargetDependsOnTargets属性来添加依赖项,方法如下:

然后,您可以通过修改SomeTargetDependsOnTargets属性来添加依赖项,方法如下:

<SomeTargetDependsOnTargets>
    $(SomeTargetDependsOnTargets);Dependency3
</SomeTargetDependsOnTargets>

这个设计的问题在于,如果作者只是将Dependency1;Dependency2内联而不是提取为属性,就没有办法进行外部修改以进行定制。

另一方面,AfterTargets不需要原始目标作者显式地将DependsOnTargets值提取到属性中以实现可扩展性。


我认为你的回答正确地回答了这个问题。不确定为什么一个关于这些含义的解释被标记为答案。无论如何,你的回答确实帮助我理解了区别。谢谢。 - Shreedhar Kotekar

7
我认为答案要简单得多。DependsOnTargets和AfterTargets的效果基本相同。BeforeTargets和AfterTargets的原因(来自Microsoft文档)是:
这使项目作者可以在不直接修改它们的情况下扩展现有一组目标。
因此,如果您有一个现有的目标B,并且您想添加一个必须首先执行的新目标A,则有两个选择:
1. 修改目标B以读取:DependsOnTargets="A"。 2. 修改目标A以读取:BeforeTargets="B"。
如果您无法修改B(例如,它是现有的Microsoft目标),那么您需要BeforeTargets。

18
针对你的第二个陈述,"不,它们不一样",有一个特别的细节需要注意,其他人都没有提到:考虑将目标A构建为 msbuild /t:A 的方式。当使用 DependsOnTargets 属性指定依赖关系时,在这种方式下调用 msbuild 不会构建目标B。但是,当使用 AfterTargets 属性指定依赖关系时,在这种方式下调用 msbuild 将构建目标B - aprelev
@aprelev:好的,说得很好。在我自己的辩护中,我确实说了“本质上” :-) 我只考虑了依赖链,假设初始目标是“B”或者其他依赖于它的内容。感谢您指出这个细节。 - Steve Robbins
谢谢@aprelev,你的评论是我在这整个页面中找到的唯一有用的东西。谢谢! - tgeng

3

还有一个差异,正如另一个答案中提到的那样,

BeforeTargetsAfterTargets会在无论条件如何都运行,而DependsOnTargets(以及目标本身)则在条件评估为false时被跳过。

  1. 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>
    
  2. 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>
    

1
AfterTargetsDependsOnTargets之间还有一个区别。
当你有一个目标依赖链/图时,请注意将1个或多个目标放入BeforeTargetsAfterTargets中,它的行为类似于“任意”,而不是“所有”。
它的作用就像在说“如果任何一个已经运行过了……”,而不是“如果所有的都运行过了……”
假设你想要实现这种目标依赖链:A1 -> A2 -> A3
以下不会起作用:
<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>

输出结果将为:
A1
A3
A2

如前所述这里,以上只是意味着:

 

<Target Name="A1" BeforeTargets="Compile">

如果Compile想要运行,需要先运行A1
<Target Name="A3" AfterTargets="A1;A2">

如果A1运行,那么在它之后运行A3
如果A2运行,那么在它之后运行A3
<Target Name="A2" AfterTargets="A1">

如果 A1 运行,那么运行 A2
因此,运行 A1 将触发运行 A3。注意,声明顺序很重要!
我们想说的是 A3 依赖于 A1A2,但上面的内容并不意味着这一点。
从另一个角度来看,声明如下:
<Target Name="A3" AfterTargets="A1;A2">

如果任何AfterTargets已经执行,那么我也要执行。
如果A1或者A2执行了,那么就执行A3

 

为了安全地实现目标依赖链A1 -> A2 -> A3,我会这样使用DependsOnTargets

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

DependsOnTargets中声明目标的所有依赖关系可以创建我们想要的图/链。
请注意,我们需要在此处将所有目标挂钩到构建中以进行额外的步骤,因为DependsOnTargets不会这样做(与AfterTargets不同)。 (上面的代码在所有目标中使用BeforeTargets="Compile"来实现此目的)
但是,由于我们声明了目标之间的依赖关系,所以声明顺序(因此挂钩顺序)并不重要。

1

DependsOnTarget

假设你有两个任务:

  1. 构建项目
  2. 复制所有内容

你可以通过执行任务2开始你的构建,然后在任务声明中定义其依赖关系。因此,如果你定义任务2依赖于任务1,则构建过程将开始并执行任务1,然后是2。

AfterTargets

更简单:它只意味着在其他目标之后执行的任务。所以,以上面的例子为例,在任务1之后-构建项目执行任务2。

我希望这能帮到你。


0

主要有两个区别:

  • 第一:在 dependsOnTargets 属性中指定的目标会在 AfterTargets 中指定的目标之前执行。

  • 第二:如果 AfterTargets 属性中指定的一个目标已经被执行,那么这个目标也会在之后被执行(我是指在指定 AfterTargets 属性的目标之后),而对于 DependsOnTargets 中的目标则不是这样。


0
它们彼此相反。 DependsOnTargets 影响当前任务的行为,而不影响引用任务的行为。 AfterTargets 影响引用任务的行为,而不影响当前任务的行为。
例如,如果你有以下目标:
<Target Name="A" DependsOnTargets="B" />
<Target Name="B" />
<Target Name="C" AfterTargets="B" />

然后你会得到以下的执行顺序:
执行目标 执行顺序 A B -> C -> A B B -> C C C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接