MSBuild笔记1-介绍

MSBuild

MSBuild是在.NET 2.0中引入的针对Visual Studio的构建系统。它可以执行构建脚本,完成各种Task——最主要的是把.NET项目编译成可执行文件或者DLL。从技术角度来说,制作EXE或者DLL的重要工作是由编译器(csc,vbc等等)完成的。MSBuild会从内部调用编译器,并完成其他必要的工作(例如拷贝引用——CopyLocal,执行构建前后的准备及清理工作等)。
这些工作都是MSBuild执行脚本中的Task完成的。MSBuild脚本就是XML文件,根元素是Project,使用MSBuild自己的命名空间。
MSBuild文件都要有Target。Target由Task组成,MSBuild运行这些Task,完成一个完整的目标。Target中可以不包含Task,但是所有的Target都要有名字。

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

在脚本文件中可以做以下操作

  • 定义和使用变量(通过Property/PropertyGourp/Item/ItemGroup等元素);
  • 使用条件分支(通过Choose/When/Otherwise等元素);
  • 在运行时给变量赋值(通过执行任务,获取其返回类型参数的方式);
  • 定义执行块(通过Target元素,相当于函数);
  • 进行异常处理(通过OnError元素);
  • 复用已有工程定义的内容(通过Import元素)。

拥有这些能力和高级语言已经相差无几了,所以笔者认为构造工程不是描述性语言,而是脚本语言。

MSBuild .targets 文件

MSBuild 包括多个 .targets 文件,文件内容包含常见方案的项、属性、目标和任务。 这些文件将自动导入到大多数 Visual Studio 项目文件中,以便简化维护,增强可读性。
项目通常会导入一个或多个 .targets 文件以定义它们的生成进程 。 例如由 Visual Studio 创建的 C# 项目将导入 Microsoft.CSharp.targets ,它可导入 Microsoft.Common.targets 。 C# 项目本身会定义特定于该项目的项和属性,但 C# 项目的标准生成规则在导入的 .targets 文件中进行定义。
$(MSBuildToolsPath) 值指定这些公用 .targets 文件的路径 。 如果 ToolsVersion 为 4.0,则文件位于以下位置:\Microsoft.NET\Framework\v4.0.30319
详细:https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild-dot-targets-files?view=vs-2019

脚本文件四个基本项

  • 属性(Property):主要用来存储配置信息
  • 项(Item):存储项目文件信息,以及文件的元数据信息
  • 任务(Task):Build过程中的一些原子操作
  • 目标(Target):按特定的顺序将任务组织在一起,并允许在命令行单独指定各个部分

MSBuild命令

添加环境变量:Path - C:\Windows\Microsoft.NET\Framework\v4.0.30319
设置属性:msbuild.exe -p:name=value
设置要执行的Target:msbuild.exe -t:target1;target2
详细:https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild-command-line-reference?view=vs-2019

条件

Condition属性来表示一个布尔表达式,类似于if条件,几乎所有的元素都可以具有Conditon属性
案例1:如果结果为True,设置属性AppendTargetFrameworkToOutputPath值为false

<PropertyGroup Condition="'$(Configuration)'=='Debug'">
    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
</PropertyGroup>

案例2:

<PropertyGroup>
  <Name>Alice</Name>
  <IsDefaultName Condition=" '$(Name)' == 'alice' ">true</IsDefaultName>
  <IsDefaultName Condition=" '$(Name)' != 'alice' ">false</IsDefaultName>
</PropertyGroup>

另外,我们还可以使用 ChooseWhenOtherwise 来根据 Condition 选择 When 或者 Otherwise 下的内容,例如:

<Choose>
  <When Condition=" '$(Name)' == 'Alice' ">
    <PropertyGroup>
      <Age>16</Age>
    </PropertyGroup>
    <ItemGroup>
      <Files Include="Alice/**/*.*" />
    </ItemGroup>
  </When>
  <When Condition=" '$(Name)' == 'Bob' or '$(Name)' == 'David' ">
    <PropertyGroup>
      <Age>18</Age>
    </PropertyGroup>
    <ItemGroup>
      <Files Include="$(Name)/**/*.*" />
    </ItemGroup>
  </When>
  <Otherwise>
    <PropertyGroup>
      <Age>20</Age>
    </PropertyGroup>
    <ItemGroup>
      <Files Include="Other/**/*.*" />
    </ItemGroup>
  </Otherwise>
</Choose>

上面当 Name 是 Alice 的时候,将会选择第一个 When 里的东西,而如果是 Bob 或者 David,则会选择第二个 When 里的东西,否则选择 Otherwise 里的东西。
条件将允许我们在构建过程中进行复杂的计算,并且控制整个构建流程。

