我该如何构建我的MSBuild脚本结构

3

最近,我开始学习MSBuild,以便为本地和服务器构建(CI,每夜构建,每周构建)创建灵活的构建脚本。基于我的经验,我知道构建脚本可能非常尴尬。即使在我的公司有一些指导,也很难了解所有目标及其如何相互配合。当然,这是一个长期的过程:你需要某些东西,但没有足够的时间,你开始变得懒惰和混乱。但我问自己,如何构建一个易于扩展和可读性高的MSBuild脚本呢?特别是目标之间的三种关系DependsOnTargets、BeforeTargets和AfterTargets非常容易让人掉进陷阱。

1个回答

7

在我的MSBuild Book中,有一个基于如何在MSBuild中创建可重用元素的部分,如果您感兴趣的话。不过我也会在这里提供一些评论,这个内容与书中的不同。

创建MSBuild文件时,应该注意隔离what (什么)和how (如何)。为了解释一下,让我们来看看默认情况下托管VS项目的工作方式(这是可重用元素的一个很好的模型)。

当你创建一个C#/VB项目时,你会得到一个.csproj文件,这个.csproj文件主要包含属性和项。在那个文件中,你找不到一个目标。这些文件包含what将被构建(以及与构建相关的一些设置)。在项目文件的底部,你会发现一个导入语句。这个导入语句引入了How项目被构建。

被导入的文件包括:

  • 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 处理两个工作流程:

  1. 构建
  2. 发布

如果我想要将目标添加到Build目标之前要执行的目标列表中,我可以动态更新BuildDependsOn属性,仅适用于发布场景。你不能使用Before/AfterTargets来做到这一点。

在理想情况下,每个目标都应该具有DependsOnTargets方面的以下特征:

  • 所有目标都有一个由属性提供的DependsOnTargets属性
  • 每个DependsOnTargets始终将现有值预置到属性定义中

例如:

<MyTargetDependsOn>
    $(MyTargetDependsOn);
    Target1;
    Target2
</MyTargetDependsOn>

不幸的是,许多目标并未遵循这种模式,因此在许多情况下,DependsOnTargets无法使用。

当我编写MSBuild脚本时,我总是使用DependsOnTargets,除非我有充分的理由选择使用Before/AfterTargets。我觉得(我对设计的真正原因没有深入了解,因为我当时不在微软)Before/AfterTargets的确是为了让用户可以在不拥有某个目标的情况下插入要执行的目标而创建的,而创建者没有使用上述模式。


嗨Sayed,我刚刚在浏览Microsoft.Common.targets文件时想到了通过属性定义依赖关系的想法。对我来说,为了获得4.0现在提供的内容,这种方法非常冗长和hacky。我同意它更加明确,对于像描述的那样的困难工作流程,你应该始终使用它,即使在4.0中也是如此!也许我没有表达清楚,但问题在于LOCAL与SERVER构建中有一些目标必须流入预定义的工作流程中。也许我会尝试属性方法,但我非常怀疑。 - Matthias
我看到你刚刚写了一篇关于这个的博客 :) 如果你有兴趣,我想展示给你一个小样本,其中我遵循了自己定义的规则 :) 顺便说一句,我认为在某种程度上我们对构建脚本的结构化有共同的理解,特别是 what vs. how 这一部分。 - Matthias
顺便提一下,Mike Fourie(你可能认识他)在他的文章中也认为BeforeTargetsAfterTargets可以实现更多可重用的目标。文章链接 - Matthias
嗨@Matthias,是的我认识Mike,他是个不错的人。我读了他的帖子,感觉他并没有强烈倡导Before/AfterTargets而是更偏向于DependsOnTargets,但谁知道呢。如果你想把你的示例发布为gist,我会看一下的。 - Sayed Ibrahim Hashimi
我可以在从未显式调用的目标上使用 AfterTargets="Build" DependsOnTargets="Build" 吗?但是这些目标仍然需要在 Build 之后运行(但不是在 Clean 之后)? - Steven Liekens

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