版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、MSBuild的简单介绍与使用MSBuild 是 Microsoft 和 Visual Studio 的新生成系统。它不仅仅是一个构造工具,应该称之为拥有相当强大扩展能力的自动化平台。一、MSBuild简介 按照笔者现在的理解,MSBuild平台的主要涉及到三部分:执行引擎、构造工程、任务。其中最核心的就是执行引擎,它包括定义构造工程的规范,解释构造工程,执行“构造动作”;构造工程是用来描述构造任务的,大多数情况下我们使用MSBuild就是遵循规范,编写一个构造工程;MSBuild引擎执行的每一个“构造动作”就是通过任务实现的 ,任务就是MSBuild的扩展机制,通过编写新的任务就能够不断扩充
2、MSBuild的执行能力。 所以这三部分分别代表了引擎、脚本和扩展能力。1.1构造工程(脚本文件)先说说构造工程,只要通过Notepad打开任何一个VS2005(也就是支持CLR 2.0)下的C#工程(csproj)文件,就知道构造工程到底是怎么回事了。 如果说脚本,我们立刻想到的是VBScript或者JavaScript,构造工程内描述的内容,和常见的脚本语言的源文件之间还是有蛮大差距的,为什么也称之为“脚本”呢?因为笔者觉得没啥区别。脚本不就是纯文本形式保存,不经编译解释执行,可以实现一定逻辑分支的程序么? 再看构造工程,在构造工程中我们可以定义和使用变量(通过Property/Prope
3、rtyGourp/Item/ItemGroup等元素),可以使用条件分支(通过Choose/When/Otherwise等元素)、能够在运行时给变量赋值(通过执行任务,获取其返回类型参数的方式)、能够定义执行块(通过Target元素,相当于函数)、能够进行异常处理(通过OnError元素)、还可以复用已有工程定义的内容(通过Import元素)。拥有这些能力和高级语言已经相差无几了,所以笔者认为构造工程不是描述性语言,而是脚本语言。 这里还需要强调一点的是,项目级元素(Property)可以在<PropertyGroup>元素下定义,也可以在构造过程中作为外部参数传入(具体参见MSB
4、uild命令行参考)。这是一个非常有用的特性,一般编译时选择配置项(Debug或者Release)就是利用这个特性实现的。有关构造工程的编写规范可以参考MSBuild项目文件引用。1.2执行引擎接下来看执行引擎,通常我们使用下面的命令行开始执行构造:MSBuild.exe <ProjectFile>其中<ProjectFile>是前面提到的构造工程,也就是脚本文件,那么MSBuild.exe就应当是执行引擎了。没错,不过看一下源代码就会发现MSBuild.exe非常简单,其实主要做的工作就是命令行解析、构造环境的准备(如生成日志记录模块准备一些全局变量),然后就是创建类
5、的实例,然后调用其BuildProjectFile方法来完成。所以真正的构造逻辑是在中定义并且实现的。下面简单的代码就模拟了MSBuild.exe的工作。view plaincopy to clipboardprint?using System; using System.Text; namespace BuildAProjectCS class Program static void Main(string args) / Instantiate a new Engine object Engine engine = new Engine(); / Point to the path tha
6、t contains the .NET Framework 2.0 CLR and tools / Instantiate a new FileLogger to generate build log FileLogger logger = new FileLogger(); / Set the logfile parameter to indicate the log destination logger.Parameters = "logfile=C:tempbuild.log" / Register the logger with the engine engine.
7、RegisterLogger(logger); / Build a project file bool success = engine.BuildProjectFile("c:j"); /Unregister all loggers to close the log file engine.UnregisterAllLoggers(); if (success) Console.WriteLine("Build succeeded."); else Console.WriteLine ("Build faile
8、d. View C:tempbuild.log for details"); 具体的对象模型参见CLR类库参考中的命名空间和命令空间。笔者简单地分析了一下MSBuild.exe和的源代码,MSBuild的构造过程大致如下:a) 先创建一个构造请求(BuildRequest,构造请求是用来记录构造状态的数据结构),创建完毕之后将构造请求投递到请求队列中。b) 在执行模块中,从请求队列中获取请求,然后开始处理。c) 通过Project类加载构造工程,加载过程中检查是Solution、VC工程还是其它语言的工程。如果是Solution的话,生成一个临时的包装工程,逐一构造Solution中
9、包含的工程;如果是VC工程的话,也生成一个包装工程,在这个工程中直接执行VCBuild任务来执行构造。否则直接通过XmlDocument加载项目文件,解析其中的元素,识别Property、Item、Target之类元素。 d) 工程解析完毕后按照Target的顺序逐一执行。e) 在执行Target的过程中先解析是否存在依赖的Target以及OnError子句(即产生错误时需要执行的Target)。f) 先执行Target依赖的Target,然后通过TaskEngine执行本Target中的每一个任务。如果Target每一个任务都正确执行的话,那么执行下一个Target;否则执行错误处理的Tar
10、get。g) 执行Task的过程就是实例化注册为Task的类,然后调用其Execute方法。h) 所有Target执行完毕,则本次构造也执行完毕。以上仅仅为了便于理解概念进行的描述,实际的构造过程可能是考虑到多CPU以及内联编译,内部逻辑相当复杂,很多地方应用了Proxy模式。1.3任务(Task)通过对执行引擎的描述可以发现执行引擎主要是维护执行流程以及记录执行流程中各类变量(Property和Item),具体构造过程中的每一个动作,都是通过Task实现的。也就是说单靠虽然可以加载并且解析构造工程,但是无法完成构造动作。之所以MSBuild能够完成编译、链接、创建目录、复制文件等一系列工作,
11、都是因为在中实现了与之对应的一个个任务。具体请参考MSBuild任务参考以及CLR类库参考中的命名空间通过观察MSBuild自带的这些常用任务,可以发现其中分为两类:一类从ToolTask继承,这类任务基本上就是直接调用外部二进制文件执行完成某个特定的动作,例如VCBuild和Exec等;另一类直接从Task继承,是通过内部代码逻辑完成特定动作,例如Copy和MSBuild等。那些直接执行外部文件的任务虽然功能强大,但是有比较大的局限性,执行结果的反馈非常有限,通常只有ExitCode,很难获得其内部执行的更多信息,例如日志输出或者操作影响的结果。大部分情况下我们只需要一个Exec任务就能够完
12、成全部的构造动作,但是这样做的结果和我们写一个命令行的批处理文件没什么区别了。MSBuild平台和命令行批处理最大不同在于,它是一个更紧密的工作环境,任务之间通过一系列自定义的全局参数互相协同工作,比较灵活并且移植性高;同时共享日志模块统一输出执行过程中的各类信息,便于观察和分析。而批处理中各个命令之间几乎是完全孤立的,只能通过硬编码的方式进行协同,协作能力比较差。举个最简单的例子,编译三个工程,然后复制编译结果到目标目录下。如果用批处理可能会写成这个样子:“编译工程1、复制编译结果、编译工程2、复制结果、编译工程3、复制结果”。而利用MSBuild就可以简化很多工作,例如“申明需要编译的工程
13、(工程1、工程2、工程3、.)、编译需要编译的工程、复制编译结果”。顺便说一句,MSBuild这个任务比较有趣,在内部直接调用了构造引擎的方法(IBuildEngine2.BuildPrejectFilesInParallel)。这个例子又一次告诉我们这个世界上许多看似强大的东西,其实什么都没有干,只是因为他们手中掌握了有效的资源。除了基础的任务之外,任务还可以任意扩展,并且实现这种扩展非常方便。创建一个CLR 2.0以上的类库工程,编写实现了ITask接口的类,然后在构造工程中通过<UsingTask>元素注册任务就可以使用了。例如:view plaincopy to clipb
14、oardprint?.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <Target Name="PlatformVerificationTask"> <PlatformVerificationTask PlatformFamilyName="$(PlatformFamilyName)" PlatformID="$(PlatformID)" SourceAssembly="(IntermediateAssembly)"
15、 ReferencePath="(ReferencePath)" TreatWarningsAsErrors="$(TreatWarningsAsErrors)" PlatformVersion="$(TargetFrameworkVersion)"/> </Target> .0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /><Target Name="PlatformVerificationTask"> &l
16、t;PlatformVerificationTask PlatformFamilyName="$(PlatformFamilyName)" PlatformID="$(PlatformID)" SourceAssembly="(IntermediateAssembly)" ReferencePath="(ReferencePath)" TreatWarningsAsErrors="$(TreatWarningsAsErrors)" PlatformVersion="$(TargetFr
17、ameworkVersion)"/></Target>所以说MSBuild能够成为一个构造引擎,不是因为有个叫MSBuild的Exe文件,也不是因为脚本文件被称之为构造工程,而是因为与之配套的中主要实现了主要是和构造相关的任务。换句话说如果提供和测试相关的任务库的话,MSBuild也就是一个自动测试的平台。总之,MSBuild本身更趋向于一个自动化执行平台,可以根据需求编写不同的脚本文件来满足不同的应用,当现有能力无法满足时,通过编写新的任务进行扩展。不仅限于构造,自动安装、自动测试等都可以依赖这个平台来实现。二、MSBuild的简单使用由于MSBuild可以集成多
18、个工具,且任务添加方式可以为加载已有的任务也可以自己书写新的加载任务或直接使用Exec任务来执行,故本文只选取一个简单的任务进行讲解,并不做测试,详细可以在开发端的集成脚本中进行查看。2.1简单项目例子首先写一个简单的C# Console程序(你也可以把它改成VB.NET):/ HelloMSBuild.csusing System;class HelloMSBuildpublic static void Main()Console.WriteLine("Hello MSBuild!");下面我们就要写一个.csproj文件来控制整个生成过程。值得注意的是,如果在调用MSB
19、uild.exe时没有指定具体的项目文件,MSBuild引擎会在当前目录下查找一个名为*.*proj的项目文件。如果你在同一目录中写了多个这样的项目文件,那么需要手动指定MSBuild.exe的目标文件,方法是:MSBuild a.csproj否则MSBuild会提示出错,要求你手动指定目标项目文件。以下是项目文件:<!- Build.csproj -><Project DefaultTargets="Run"><Property Bin="bin" /><Property OutputAssembly=&quo
20、t;HelloMSBuild" /><Item Type="Source" Include="HelloMSBuild.cs" /><Target Name="Build"><Task Name="MakeDir"Directories="$(Bin)"Condition="!Exists('$(Bin)')" /><Task Name="Csc"Sources="(Sou
21、rce)"TargetType="exe"OutputAssembly="$(Bin)$(OutputAssembly).exe" /></Target><Target Name="Run" DependsOnTargets="Build"><Task Name="Exec"Command="$(Bin)$(OutputAssembly).exe" /></Target></Project>如果你此前
22、没有过NAnt的开发经验,那么上面这些东西肯定看起来挺吓人。这个时候最好的办法是打开那篇MSBuildFileFormat,对照上面代码查找相应的项目元素的含义。下面我对其中重要的项目元素进行一下解释。2.2 MSBuild的基本元素 Project元素这是每一个项目文件的最外层元素,它表示了一个项目的范围。如果缺少了这一元素,MSBuild会报错称Target元素无法识别或不被支持。Project元素拥有多个属性,其中最常用到的是DefaultTargets属性。我们都知道,在一个项目的生成过程中可能需要完成几项不同的任务(比如编译、单元测试、check-in到源代码控制服务器中等),其中每
23、一项任务都可以用Target来表示。对于拥有多个Target的项目,你可以通过设置Project的DefaultTargets(注意是复数)属性来指定需要运行哪(几)个Target,比如:<Project DefaultTargets=”Build” >或者: <Project DefaultTargets=”Build;Test;Run” >如果没有这个设置,MSBuild将只运行排在最前面的那个Target。2.2.2 Property元素在项目中你肯定需要经常访问一些信息,例如需要创建的路径名、最终生成的程序集名称等。这些信息你最好别hard code进项目中,除
24、非你一次写过之后永不更改。这时Property就能派上用场了。你把上面提到的那些信息以name/value的形式添加进Property,随后就可以以$(PropertyName)的形式访问。这样你就无须为了改动一个文件名称而让整个项目文件伤筋动骨了。比如上面代码中的Bin就是将要创建的路径名称,而Assembly Name则是最终要生成的程序集名称。这些属性的名称不是固定的,你完全可以按自己的习惯来进行命名。在使用时,你需要把属性名称放在”$(“和”)”对内(不包括引号),以表示这里将被替换成一个Property元素的值。另外,如果Property元素数量比较多,你还可以把它们分门别类地放在不
25、同的PropertyGroup里,以提高代码的可阅读性。这对Property本身没有任何影响。比如:<PropertyGroup><Property . /><Property . /></PropertyGroup>2.2.3 Item元素在整个项目文件中你肯定要提供一些可被引用的输入性资源(inputs)信息,比如源代码文件、引用的程序集名称、需要嵌入的图标资源等。它们应该被放在Item里,以便随时引用。语法是:<Item Type=”TheType” Include=”NameOrPath” />其中Type属性可以被看作是资源
26、的类别名称,比如对于.cs源文件,你可以把它们的Type都设置为Source,对于引用的程序集把Type都设置为Reference,这样在随后想引用这一类别的资源时只要引用这个Type就可以了,方法是(TypeName)。可千万别和Property的引用方法弄混了。既然Type是资源的类名,那么Include就是具体的资源名称了,比如在上面的示例代码中,Include引用的就是C#源代码文件的名称。你也可以用使用通配符*来扩大引用范围。比如下面这行代码就指定了当前目录下的所有C#文件都可以通过(Source)来引用:<Item Type=”Source” Include=”*.cs” /
27、>另外,你也可以通过与PropertyGroup类似的方法把相关的Item放在ItemGroup里。2.2.4 Target元素上面已经提到了,Target表示一个需要完成的虚拟的任务单元。每个Project可以包括一个或多个Target,从而完成一系列定制的任务。你需要给每个Target设置一个Name属性(同一Project下的两个Target不能拥有同样的Name)以便引用和区别。举例来说,在你的项目生成过程中可能需要完成三个阶段的任务:首先从VSS中check-out源代码,接下来编译这些代码并执行单元测试,最后把它们check-in回VSS。那么通常情况下你可以创建三个不同的T
28、arget以清晰划分三个不同的阶段:<Target Name=”CheckOut” >.</Target><Target Name=”Build” DependsOnTargets=”CheckOut”><Task Name=”Build” ./><Task Name=”UnitTest” . /></Target><Target Name=”CheckIn” DependsOnTargets=”CheckOut;Build”>.</Target>这样,你就可以非常清晰地控制整个生成过程。为了反应不
29、同Target之间的依赖关系(只有Check-in后才能编译,只有编译完成才可能Check-out),你需要设置Target的DependsOnTargets属性(注意是复数),以表示仅当这些Target执行完成之后才能执行当前的Target。当MSBuild引擎开始执行某项Target时(别忘了Project的DefaultTargets属性),会自动检测它所依赖的那些Target是否已经执行完成,从而避免因为某个生成环节缺失而导致整个生成过程发生意外。你可以通过Project的DefaultTargets属性指定MSBuild引擎从哪(几)个Target开始执行,也可以在调用MSBuild
30、.exe时使用t开关来手动指定将要运行的Target,方法如下:MSBuild /t:CheckOut这样,只有CheckOut(以及它所依赖的Target,在上文中没有)会被执行。2.2.5 Task元素这可能是整个项目文件中最重要的,因为它才是真正可执行的部分(这也是为什么我在上面说Target是虚拟的)。你可以在Target下面放置多个Task来顺序地执行相应的任务,比如我在上面示例代码中就在两个不同的Target中安排了MakeDir、Csc和Exec三个不同的Task。这些Task通过Name属性来相互区分,并各自拥有不同的其它属性来完成不同的任务,比如Csc有Sources(源代码
31、文件)、TargetType(目标类型)、OutputAssembly(生成程序集名称)等属性,而MakeDir则只需设置Directories(需要创建的路径名称列表)即可。也许你会奇怪这些Task的名称和属性从哪里来。好吧,请用文本编译器打开文件,看到了吗?默认情况下里面应该是这样的(不同的版本可能会有细微差别):<!- This file lists all the tasks that ship by default with MSBuild -><DefaultTasks></DefaultTasks>你会注意到,在DefaultTasks元素下面
32、排列的全是UsingTask,其中指明每一个Task的TaskName(名称)和AssemblyName(程序集)。比如说第一个UsingTask就对应着我们上面用过的Csc任务,它的完整名称(namespace+class)是,位于MSBuildTasks.dll程序集中(请在同一目录下确认这一.dll文件的存在)。这样,MSBuild引擎在遇到对Csc任务的调用时就会通过这里的注册信息来确定Csc所在的程序集,从而最终运行相应的托管代码。这样,如果你自己也写了不同的Task,请按同样的方式对它进行注册以便使用。如果你引用了一个还没有注册的Target,那么MSBuild引擎将无法找到它的存在而导致生成失败。当然,MSBuild Task的注册方式不止以上一种。以上注册方法的影响范围是全局,你可以在每一个Project里应用上面注册的那些Task。但你也可以选择在Project范围内注册Task,这将对应着另外一种略有不同的方法。我会在后面的一篇文章里给出具体介绍。在这里,你
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 《讲行业分析》课件
- 《西外·麻醉讲义》课件
- 《相电路教学》课件
- 《蛋白质双向电泳》课件
- 《药理学利尿药》课件
- 《种快乐的方法》课件
- 2026中化集团技术类储能方向招聘笔试历年参考题库附带答案详解
- 2026年禽病防治考试题库及答案
- 2026注册验船师考试(C级船舶检验专业综合能力)模拟题及答案二
- 2026年企业网络安全管理培训考试题库附答案(网络安全专题)
- AQ3067-2026重大事故隐患判定准则专项培训考核试卷-答案卷
- 2026-2027学年小学五年级上册数学全册教案(教学设计)人教版
- (零模)南京市2027届高三年级学情调研语文试卷(含答案)
- 2026事业单位笔试-云南-云南财务(医疗招聘)历年参考题库含答案详解
- 《计算政治学概论》课件 第1-8章 计算政治学的起源与发展-数字社会治理
- 2025湖南长沙矿山研究院发布校招招聘52人笔试历年典型考点题库附带答案详解
- T∕CCEAS008-2026 建设工程造价咨询成果文件质量标准
- 自密实混凝土施工方法及浇筑管控要点
- (正式版)DB34∕T 4541-2023 《废弃露天采坑一般工业固废处置与生态修复技术规范》
- 2026年湖北省检察官、法官入员额考试真题(附答案)
- 常见ABO疑难血型案例分析
评论
0/150
提交评论