我刚刚在http://sedodream.com/2012/05/14/MSBuildHowToExecuteATargetAfterCoreCompile.aspx上写了这篇博客,但我在下面为您粘贴了内容。
我今天在 StackOverflow 上,注意到一个问题“<a href="https://stackoverflow.com/q/10555649/105999">如何创建一个在 CoreCompile 时执行的目标,并且被跳过什么时候跳过 CoreCompile?” 下面是我的回答。
对于一般情况,这是一个很难解决的问题,但在您的情况下,这很容易,因为 CoreCompile 对这种情况有特殊的内置支持。在详细介绍如何使用 CoreCompile 完成此任务之前,让我先解释一下它的一般工作原理。
一般情况说明
在 MSBuild 中,由于增量构建,目标被跳过。增量构建完全由目标本身的输入和输出属性驱动。输入是目标将“使用”的文件列表,输出是目标“生成”的文件列表。我使用引号是因为它是一个松散的概念,而不是一个具体的概念。为了简化它,您可以将输入/输出视为文件列表。当目标即将执行时,MSBuild 将获取输入并将它们的时间戳与输出进行比较。如果所有输出都比输入新,则将跳过目标。(仅供参考,如果您想知道只有一些输出过期时会发生什么,请阅读我的博客http://sedodream.com/2010/09/23/MSBuildYouveHeardOfIncrementalBuildingButHaveYouHeardOfPartialBuilding。
在任何情况下,如果您希望跳过某个目标,您必须正确地制作您的输入/输出。在您的情况下,您希望在跳过 CoreCompile 时跳过您的目标,因此从表面上看,您似乎可以简单地复制 CoreCompile 的输入/输出,但这不起作用。它不起作用,因为执行 CoreCompile 时,文件可能已过时,但该目标本身会使它们保持最新。然后,当您的目标被执行时,因为它们都是最新的,它将被跳过。您必须复制输入/输出并将附加文件附加到目标创建的输入/输出。这将确保您的目标在第一次通过时不会被跳过。
CoreCompile的具体解决方案
如果您查看项目文件,您将在底部看到文件 Microsoft.Common.targets 已导入,然后此文件将导入特定于语言的 .targets 文件。例如,它将导入 Microsoft.CSharp.targets 或 Microsoft.VisualBasic.targets(如果您使用的是 C# 或 VB)。在这些 .targets 文件中,您会发现定义了 CoreCompile。在 CoreCompile 的定义中,您将在末尾找到以下内容。
<CallTarget Targets="$(TargetsTriggeredByCompilation)" Condition="'$(TargetsTriggeredByCompilation)' != ''"/>
这将调用TargetsTriggeredByCompilation
属性中定义的所有目标。因此,如果您希望在执行CoreCompile 时调用您的目标,您可以扩展该属性。这是如何做到这一点的。
<PropertyGroup>
<TargetsTriggeredByCompilation>
$(TargetsTriggeredByCompilation);
MyCustomTarget
</TargetsTriggeredByCompilation>
</PropertyGroup>
<Target Name="MyCustomTarget">
<Message Text="MyCustomTarget called" Importance ="high"/>
</Target>
在这种情况下,我定义属性TargetsTriggeredByCompilation并将 MyCustomTarget 附加到它。包含$(TargetsTriggeredByCompilation);非常重要。在那里,如果你不这样做,那么你将不会追加而是覆盖。因此,如果其他人使用此技术,您将消灭他们的目标。
下图显示了我构建一次并执行 CoreCompile 和 MyCustomTarget 的位置。然后第二个构建 CoreCompile 被跳过,任何 MyCustomTarget 永远不会被调用。
