如果您有兴趣,在我的MSBuild Book 中有一节介绍如何在 MSBuild 中创建可重用元素。不过,我也会在这里给出一些 cmets。此内容与书中的内容不同。
在创建 MSBuild 文件时,您应该小心区分 what 与 how。为了稍微解释一下,让我们看看托管 VS 项目是如何开箱即用的(这是可重用元素的绝佳模型)。
当您创建 C#/VB 项目时,您会获得一个 .csproj 文件,该 .csproj 文件主要包含属性和项。您不会在该文件中找到单个目标。这些文件包含将要构建的什么(以及与构建相关的一些设置)。在项目文件的底部,您将找到一个导入语句。此导入引入了如何构建项目。
导入的文件包括:
- Microsoft.CSharp/VisualBasic/FSharp.targets
- Microsoft.common.targets
在这种情况下,Microsoft.common.targets 定义了所有托管语言的整体构建过程。然后 Microsoft.CSharp.targets(或其他特定语言的 .targets 文件之一)填补了如何调用特定语言特定工具的空白。
DependsOnTargets 与 Before/AfterTargets
在您上面的回答中,您声明“我建议避免使用 DependsOnTargets,除非确实有必要,例如两个”。我不同意这一点。这是我对 DependsOnTargets 与 Before/AfterTargets 的看法。
在
时使用 DependsOnTargets
- 当您尝试创建要执行的目标工作流时
- 如果没有其他目标首先执行,目标将无法运行
- 当您需要根据所需操作在特定步骤注入不同目标时
在
时使用Before/AfterTargets
- 当您不拥有目标所在的文件并且它没有可以扩展的 DependsOnTargets 属性时
- 无论何时执行,您都希望目标在特定目标之前/之后执行
要稍微梳理一下差异,请考虑 Web 项目。对于 Web 项目,.csproj/.vbproj 负责两个工作流程:
- 构建
- 发布
如果我想在构建目标之前将目标添加到要执行的目标列表中,我可以仅为发布场景动态更新 BuildDependsOn 属性。您不能使用 Before/AfterTargets 执行此操作。
在理想的世界中,每个目标都有以下 DependsOnTargets。
- 所有目标都有一个由属性提供的 DependsOnTargets 属性
- 每个 DependsOnTargets 始终将现有值添加到属性定义中
例如
<MyTargetDependsOn>
$(MyTargetDependsOn);
Target1;
Target2
</MyTargetDependsOn>
不幸的是,许多目标不遵循这种模式,因此 DependsOnTargets 在很多情况下都被淘汰了。
当我创作 MSBuild 脚本时我总是使用 DependsOnTargets,除非我有充分的理由选择使用 Before/AfterTargets。我觉得(我不了解设计的真正原因,因为我当时不在 Microsoft )Before/AfterTargets 确实是为了允许用户注入要在之前/之前执行的目标而创建的。在他们不拥有的目标之后,并且创建者没有使用上述模式。