MSBuild 是 Microsoft 和 Visual Studio的生成系统。它不仅仅是一个构造工具,应该称之为拥有相当强大扩展能力的自动化平台。MSBuild平台的主要涉及到三部分:执行引擎、构造工程、任务。其中最核心的就是执行引擎,它包括定义构造工程的规范,解释构造工程,执行“构造动作”;构造工程是用来描述构造任务的,大多数情况下我们使用MSBuild就是遵循规范,编写一个构造工程;MSBuild引擎执行的每一个“构造动作”就是通过任务实现的,任务就是MSBuild的扩展机制,通过编写新的任务就能够不断扩充MSBuild的执行能力。所以这三部分分别代表了引擎、脚本和扩展能力。

构造工程(脚本文件)
先说说构造工程,只要通过Notepad打开任何一个Visual Studio下的C#工程(csproj)文件,就知道构造工程到底是怎么回事了。

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Root>$(MSBuildStartupDirectory)</Root>
</PropertyGroup>
<Target Name="Build">
<!-- Compile -->
<ItemGroup>
<ProjectToBuild Include="$(Root)\..\src\Foundation\Common\Gimela.Common.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\Infrastructure\Gimela.Infrastructure.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\Management\Gimela.Management.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\Security\Gimela.Security.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\Tasks\Gimela.Tasks.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\Text\Gimela.Text.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\Net\Gimela.Net.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\ServiceModel\Gimela.ServiceModel.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\Data\Gimela.Data.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\Presentation\Gimela.Presentation.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\Media\Gimela.Media.sln" />
<ProjectToBuild Include="$(Root)\..\src\Foundation\Streaming\Gimela.Streaming.sln" />
<ProjectToBuild Include="$(Root)\..\src\Crust\Gimela.Crust.sln" />
</ItemGroup>
<MSBuild Projects="@(ProjectToBuild)" Targets="Build" Properties="Configuration=Debug;">
<Output TaskParameter="TargetOutputs" ItemName="AssembliesBuiltByChildProjects" />
</MSBuild> </Target>
</Project>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

在构造工程中我们可以定义和使用变量(通过Property/PropertyGourp/Item/ItemGroup等元素),可以使用条件分支(通过Choose/When/Otherwise等元素)、能够在运行时给变量赋值(通过执行任务,获取其返回类型参数的方式)、能够定义执行块(通过Target元素,相当于函数)、能够进行异常处理(通过OnError元素)、还可以复用已有工程定义的内容(通过Import元素)。拥有这些能力和高级语言已经相差无几了,所以笔者认为构造工程不是描述性语言,而是脚本语言。

这里还需要强调一点的是,项目级元素(Property)可以在元素下定义,也可以在构造过程中作为外部参数传入,这是一个非常有用的特性,一般编译时选择配置项(Debug或者Release)就是利用这个特性实现的。

Project元素

这是每一个项目文件的最外层元素,它表示了一个项目的范围。如果缺少了这一元素,MSBuild会报错称Target元素无法识别或不被支持。

Project元素拥有多个属性,其中最常用到的是DefaultTargets属性。我们都知道,在一个项目的生成过程中可能需要完成几项不同的任务(比如编译、单元测试、check-in到源代码控制服务器中等),其中每一项任务都可以用Target来表示。对于拥有多个Target的项目,你可以通过设置Project的DefaultTargets(注意是复数)属性来指定需要运行哪(几)个Target,如果没有这个设置,MSBuild将只运行排在最前面的那个Target。

Property元素

在项目中你肯定需要经常访问一些信息,例如需要创建的路径名、最终生成的程序集名称等。以name/value的形式添加进Property,随后就可以以$(PropertyName)的形式访问。这样你就无须为了改动一个文件名称而让整个项目文件伤筋动骨了。比如上面代码中的Bin就是将要创建的路径名称,而AssemblyName则是最终要生成的程序集名称。这些属性的名称不是固定的,你完全可以按自己的习惯来进行命名。在使用时,你需要把属性名称放在”$(“和”)”对内(不包括引号),以表示这里将被替换成一个Property元素的值。

