天天看点

msbuildMSBuild是什么?为何去了解MSBuild我想从MSBuild中得到什么MSBuild基本概念MSBuild属性MSBuild项MSBuild任务MSBuild目标MSBuild的简单介绍与使用

http://www.cnblogs.com/l_nh/archive/2012/08/30/2662648.html

MSBuild是什么?

MSBuild全称(Microsoft Build Engine),是用来生成.NET程序的平台。您可能不知道它,但是如果您在使用VS做开发,那么一定时时刻刻在使用它。因为是它在背后为你管理生成你的项目文件。当新建一个项目时,注意下项目文件夹中的*.*proj文件就是为MSBuild提供的,这是个文本文件,基于XML格式,里面包含有项目所包含的文件,生成配置,输出配置等信息。当把一个文件或者图片等添加到项目中,就会在这里添加一个描述,反之则删除一个描述信息;在项目属性页所做的配置也会在这里存储。

为何去了解MSBuild

想去了解这个源于以前学WPF时的疑惑(当时就想从MSBuild下手了,一直没精力,拖到现在),因为不知道XAML为何就跑到生成的程序集,以及这个XAML标记最后变成什么,WPF是如何处理这些XAML标签与C#代码的?一般写代码时我都会清楚的知道这个代码最后经由编译器变成了什么,这样心里比较底。但是这个XAML,是看不透,看不透就心里堵得慌,不踏实,我比较喜欢刨根问底,所以就想到通过这个入口探个究竟。

我想从MSBuild中得到什么

第一解决我上面说疑惑;

第二理解项目中这些文件是如何组织在一起并生成最终程序的(就像在WPF上Build是生成出来exe,而WP7则是出来一个XAP包,为何?);

第三了解到为止,以看懂理解为目的,不做深入研究。

MSBuild基本概念

MSBuild有四个基本块(属性、项、任务、目标):

MSBuild属性:   属性是一些键/值对,主要用来存储一些配置信息。

MSBuild   项:   主要是存储一些项目文件信息,以及文件的元数据信息(如版本号)。

MSBuild任务:   Build过程中的一些原子操作(如CSC、MakeDir)

MSBuild目标:   按特定的顺序将任务组织在一起,并允许在命令行单独指定各个部分。

一句话总结MSBuild的作用:利用配置信息对项目文件实施特定顺序的操作。

MSBuild属性

属性声明方式:

 1 <?xml version="1.0" encoding="utf-8"?>      
2 <!--根元素,表示一个项目-->      
3 <!--DefaultTargets用于定默认执行的目标-->      
4 <Project DefaultTargets="build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">      
5   <!--属性都要包含在PropertyGroup元素内部-->      
6   <PropertyGroup>      
7     <!--声明一个"linianhui"属性,其值为"hello world"-->      
8     <linianhui>hello world</linianhui>      
9   </PropertyGroup>      
10   <!--目标-->      
11   <Target Name="build">      
12     <!--MSBuild提供的一个内置任务,用于生成记录信息用$(属性名)来引用属性的值-->      
13     <Message Text="$(linianhui)"></Message>      
14   </Target>      
15 </Project>      

保存此文件到d:\helloworld.xml文件。打开CMD窗口,输入MSBuild helloworld.xml:

打印出“linianhui”属性的值。MSBuild提供一些保留属性,可以方便的引用$,如$(MSBuildProjectFile)将返回项目文件的完整名(helloworld.xml)。其他的保留属性可以查阅MSDN帮助文档。

MSBuild项

 项声明方式:

<?xml version="1.0" encoding="utf-8"?>      
<Project DefaultTargets="build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">      
  <!--项都要包含在ItemGroup元素内部-->      
  <ItemGroup>      
    <!--声明一个"CSFile"的项,Include表示引入"csfile1.cs"文件-->      
    <CSFile Include="csfile1.cs">      
      <!--Version表示项的元数据(附加信息)-->      
     <Version>1.0.0.0</Version>      
    </CSFile>      
    <!--也可用";"一次引入多个文件-->      
    <CSFile Include="csfile2.cs;csfile3.cs"/>      
  </ItemGroup>      
  <Target Name="build">      
    <!--@引用项的值,默认以";"分割开-->      
    <!--输出"csfile1.cs;csfile2.cs;csfile3.cs"-->      
    <Message Text="@(CSFile)"></Message>      
    <!--可以加第二个参数替换默认的";"分隔符-->      
    <!--输出"csfile1.cs+csfile2.cs+csfile3.cs"-->      
    <Message Text="@(CSFile,'+')"></Message>      
    <!--%引用项的元数据,输出"1.0.0.0"-->      
    <Message Text="%(CSFile.Version)"></Message>      
  </Target>      
</Project>      

MSBuild任务

上述Msaage就是一个任务,用于打印信息,常用的一些还包括CSC、MakeDir、Copy等等,大多任务都是有输出信息的,这些信息可以通过OutPut元素存储在属性或者项中。先写如下CS代码:

1 //存为d:\MSBuildDemo.cs      
2 public class MSBuildDemo      
3 {      
4     static void Main()      
5     {      
6         System.Console.WriteLine("MSBuild组织编译");      
7     }      
8 }      

然后更改项目文件如下:

 1 <?xml version="1.0" encoding="utf-8"?>      
2 <Project DefaultTargets="build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">      
3   <ItemGroup>      
4     <!--指定要编译的文件-->      
5     <CSFile Include="MSBuildDemo.cs"/>      
6   </ItemGroup>      
7   <Target Name="build">      
8     <!--使用Csc任务,对应csc编译器-->      
9     <!--Sources属性表示要编译的文件集合-->      
10     <!--TargetType表示编译目标类型,对应csc编译器的/target参数-->      
11     <Csc Sources="@(CSFile)"      
12          TargetType="exe">      
13       <!--OutputAssembly为csc的输出参数-->      
14       <!--PropertyName表示把TaskParameter属性所指定的输出参数的值存储到outputExeName这个属性中-->      
15       <!--Output还有一个ItemName属性,表示存储到一个项中-->      
16       <Output TaskParameter="OutputAssembly" PropertyName="outputExeFileName"/>      
17     </Csc>      
18     <!--Message任务就可以使用csc所导出的属性outputExeFileName了-->      
19     <!--输出MSBuildDemo.exe-->      
20     <Message Text="$(outputExeFileName)"/>      
21     <!--Exec任务可以运行带有指定程序(可加参数)或命令-->      
22     <!--运行刚从MSBuildDemo.cs源文件编译好的程序-->      
23     <!--运行结果为"MSBuild组织编译"-->      
24     <Exec Command="$(outputExeFileName)"></Exec>      
25   </Target>      
26 </Project>      

用MSbuild执行此项目文件,如期正确打印信息。

MSBuild目标

上面的一个例子中Target元素就是MSBuild目标,此目标按照编译源代码、打印编译好的程序文件名、执行该文件这个顺序组织了这三个任务。这就是目标所要做的事情。先简单介绍到这里吧,关于(属性、项、任务、目标)的一些扩展信息会在下一篇介绍。如有错误之处,欢迎指正!

注:以上资料全部来自MSDN帮助文档。

http://www.cnblogs.com/shanyou/p/3452938.html

MSBuild的简单介绍与使用

MSBuild 是 Microsoft 和 VisualStudio的生成系统。它不仅仅是一个构造工具,应该称之为拥有相当强大扩展能力的自动化平台。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 -->      
      <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>      

在构造工程中我们可以定义和使用变量(通过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>      

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来顺序地执行相应的任务。

继续阅读