更新2
根据Microsoft的文档:
这是目标构建顺序
- 运行InitialTargets目标。
- 通过/target开关在命令行上指定的目标将被运行。如果您在命令行上未指定目标,则将运行DefaultTargets目标。如果两者都不存在,则运行遇到的第一个目标。
- 评估目标的条件属性。如果存在Condition属性并且计算结果为false,则不会执行该目标,并且对构建没有进一步影响。
- 在执行目标之前,运行其DependsOnTargets目标。
- 在执行目标之前,运行任何在BeforeTargets属性中列出它的目标。
- 在执行目标之前,比较其Inputs属性和Outputs属性。如果MSBuild确定任何输出文件与相应的输入文件过期,则MSBuild执行该目标。否则,MSBuild跳过该目标。
- 在执行或跳过目标后,运行任何在AfterTargets属性中列出它的目标。
这是您问题的答案:
如果我的目标应该在项目构建之前运行,因为项目依赖于它,那么使用后者会更好吗?
不会,因为所有CoreBuild的依赖项将在你的模板生成目标之前执行,这太晚了。
或者说,为什么AfterTargets="BeforeBuild"仍然保证在核心构建之前运行?
AfterTargets="BeforeBuild"保证你的目标将按时执行,因为它将在所有CoreBuild依赖项之前执行。
我还看到过BeforeTargets="BeforeBuild",这是放置".tt文本生成目标的更好位置吗?
- 在两种情况下,AfterTargets="BeforeBuild"或BeforeTargets="BeforeBuild",您的目标将在所有CoreBuild依赖之前执行,但在这两种情况下,您仍然有可能影响您的模板生成目标的结果,具体取决于您在BeforeBuild中需要执行的内容。如果您已经掌控了这个问题,您可以安全地使用任何一个选项。
在CoreBuild之前运行目标?
> there appear to be 2 ways of doing it.
There are more options to achieve this. Please review below.
为此目的,您应该使用特定的内置目标(BeforeBuild或AfterBuild)。这是Microsoft提供的机制,用于在使用依赖于Microsoft.Common.targets的项目时安全地扩展构建过程。
如果您只需要在CoreBuild之前运行一个目标,则可以执行以下操作:
<Target Name="BeforeBuild">
<!-- add your tasks here -->
</Target>
如果在 CoreBuild 之前有多个目标需要运行,您可以定义一个属性,其中包含所有需要按照执行顺序调用的目标:
<PropertyGroup>
<BeforeBuildDependsOn>
CustomTarget1;
CustomTarget2;
CustomTarget3
</BeforeBuildDependsOn>
</PropertyGroup>
<Target Name="BeforeBuild" DependsOnTargets="$(BeforeBuildDependsOn)"/>
更新:
根据@stijn提供的片段:
AfterTargets="BeforeBuild"会像这样插入/执行自定义目标:(依赖于BeforeBuild)
<BuildDependsOn>
BeforeBuild;
|-> Custom Target
CoreBuild;
AfterBuild
</BuildDependsOn>
BeforeTargets="CoreBuild"会在CoreBuild之前插入/执行自定义操作:
<BuildDependsOn>
BeforeBuild;
|-> Custom Target
CoreBuild;
AfterBuild
</BuildDependsOn>
“模板生成目标”将在同一位置执行(在
BeforeBuild和
CoreBuild之间,但根据不同的目标而定,因此应使用适当的目标
BeforeBuild内联或具有依赖项。
现在关于第三方问题评论, BeforeBuild / AfterBuild 目标旨在供最终用户使用,第三方提供者应该实现其脚本而不影响基本工作流程。以下是第三方应使用的一些选项,以避免破坏常规流程:
将此视为基础:
<PropertyGroup>
<BuildDependsOn>
BeforeBuild;
CoreBuild;
AfterBuild
</BuildDependsOn>
</PropertyGroup>
<Target Name="Build" DependsOnTargets="$(BuildDependsOn)"/>
选项1: 这将在BeforeBuild之前注入您的自定义第三方脚本,而不影响默认的BuildDependsOn序列,这仍然允许最终用户使用BeforeBuild目标。
<PropertyGroup>
<BuildDependsOn>
MyCustomThirdParty;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
<PropertyGroup>
<MyCustomThirdPartyDependsOn>
BeforeMyCustomThirdParty;
CustomStep1;
CustomStep2;
CustomStep1;
AfterMyCustomThirdParty
</MyCustomThirdPartyDependsOn>
</PropertyGroup>
<Target Name="MyCustomThirdParty" DependsOnTargets="$(MyCustomThirdPartyDependsOn)"/>
选项2:如果第三方脚本需要在BeforeBuild目标之后执行,可以按照以下方式进行:
<PropertyGroup>
<BuildDependsOn>
BeforeBuild;
MyCustomThirdParty;
CoreBuild;
AfterBuild
</BuildDependsOn>
</PropertyGroup>
注意:为了使其正常工作,您必须在导入Microsoft.CSharp.targets之后添加PropertyGroup和targets。
这样,您将能够使用多个第三方脚本来尊重一般的工作流程。
显然,您可以根据情况使用这些选项的组合。但是,您应该遵循以下一般规则:
1. 尊重默认工作流程(BeforeBuild,CoreBuild,AfterBuild)。
2. 为您的第三方脚本包含Before/After targets,以允许最终用户在第三方脚本执行之前或之后注入任何内容。
如果您正在使用默认的Visual Studio生成的构建脚本(如.csproj,.vbproj等项目),则应考虑这些问题。如果您正在为其他语言或目的实现自己的脚本,则可以在任何地方使用BeforeTargets和AfterTargets,但为什么不遵循基于现有脚本的良好实践呢?