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

时间:2013-02-07 22:22:05

标签: msbuild

最近,我开始学习MSBuild,以便为本地和服务器构建(CI,Nightly,Weekly)灵活构建脚本。根据我的经验,我知道构建脚本可能非常尴尬。即使在我公司的某些指导下,了解所有目标以及它们如何协同工作也是一件痛苦的事。当然,这是一个长期的过程:你需要一些东西,你没有足够的时间,你开始变得懒散和凌乱。但我问自己,我怎么能构建一个MSBuild脚本以便于扩展和可读性?特别是目标 DependsOnTargets,BeforeTargets,AfterTargets 之间的三种关系对于射击自己很有用。

2 个答案:

答案 0 :(得分:7)

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

创建MSBuild文件时,应小心隔离 。为了解释这一点,让我们来看看托管VS项目如何开箱即用(这是一个可重用元素的伟大模型)。

当你创建一个C#/ VB项目时,你会得到一个.csproj文件,这个.csproj文件主要包含Properties和Items。您将无法在该文件中找到单个目标。这些文件包含构建(以及与构建相关的一些设置)。在项目文件的底部,您将找到一个import语句。此导入带来如何项目的构建。

导入的文件包括:

  • 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项目,.csproj / .vbproj有两个工作流程:

  1. 构建
  2. 发布
  3. 如果我想在Build目标之前将目标添加到要执行的目标列表中,我可以仅为发布方案动态更新BuildDependsOn属性。你不能用Before / AfterTargets做到这一点。

    在理想世界中,每个目标都有以下wrt DependsOnTargets。

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

    例如

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

    不幸的是,很多目标并没有遵循这种模式,所以DependsOnTargets在很多情况下已经死了。

    当我创作MSBuild脚本时我总是使用DependsOnTargets,除非有充分理由说明我应该选择使用Before / AfterTargets 。我觉得(我对设计的真正原因没有任何见解,因为我当时没有与微软合作)真正创建了Before / AfterTargets以允许用户注入要在/之前执行的目标在他们没有拥有的目标之后,创作者没有使用上面的模式。

答案 1 :(得分:0)

好吧,正如我已经说过的,我有自己的经历:)

  1. 每个目标进入单个文件,就像在面向对象的编程中一样:)同样常见的属性和项目组应保留在自己的文件中(例如, Projects.conf 包含要构建的所有项目; Environment.conf 包含工具和扩展包的所有路径)。正如您将看到的,这对于不同的构建集(如本地和服务器构建)非常方便。
  2. 定义所需的所有路径,文件和属性。不要遵循DRY原则。这很难,但根据我的经验,很难根据已定义的值构建新值。因此,如果您的项目包含 .csproj .nuspec 文件,请不要明确声明它们。
  3. 声明初始目标。说明如下。
  4. 声明在构建过程中必须处理的一些主要目标,例如清理,构建,测试,打包,部署,存档等。使它们相互依赖( DependsOnTargets )。例如,测试取决于 Build 目标。它们都应该取决于 Init 目标。
  5. 完整性检查是规则1的例外。它们属于需要它们的同一文件。例如, PackageCheck 目标将监视 .nuspec 文件是否存在,并且还将 Init 声明为 AfterTargets 。这允许快速失败构建。
  6. 所有其他目标将使用 BeforeTargets,AfterTargets 进行排序。我建议避免使用 DependsOnTargets ,除非确实有必要,例如,如果必须在 Build 之前处理两个目标,并且彼此之间也有订单。
  7. 在服务器和本地构建脚本中,只需导入您需要的所有内容以及公共API应该是什么。正如我所说,每个目标都进入一个文件(1)。现在,如果您有 UpdateAssemblyVersion 目标,则应在 AfterTargets (5)中声明 Build 。您只需添加/删除导入即可激活/停用该目标。
  8. 使用MSBuildExtensionPack 。他们真的很有帮助!但也不要害怕编写自己的任务
  9. 所以这些是我的规则。我将不胜感激任何意见或补充!