我应该如何构造MSBuild脚本

我应该如何构造MSBuild脚本,msbuild,Msbuild,最近,我开始学习MSBuild,以便为本地构建和服务器构建(CI、夜间构建和每周构建)灵活构建脚本。根据我的经验,我知道构建脚本可能非常笨拙。即使在我的公司,在一些指导下,了解所有目标以及它们如何协同工作也是一件痛苦的事情。当然,这是一个长期的过程:你需要一些东西,你没有足够的时间,你开始变得懒惰和混乱。但我问自己,我如何构造一个MSBuild脚本以使其易于扩展和可读?尤其是目标之间的三种关系依赖于目标、目标前、目标后,这三种关系对射中我自己的脚非常有用。好吧,正如我已经说过的,我有自己的经验:

最近,我开始学习MSBuild,以便为本地构建和服务器构建(CI、夜间构建和每周构建)灵活构建脚本。根据我的经验,我知道构建脚本可能非常笨拙。即使在我的公司,在一些指导下,了解所有目标以及它们如何协同工作也是一件痛苦的事情。当然,这是一个长期的过程:你需要一些东西,你没有足够的时间,你开始变得懒惰和混乱。但我问自己,我如何构造一个MSBuild脚本以使其易于扩展和可读?尤其是目标之间的三种关系依赖于目标、目标前、目标后,这三种关系对射中我自己的脚非常有用。

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

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

    如果您感兴趣,我在我的中有一节介绍如何在MSBuild中创建可重用元素。不过,我在这里也会给出一些评论。这个内容与这本书的内容不同

    创建MSBuild文件时,应注意将内容与方式区分开来。为了解释这一点,让我们检查一下托管VS项目是如何开箱即用的(这是可重用元素的一个很好的模型)

    创建C#/VB项目时,会得到一个.csproj文件,该.csproj文件主要包含属性和项。在该文件中找不到单个目标。这些文件包含将生成的内容(以及与生成相关的一些设置)。在项目文件的底部,您将找到一条导入语句。此导入引入了项目的构建方式

    导入的文件包括:

    • Microsoft.CSharp/VisualBasic/FSharp.targets
    • Microsoft.common.targets
    在本例中,Microsoft.common.targets定义了所有托管语言的总体生成过程。然后,Microsoft.CSharp.targets(或另一个特定于lang的.targets文件)填补了如何调用特定于语言的工具的空白

    依赖于目标与之前/之后的目标 在上面的回答中,您指出“我建议避免依赖目标,除非确实有必要,例如两个目标”。我不同意这一点。这是我对依赖目标与之前/之后目标的对比

    • 当您尝试创建要执行的目标工作流时
    • 当一个目标在没有其他目标先执行的情况下无法运行时
    • 当您需要根据所需操作在特定步骤注入不同的目标时

    • 如果您不拥有目标所在的文件,并且该文件没有可扩展的DependsOnTargets属性
    • 您希望目标在特定目标之前/之后执行,无论何时执行
    <> P>为了区分差异,有点考虑Web项目。对于web项目,.csproj/.vbproj负责两个工作流:

  • 建造
  • 发表
  • 如果我想在生成目标之前将目标添加到要执行的目标列表中,我可以仅为发布场景动态更新BuildDependsOn属性。您不能对前/后目标执行此操作

    在理想情况下,每个目标将具有以下wrt DependsOnTargets

    • 所有目标都有DependsOnTargets属性,该属性由属性馈送
    • 每个DependsOnTargets始终将现有值前置到特性定义中
    比如说

    <MyTargetDependsOn>
        $(MyTargetDependsOn);
        Target1;
        Target2
    </MyTargetDependsOn>
    
    
    美元(MyTargetDependsOn);
    Target1;
    目标2
    
    不幸的是,许多目标没有遵循这种模式