条件

  • ==:相等返回true
  • !=:不相等返回true
  • <, >, <=, >=:计算操作数的数值。 如果关系评估为 true,则返回 true。
  • Exists('stringA'):如果存在名为 stringA 的文件或文件夹,则计算结果为 true
  • HasTrailingSlash('stringA'):如果指定的字符串末尾包含反斜杠 () 或正斜杠 (/) 字符,则计算结果为 true。
  • !:如果操作数计算结果为 false,则计算结果为 true。
  • And:如果两个操作数计算结果均为 true,则计算结果为 true。
  • Or:如果内含表达式计算结果为 true,则分组机制的计算结果为 true。
  • ():如果内含表达式计算结果为 true,则分组机制的计算结果为 true。

详细:https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild-conditions?view=vs-2019

Project元素

这是每一个项目文件的最外层元素,它表示了一个项目的范围。

Project元素属性:

  • DefaultTargets属性:在一个项目的生成过程中可能需要完成几项不同的任务,其中每一项任务都可以用Target来表示。
    对于拥有多个Target的项目,你可以通过设置Project的DefaultTargets属性来指定需要运行哪(几)个Target,如果没有这个设置,MSBuild将只运行排在最前面的那个Target。
  • xmlns属性:命名空间
  • Sdk属性:可以用来引入 SDK,允许直接引用 SDK 中定义的构建文件

执行多个target

  • 方式1:DefaultTargets
<?xml version="1.0" encoding="utf-8"?>
  <Project DefaultTargets="hello1;hello2" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="hello1">
		<Message Text="hello1"></Message>
   </Target>
    <Target Name="hello2">
		<Message Text="hello2"></Message>
   </Target>
 </Project>
  • 方式2:执行命令时使用/t或-t、-target
msbuild app1.csproj /t:hello1;hello2

PropertyGroup元素

属性都要包含在PropertyGroup元素内部;

<PropertyGroup>
  <Configuration>Release</Configuration>
</PropertyGroup>

也可以通过命令行添加全局属性:

MSBuild.exe xxx.csproj /p:name=fan 
or
MSBuild.exe xxx.csproj -property:Configuration=Release

对属性的引用使用$来引用:

 <PropertyGroup>
	<name>fan</name>
	<!--带条件-->
        <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
 </PropertyGroup>
 <Target Name="build">
	<Message Text="$(name)"></Message>	
	<Message Text="$(Configuration)"></Message>
	<!--输出系统属性,MSBuild.exe的路径-->
	<Message Text="$(MSBuildToolsPath)"></Message>
 </Target>

Cofiguration属性用了Condition属性,它在这里的含义是,只有当属性没有值的情况下,才用我们定义的数据给它们赋值。这段代码实际上就是给它们一个默认值。
如果通过/property(简写为/p)赋值,就不使用默认值

MSBuild.exe app1.csproj /p:Configuration=Release      #输出Release

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

常用属性

可空类型校验:

<Nullable>enable</Nullable>

消除指定代码的警告:

<NoWarn>1701;1702;1591;1570;1572;1573</NoWarn>

将警告转成错误:

<WarningsAsErrors>CS8602;</WarningsAsErrors>

指定编译器使用的C#语言版本:

<LangVersion>preview</LangVersion>
<LangVersion>10.0</LangVersion>

隐式using:

<ImplicitUsings>enable</ImplicitUsings>

指定生成的XML文档文件:

<DocumentationFile>bin\Debug\xxxx.xml</DocumentationFile>

当您编译一个项目时,可以选择生成包含项目中类型、成员和注释的XML文档。这些XML文档可以与项目一起发布,并且可以用于生成API文档或者在集成开发环境中提供代码提示和文档。

ItemGroup元素

Item项都包含在ItemGroup元素中,项大都是用来引用文件的,而文件会有一些附加信息,比如版本,语言等,而这些附加信息在项目文件中是以项的子元素的出现的,称为项的元数据。元数据是键/值的形式存储的,声明方式和属性相同。
根据item的名称,将其分成不同的Item 类型
在项目文件中使用项类型,语法:@(Item Type)
多个元素可以用;分割

使用通配符指定项类型的文件

可以使用**、*和?三种通配符指定一组文件作为构建的输入.

  • ?通配符指定一个单一的字符
  • *通配符指定零个或多个字符
  • **通配符匹配部分路径
    包含当前项目中所有的cs文件
<CSFile Include="*.cs"/> 

D盘下的除DoNotBuild.cs文件外的所有cs文件

<!--Exclude属性是用来排除某些不想加入到项类型中的文件-->
<CSFile Include="D:/**/*.cs"  Exclude="DoNotBuild.cs/> 

常用的Item项

PackageReference:包引用

<PackageReference Include="Dapper" Version="2.0.35" /> 

ProjectReference:项目引用

<ProjectReference Include=".\MeShop.Application.csproj" /> 

EmbeddedResource:表示要嵌入所生成的程序集中的资源。

<EmbeddedResource Include="EmailHandler\Template\PayUrge\Item.html" />

