• MSBuild入门(续)


    MSBuild基本概念(续)

    在上一篇简单的介绍了下MSBuild中的四个基本块,每块介绍比较单薄,在这里对在大多数的项目模版生成的*.*proj文件中比较常见一些用法和概念做些补充。主要有一下几方面:

    MSBuild特殊字符:MSBuild保留的一些字符,以及XML中的特殊字符处理。
    MSBuild条件: Condition特性,作用类似于C#的if。
    MSBuild属性: 使用环境变量、保留属性、全局属性。
    MSBuild项: 元数据、项转换。
    MSBuild任务: ITask接口、UsingTask[自定义任务]、ContinueOnError。
    MSBuild目标: 初始目标、默认目标、目标依赖项。
    Import元素: 导入项目文件到当前项目文件。

    MSBuild特殊字符

    一些字符在MSBuild中代表着特殊的上下文含义,如下:

    MSBuild的特殊字符[%引用元数据]、[$引用属性]、[@引用项]、['条件或其他表达式]、[;列表分隔符]、[?文件名通配符]、[*文件名通配符];
    XML的保留字符:<、>、&、"、'

    针对MSBuild的特殊字符转义需要用[%xx]这种方式,xx代表字符的ASCII十六进制值([%=%25][$=%24][@=%40]['=%27][;=%3B][?=%3F][*=%2A])。针对XML保留字符则使用&lt这种方式。 一般用到这些特殊字符的情况不多,见到时能知道是转义就可以了。

    MSBuild条件

    条件在*.*proj项目文件中非常常见,用Condition特性来表示一个布尔表达式,类似于if条件,几乎所有的元素都可以具有Conditon特性。一个简单的例子如下:

    复制代码
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <!--condition.xml文件-->
     3 <Project DefaultTargets="show" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     4   <PropertyGroup>
     5     <!--Condition在属性、项、任务、目标生都有使用-->
     6     <!--如果Configuration为空(''),则其值为Debug-->
     7     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     8     <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
     9   </PropertyGroup>
    10   <ItemGroup>
    11     <!--如果csfile1.cs文件存在就包含在CSFile项中-->
    12     <CSFile Include="csfile1.cs" Condition="Exists('csfile1.cs')"></CSFile>
    13   </ItemGroup>
    14   <Target Name="show">
    15     <!--输出Debug|x86-->
    16     <Message Text="$(Configuration)|$(Platform)"/>
    17     <!--输出空,因为csfile1.cs并不存在-->
    18     <Message Text="@(CSFile)"/>
    19   </Target>
    20 </Project>
    复制代码

    还有一些常用的表达式如!=、!、And、Or等。

    MSBuild属性

    上篇介绍到可以用$可以引用自定义的属性,除此之外亦可以引用系统的环境变量,如$(Path),以及 MSBuild保留属性(MSDN)

    属性除了可以在项目文件中声明是赋值外,在MSBuild命令行也允许设置属性的值(语法:/p:propertyName=value)。称作全局属性,这类属性会重写在项目文件中设置的属性值,保留属性除外的任何属性都可被这种方式覆盖其原值。 以上面示例为基础:[MSBuild condition.xml /p:Platform=x64],则最终输出结果就为Debug|x64了。

    属性还有一种叫做任务发出属性,在上篇用到了,由Output元素的PropertyName特性指定了属性名,这类属性不像一般的声明式属性那样赋值,而是动态得到的值。是在项目文件中很常见的用法。

    MSBuild项

    项大都是用来引入文件用的,而文件会有一些附加信息,比如版本,语言等,而这些附加信息在项目文件中是以项的子元素的出现的,称为项的元数据。元数据是键/值的形式存储的,声明方式和属性相同。

    复制代码
    1   <ItemGroup>
    2     <!--如果csfile1.cs文件存在就包含在CSFile项中-->
    3     <CSFile Include="csfile1.cs">
    4       <!--声明元数据,必须为项的一级子元素-->
    5       <!--引用方式:%(CSFile.Culture)-->
    6       <Culture>zh-cn</Culture>
    7     </CSFile>
    8   </ItemGroup>
    复制代码

    除了自定义的一些元数据外,系统还提供一些隐式存在的元数据,即不用声明即可使用,具体可参见MSBuild常见的已知元数据。引用这类元数据的语法和自定义的完全相同。

    项转换允许把一个项的列表与另一个列表一一变换。比如下面的例子:

    复制代码
     1 <?>
     5     <CSFile Include="1.cs;2.cs"/>
     6     <!--%(Filename)为项的元数据,由系统提供-->
     7     <VBFile Include="@(CSFile->'%(Filename).vb')"/>
     8   </ItemGroup>
     9   <Target Name="show">
    10     <!--输出1.cs;2.cs-->
    11     <Message Text="@(CSFile)"/>
    12     <!--输出1.vb;2.vb-->
    13     <Message Text="@(VBFile)"/>
    14   </Target>
    15 </Project>
    复制代码

    MSBuild任务

    从上篇中我们对任务的认识是它是一个原子操作,用来执行某一项逻辑处理,但是xml格式的项目文件是没有这个处理能力的,所以这些任务都是映射到.NET类库中的一些类,由这些类来处理操作中的逻辑。具体来说都是实现ITask接口的类,ITask接口位于Microsoft.Build.Framework命名空间。当然我们也可以实现自己的任务类,直接实现ITask接口或者继承自Task(此抽象类实现了ITask接口的部分功能,可简化自定义任务类的编写,留出一个Execute抽象方法供子类重写自己的任务逻辑)。然后通过UsingTask元素映射到出一个任务元素。我就继承Task写一个简单的示例:

    复制代码
     1 //AddTwoNumberTask.cs,需编译为dll
     2 using System;
     3 using Microsoft.Build.Utilities;
     4 using Microsoft.Build.Framework;
     5  
     6 /// <summary>
     7 /// 继承Task,任务逻辑是处理加法
     8 /// </summary>
     9 public class AddTwoNumberTask : Task
    10 {
    11     /// <summary>
    12     /// 定义一个加数,
    13     /// 如果一个输入属性被要求必须输入,则用[Required]特性标识该属性
    14     /// </summary>
    15     public String Number1 { get; set; }
    16     /// <summary>
    17     /// 定义另一个加数
    18     /// </summary>
    19     public String Number2 { get; set; }
    20     public override bool Execute()
    21     {
    22         this.Sum = (Int32.Parse(this.Number1) + Int32.Parse(this.Number2)).ToString();
    23         return true;
    24  
    25     }
    26     /// <summary>
    27     /// 定义一个输出参数,使用Output特性修饰该属性
    28     /// </summary>
    29     [Output]
    30     public String Sum { get; set; }
    31 }
    复制代码
     然后编写如下项目文件,放于AddTwoNumberTask.cs同目录下:
    复制代码
     1 <!--buildAddTaskDll.csproj-->
     2 <?xml version="1.0" encoding="utf-8"?>
     3 <!--从AddTwoNumberTask.cs源文件到编译成dll-->
     4 <Project DefaultTargets="buildAddTaskDll"  ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     5 <PropertyGroup>
     6     <OutputType>Library</OutputType>
     7 </PropertyGroup>
     8 <ItemGroup>
     9     <Reference Include="Microsoft.Build.Framework" />
    10     <Reference Include="Microsoft.Build.Utilities.v4.0" />
    11     <Reference Include="System" />
    12 </ItemGroup>
    13 <ItemGroup>
    14     <Compile Include="AddTwoNumberTask.cs" />
    15 </ItemGroup>
    16 <Target Name="buildAddTaskDll">
    17     <!--@(Reference->'$(MSBuildBinPath)\%(Identity).dll')表示项转换-->
    18     <Csc Sources="@(Compile)"
    19     References="@(Reference->'$(MSBuildBinPath)\%(Identity).dll')"
    20         TargetType="$(OutputType)">
    21     </Csc>
    22 </Target>
    23 </Project>
    复制代码

    用MSBuild编译buildAddTaskDll.csproj项目文件。得到AddTwoNumberTask.dll程序集。再编写一个项目文件usingtask如下:

    复制代码
    <?xml version="1.0" encoding="utf-8"?>
    <!--使用自定义的任务做加法-->
    <Project DefaultTargets="show"  ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <UsingTask TaskName="AddTwoNumberTask" AssemblyFile = "AddTwoNumberTask.dll"/>
      <Target Name="show">
        <AddTwoNumberTask Number1="1" Number2="2" >
          <Output TaskParameter="Sum" PropertyName="SumValue"/>
        </AddTwoNumberTask>
        <!--输出3-->
        <Message Text="$(SumValue)"/>
      </Target>
    </Project>
    复制代码

    如果仔细看AddTwoNumberTask.cs文件就会发现

    //如果Number1或者2不是数字,则此任务就会抛异常了 
    this.Sum = (Int32.Parse(this.Number1) + Int32.Parse(this.Number2)).ToString();

    那么如果<AddTwoNumberTask Number1="1" Number2="2" >在这里加一个ContinueOnError=“true”,则表示会忽略掉逻辑处理中的错误,继续运行,否则会终止执行后续任务。如果任务有输出参数的话,Output元素总是作为任务的子元素出现,作为一个中间桥梁把任务的输出传输到属性或者项中。

    MSBuild目标

    Project根元素代表者一个项目文件,上面的例子我都会写一个DefaultTargets特性来指定该项目文件要执行的默认目标是哪一个。其实此特性是可选的,也是可以用分号分割写多个的,执行顺序依据书写顺序来判定,也可通过MSBuild命令行参数来传递:

    msbuild /target:Build1;Build2

    除此之外,Project元素还有一个可选特性InitialTargets,也支持多个目标。如果这两个特性都没有,则MSBuild先执行它遇到的第一个Target。Target有一个DependsOnTargets特性表示当前目标依赖另一个目标,效果就是DependsOnTargets特性指定的目标先于当前目标执行。这绕来绕去好多先后顺序关系,写一个示例看看吧。

    复制代码
     1 <?xml version="1.0" encoding="utf-8"?>
     2 <!--目标执行顺序-->
     3 <!--如果InitialTargets特性存在,则首先执行此目标列表-->
     4 <!--如果DefaultTargets特性存在,则继续执行此目标列表-->
     5 <Project InitialTargets="B1;B2" DefaultTargets="B3;B4"  
     6          ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
     7   <!--如果发现Target具有DependsOnTargets特性-->
     8   <!--则先执行DependsOnTargets指定的目标-->
     9   <!--MSBuild4新加入了RunBeforeTargets和RunAfterTargets特性-->
    10   <!--其作用和DependsOnTargets类似,一前一后,不做演示了-->
    11   <Target Name="B1" DependsOnTargets="B5">
    12     <Message Text="B1"/>
    13   </Target>
    14   <Target Name="B2">
    15     <Message Text="B2"/>
    16   </Target>
    17   <Target Name="B3">
    18     <Message Text="B3"/>
    19   </Target>
    20   <Target Name="B4">
    21     <Message Text="B4"/>
    22   </Target>
    23   <Target Name="B5">
    24     <Message Text="B5"/>
    25   </Target>
    26   <!--结果为:B5 B1 B2 B3 B4-->
    27 </Project> 
    复制代码

    Import元素

    项目模版产生的*.*proj项目文件大量的使用这个元素,用来导入可重用的项目文件,其中最常见的一个应该是这个吧,如果你用C#开发的话。

    <Import Project="$(MSBuildToolsPath)Microsoft.CSharp.targets" />

    MSBuildToolsPath或者是MSBuildBinPath,Project特性指定要导入的项目文件。Import元素像是一个占位元素,MSBuild在执行到此时会用*.targets替换掉此元素,就像本来就声明在这里一样,所以和*.targets文件有关的所有保留属性会被重置。 Import元素对导入文件的扩展名无要求,文件是正确的项目文件就行,但一般约定为*.targets。

    总结和备注

    了解了以上知识点后,阅读一般的项目模版生成的项目文件(*.*proj)应该是可以的了,下篇文章先认识几个重要的*.targets,为剖析项目文件做准备。

    备注:针对项目文件中所指的“特性”是表示一个xml元素的“属性”。由于属性在MSBuild中有特殊含义,则MSDN文档一律把项目文件中的xml属性称作是特性,比如Message任务的Text特性。如有错误之处,欢迎指正!

    http://www.cnblogs.com/linianhui/archive/2012/09/01/2666104.html#MSBuildPropertyGroup

  • 相关阅读:
    3. 无重复字符的最长子串
    24. 两两交换链表中的节点
    2. 两数相加
    23. 合并K个排序链表
    synergy配置 Ubuntu作Server, Win 7作client
    ros与下位机通信常用的c++ boost串口应用
    tar
    发布里程计传感器信息
    ROS TF——learning tf
    在linux终端下打开pdf文件
  • 原文地址:https://www.cnblogs.com/chen110xi/p/4835716.html
Copyright © 2020-2023  润新知