更新 2
基于documentation from Microsoft:
这是目标构建顺序
- InitialTargets 目标已运行。
- 由 /target 开关在命令行上指定的目标运行。如果您在命令行上未指定任何目标,则运行 DefaultTargets 目标。如果两者都不存在,则运行遇到的第一个目标。
- 评估目标的条件属性。如果 Condition 属性存在且计算结果为 false,则不会执行目标,并且不会对构建产生进一步影响。
- 在执行目标之前,会运行其 DependsOnTargets 目标。
- 在执行目标之前,将运行在 BeforeTargets 属性中列出它的任何目标。
- 在执行目标之前,会比较其输入属性和输出属性。如果 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.Common.targets的项目时提供给safely extend the build process的机制
如果您在 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之间,但是根据不同的目标,这就是为什么要选择合适的目标used 应该是 BeforeBuild 内联或带有依赖项。
现在关于第 3 方问题评论,BeforeBuild/AfterBuild 目标适用于最终用户,第三方提供商应在不影响基本工作流程的情况下实施其脚本。这些是第 3 方应使用的一些选项以避免破坏常规流程:
以此为基础:
<PropertyGroup>
<BuildDependsOn>
BeforeBuild;
CoreBuild;
AfterBuild
</BuildDependsOn>
</PropertyGroup>
<Target Name="Build" DependsOnTargets="$(BuildDependsOn)"/>
选项 1:这将在 BeforeBuild 之前注入您的自定义 3rd 方脚本,而不影响默认的 BuildDependsOn 序列,这仍然允许最终用户在没有的情况下使用 BeforeBuild 目标。
<PropertyGroup>
<BuildDependsOn>
MyCustomThirdParty;
$(BuildDependsOn);
</BuildDependsOn>
</PropertyGroup>
<PropertyGroup>
<MyCustomThirdPartyDependsOn>
BeforeMyCustomThirdParty;
CustomStep1;
CustomStep2;
CustomStep1;
AfterMyCustomThirdParty
</MyCustomThirdPartyDependsOn>
</PropertyGroup>
<Target Name="MyCustomThirdParty" DependsOnTargets="$(MyCustomThirdPartyDependsOn)"/>
选项2:如果需要在BeforeBuild目标之后执行第3方脚本,可以这样做:
<PropertyGroup>
<BuildDependsOn>
BeforeBuild;
MyCustomThirdParty;
CoreBuild;
AfterBuild
</BuildDependsOn>
</PropertyGroup>
注意:为了使其正常工作,您必须在 Microsoft.CSharp.targets 导入之后添加 PropertyGroup 和目标。
这样您就可以使用多个符合一般工作流程的第 3 方脚本。
您显然可以根据情况使用这些选项的组合。但是您应该遵循以下一般规则:
- 尊重默认工作流程(BeforeBuild、CoreBuild、AfterBuild)。
- 为您的 3rd 方脚本包括 Before/After 目标,以允许最终用户在 3rd 方脚本执行之前或之后注入任何内容。
当您使用默认的 Visual Studio 生成的构建脚本(如 .csproj、.vbproj 等项目)时,应考虑这些。如果您正在为其他语言或目的实现自己的脚本,您可以在任何需要的地方使用 BeforeTargets 和 AfterTargets,但为什么不遵循基于现有脚本的良好实践呢?