Folder:目录

<Folder Include="Areas\CheckOut\Handlers\" /> 

Content:表示未编译到项目中但可能嵌入项目或随其一起发布的文件。

<Content Include="staticfiles\ForgetPwdEmailTemplate.html">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

None:表示在生成过程中不应具有角色的文件。
NativeReference:
Compile:表示编译器的源文件。
COMReference:
COMFileReference:
AssemblyMetadata:表示要生成为 [AssemblyMetadata(key, value)] 的程序集特性。
Item详细信息:https://docs.microsoft.com/zh-cn/visualstudio/msbuild/common-msbuild-project-items?view=vs-2019

项元数据(Item Metadata)

项类型中除了有Include属性和ExClude属性之外,还可以有项元数据.项元数据向Task提供了更多的关于项类型的信息;如果想在项目文件中使用项元数据,语法:%(ItemType.ItemMetadataName)
项元数据是以键值对的方式来表示,如下:(Version)

案例

  <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>

Item元数据

Item元数据是附加到Item的值。 有些是由 MSBuild 在创建项时分配给Item的,但你也可以定义所需的任何元数据。
系统元数据:

  • %(Item.FullPath) 包含项的完整路径。 例如:C:\MyProject\Source\Program.cs
  • %(Item.RootDir) 包含项的根目录。 例如:C:\
  • %(Item.Filename) 包含项的文件名,但不包含扩展名。 例如:Program
  • %(Item.Extension) 包含项的文件扩展名。 例如:.cs
  • %(Item.RelativeDir) 包含 Include 特性中指定的路径,直到最后的反斜杠 ()。 例如:Source\
  • %(Item.Directory) 包含项的目录,但不包含根目录。 例如:MyProject\Source\
  • %(Item.RecursiveDir) 如果 Include 特性包含通配符 **,则此元数据将指定代替通配符的路径的一部分。
  • %(Item.Identity) 在 Include 特性中指定的项。 例如:Source\Program.cs
  • %(Item.ModifiedTime) 包含上一次修改项的时间戳
  • %(Item.CreatedTime) 包含创建项的时间戳
  • %(Item.AccessedTime) 包含上一次访问项的时间戳
    Item系统元数据Demo:
  <ItemGroup>
	<MyItem Include="BuildFolder\1.txt" />
  </ItemGroup>  
    <Target Name="hello1">
		<Message Text="%(MyItem.FullPath)"></Message>
		<Message Text="%(MyItem.RootDir)"></Message>
		<Message Text="%(MyItem.Filename)"></Message>
		<Message Text="%(MyItem.Extension)"></Message>
		<Message Text="%(MyItem.RelativeDir)"></Message>
		<Message Text="%(MyItem.Directory)"></Message>
		<Message Text="%(MyItem.RecursiveDir)"></Message>
   </Target>

.NET 函数调用

MSBuild 允许我们直接调用 MSBuild 内置的或者 .NET 中的函数,调用方法为 [类型名]::方法名(参数...),例如:

<PropertyGroup>
  <Foo>1</Foo>
  <Foo Condition="[MSBuild]::IsOsPlatform('Windows')">2</Foo>
</PropertyGroup>

则 Foo 在 Windows 上为 2,而在其他系统上为 1。

属性和项都有各自的 MSBuild 内置函数可以用,例如 ExistsHasMetadata 等等,具体可在 MSBuild 官方文档上查阅:

属性函数:https://docs.microsoft.com/zh-cn/visualstudio/msbuild/property-functions
项函数:https://docs.microsoft.com/zh-cn/visualstudio/msbuild/item-functions
有了这些,我们便可以利用 MSBuild 完成各种事情。

MSBuild特殊字符:

[%引用元数据]、[$引用属性]、[@引用项]、['条件或其他表达式]、[;列表分隔符]、[?文件名通配符]、[*文件名通配符]

Import元素

用来导入可重用的项目文件,Project特性指定要导入的项目文件。Import元素像是一个占位元素,MSBuild在执行到此时会用文件内容替换掉此元素,就像本来就声明在这里一样。 Import元素对导入文件的扩展名无要求,文件是正确的项目文件就行,但一般约定为*.targets

<Import Project="foo.targets" />

参考:
https://www.cnblogs.com/hez2010/p/a-brand-new-look-at-msbuild-1.html
https://www.cnblogs.com/linianhui/archive/2012/08/30/msbuid-introduction-1.html(MSBuild入门)
https://www.cnblogs.com/linianhui/archive/2012/09/01/msbuid-introduction-2.html(MSBuild入门续)
https://www.cnblogs.com/shanyou/p/3452938.html(MSBuild简单使用)
https://learn.microsoft.com/zh-cn/visualstudio/msbuild/msbuild?view=vs-2022

posted @ 2020-10-17 16:16  .Neterr  阅读(1035)  评论(0编辑  收藏  举报