另外,如果Property元素数量比较多,你还可以把它们分门别类地放在不同的PropertyGroup里,以提高代码的可阅读性。这对Property本身没有任何影响。

 <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{6C2561FB-4405-408F-B41B-ACE5E519A26E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Gimela.Infrastructure.Patterns</RootNamespace>
<AssemblyName>Gimela.Infrastructure.Patterns</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>

Item元素

在整个项目文件中你肯定要提供一些可被引用的输入性资源(inputs)信息,比如源代码文件、引用的程序集名称、需要嵌入的图标资源等。它们应该被放在Item里,以便随时引用。语法是:<Item Type=”TheType”Include=”NameOrPath” />

其中Type属性可以被看作是资源的类别名称,比如对于.cs源文件,你可以把它们的Type都设置为Source,对于引用的程序集把Type都设置为Reference,这样在随后想引用这一类别的资源时只要引用这个Type就可以了,方法是@(TypeName)。可千万别和Property的引用方法弄混了。

既然Type是资源的类名,那么Include就是具体的资源名称了,比如在上面的示例代码中,Include引用的就是C#源代码文件的名称。你也可以用使用通配符*来扩大引用范围。比如下面这行代码就指定了当前目录下的所有C#文件都可以通过@(Source)来引用:

<Item Type=”Source” Include=”*.cs” />

另外,你也可以通过与PropertyGroup类似的方法把相关的Item放在ItemGroup里。

  <ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Commands\CommandBase.cs" />
<Compile Include="Commands\DuplexCommandBase.cs" />
<Compile Include="Commands\ICommand.cs" />
<Compile Include="Commands\IDuplexCommand.cs" />
<Compile Include="Extensions\BitConverterExtensions.cs" />
<Compile Include="Extensions\ConcurrentDictionaryExtensions.cs" />
<Compile Include="Extensions\StopwatchExtensions.cs" />
<Compile Include="Extensions\TimeSpanExtensions.cs" />
<Compile Include="Flyweight\FlyweightObjectPool.cs" />
<Compile Include="Singleton\StaticSingleton.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SmartQueue\ISmartQueueMapper.cs" />
<Compile Include="SmartQueue\SmartQueue.cs" />
<Compile Include="SmartQueue\SmartQueueBase.cs" />
<Compile Include="SmartQueue\SmartQueueMapper.cs" />
<Compile Include="UnitOfWork\IUnitOfWork.cs" />
<Compile Include="UnitOfWork\IUnitOfWorkFactory.cs" />
<Compile Include="UnitOfWork\UnitOfWork.cs" />
<Compile Include="WeakActions\IWeakActionExecuteWithObject.cs" />
<Compile Include="WeakActions\WeakAction.cs" />
<Compile Include="WeakActions\WeakActionGeneric.cs" />
<Compile Include="WeakFuncs\IWeakFuncExecuteWithObjectAndResult.cs" />
<Compile Include="WeakFuncs\WeakFunc.cs" />
<Compile Include="WeakFuncs\WeakFuncGeneric.cs" />
</ItemGroup>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Target元素

Target表示一个需要完成的虚拟的任务单元。每个Project可以包括一个或多个Target,从而完成一系列定制的任务。你需要给每个Target设置一个Name属性(同一Project下的两个Target不能拥有同样的Name)以便引用和区别。

举例来说,在你的项目生成过程中可能需要完成三个阶段的任务:首先check-out源代码,接下来编译这些代码并执行单元测试,最后把它们check-in。那么通常情况下你可以创建三个不同的Target以清晰划分三个不同的阶段:

<Target Name=”CheckOut” ></Target>

<Target Name=”Build”  DependsOnTargets=”CheckOut”> <Task Name=”Build”

.../> <Task Name=”UnitTest” ... />

</Target>

<Target Name=”CheckIn” DependsOnTargets=”CheckOut;Build”> 

</Target>

这样,你就可以非常清晰地控制整个生成过程。为了反应不同Target之间的依赖关系(只有Check-in后才能编译,只有编译完成才可能Check-out……),你需要设置Target的DependsOnTargets属性(注意是复数),以表示仅当这些Target执行完成之后才能执行当前的Target。当MSBuild引擎开始执行某项Target时(别忘了Project的DefaultTargets属性),会自动检测它所依赖的那些Target是否已经执行完成,从而避免因为某个生成环节缺失而导致整个生成过程发生意外。

你可以通过Project的DefaultTargets属性指定MSBuild引擎从哪(几)个Target开始执行,也可以在调用MSBuild.exe时使用t开关来手动指定将要运行的Target,方法如下:

MSBuild /t:CheckOut 这样,只有CheckOut(以及它所依赖的Target,在上文中没有)会被执行。

Task元素

这可能是整个项目文件中最重要的,因为它才是真正可执行的部分(这也是为什么我在上面说Target是虚拟的)。你可以在Target下面放置多个Task来顺序地执行相应的任务。

 

相关文档

MSBuild的简单介绍与使用的更多相关文章

  1. [原创]关于mybatis中一级缓存和二级缓存的简单介绍

    关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...

  2. 利用Python进行数据分析(7) pandas基础: Series和DataFrame的简单介绍

    一.pandas 是什么 pandas 是基于 NumPy 的一个 Python 数据分析包,主要目的是为了数据分析.它提供了大量高级的数据结构和对数据处理的方法. pandas 有两个主要的数据结构 ...

  3. 利用Python进行数据分析(4) NumPy基础: ndarray简单介绍

    一.NumPy 是什么 NumPy 是 Python 科学计算的基础包,它专为进行严格的数字处理而产生.在之前的随笔里已有更加详细的介绍,这里不再赘述. 利用 Python 进行数据分析(一)简单介绍 ...

  4. yii2的权限管理系统RBAC简单介绍

    这里有几个概念 权限: 指用户是否可以执行哪些操作,如:编辑.发布.查看回帖 角色 比如:VIP用户组, 高级会员组,中级会员组,初级会员组 VIP用户组:发帖.回帖.删帖.浏览权限 高级会员组:发帖 ...

  5. angular1.x的简单介绍(二)

    首先还是要强调一下DI,DI(Denpendency Injection)伸手获得,主要解决模块间的耦合关系.那么模块是又什么组成的呢?在我看来,模块的最小单位是类,多个类的组合就是模块.关于在根模块 ...

  6. Linux的简单介绍和常用命令的介绍

    Linux的简单介绍和常用命令的介绍 本说明以Ubuntu系统为例 Ubuntu系统的安装自行百度,或者参考http://www.cnblogs.com/CoderJYF/p/6091068.html ...

  7. iOS-iOS开发简单介绍

    概览 终于到了真正接触IOS应用程序的时刻了,之前我们花了很多时间去讨论C语言.ObjC等知识,对于很多朋友而言开发IOS第一天就想直接看到成果,看到可以运行的IOS程序.但是这里我想强调一下,前面的 ...

  8. iOS开发多线程篇—多线程简单介绍

    iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcod ...

  9. iOS开发UI篇—UITabBarController简单介绍

    iOS开发UI篇—UITabBarController简单介绍 一.简单介绍 UITabBarController和UINavigationController类似,UITabBarControlle ...

随机推荐

  1. 实现移动设备远程登录linux服务器

    明天下午要考试了.所以最近时间有点紧,都在忙着看矩阵课本,刷刷题. 回到我们博客题目内容,最近正在看linux,之前是通过在笔记本上装着虚拟机的方法来进行操作. 之后发现一些能够进一步改进的地方,首先 ...

  2. 剑指Offer-【面试题04:替换空格】

    package com.cxz.question4; /* * 请实现一个函数,把字符串中的每个空格替换成"%20",例如"We are happy.",则输出 ...

  3. C++ 系列:多线程资源收集

    Copyright © 1900-2016, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ 欢迎转载,请保留此版权声明. -- ...

  4. Js(DOM) 和Jq 对象的相互转换

    JQuery 对象不能使用DOM对象中的方法,同样,Dom对象 不能使用JQuery 中的方法,但有时候 ,我们不得不使用JQuery的方法或者 Dom对象的方法,该怎么办呢? 下面介绍一下 jq对象 ...

  5. 【原创】内核ShellCode注入的一种方法

    标 题: [原创]内核ShellCode注入的一种方法 作 者: organic 时 间: 2013-05-04,04:34:08 链 接: http://bbs.pediy.com/showthre ...

  6. IDEA快捷键+使用小技巧

    一 常用快捷键 Alt+回车 导入包,自动修正,当引入的类需要异常捕获的时候 Ctrl+Shift+Space 自动补全代码,"new"字符,还可以引入强制转换的 Ctrl-Alt ...

  7. ffmpeg 内存读写相关

    需要的解码的视频数据在一段内存中.例如,通过其他系统送来的视频数据.同样,有的时候编码后的视频数据也未必要保存成一个文件.例如,要求将编码后的视频数据送给其他的系统进行下一步的处理.以上两种情况就要求 ...

  8. selenium使用笔记(一)

    有时候在交流群里经常会看到这样的问题,selenium能进行性能测试吗?selenium1和selenium2有什么区别等等问题,在这里谈一下自己学习和工作以后对selenium的认识.我所记录的东西 ...

  9. OSG消息机制之消息分析

    OSG消息接收在头文件有各种事件的相关参数

  10. mac apache 2.4的配置

    开启vhost 文件 命令行输入 vim /etc/apache2/httpd.conf 找到把前边的# include /private/etc/apache2/extra/httpd-vhost. ...