本文内容
安装 MSBuild
创建 MSBuild 项目
检查项目文件
目标和任务
添加目标和任务
生成目标
生成属性
检查属性值
从命令行设置属性
特殊字符
生成项
检查项类型值
项元数据
后续步骤
请参阅
MSBuild 是 Microsoft 和 Visual Studio 的生成平台。 本演练介绍 MSBuild 的构建基块,并演示如何编写、操作和调试 MSBuild 项目。 学习内容:
创建和操作的项目文件。
如何使用生成属性
如何使用生成项。
可从 Visual Studio 或命令窗口 运行 MSBuild。 本演练将使用 Visual Studio 创建 MSBuild 项目文件。 可在 Visual Studio 中编辑项目文件,并使用命令窗口 生成项目并检查结果。
如果具有 Visual Studio,表示已经安装了 MSBuild。 在 Visual Studio 2019 及更高版本中,它安装在 Visual Studio 安装文件夹下。 对于 Windows 10 上的典型默认安装,MSBuild.exe 位于 MSBuild\Current\Bin 中的安装文件夹下。
在安装程序中,确保选择要为工作负载使用的 MSBuild 工具,然后选择“安装”。
若要在没有 Visual Studio 的系统上安装 MSBuild,请转到 Visual Studio 2019 生成工具 ,或安装 .NET SDK 。
如果具有 Visual Studio,表示已经安装了 MSBuild。 在 Visual Studio 2022 中,它安装在 Visual Studio 安装文件夹下。 对于 Windows 10 上的典型默认安装,MSBuild.exe 位于 MSBuild\Current\Bin 中的安装文件夹下。
在 Visual Studio 安装程序中,导航到“各个组件”,并找到“MSBuild”。 当你选择安装任何其他工作负荷时,会自动选择它。
若要在没有 Visual Studio 的系统上安装 MSBuild,请转到下载页面 上的 Visual Studio 2022 生成工具。 另一种安装 MSBuild 的方式是安装 .NET SDK 。
Visual Studio 项目系统以 MSBuild 为基础。 因此可使用 Visual Studio 轻松创建新项目文件。 本部分将创建 Visual C# 项目文件。 可选择改为创建 Visual Basic 项目文件。 在本演练的上下文中,两种项目文件的差异很小。
创建项目文件
打开 Visual Studio 并创建一个项目:
在搜索框中,键入“winforms” ,然后选择“创建一个新的 Windows 窗体应用(.NET Framework)”。 在出现的对话框中,选择“创建” 。
在“项目名称”框中 ,键入 BuildApp
。 输入解决方案的“位置”,例如 D:\。
单击“确定” 或“创建” 以创建项目文件。
上一节中使用 Visual Studio 创建了一个 Visual C# 项目文件。 该项目文件在解决方案资源管理器 中由名为 BuildApp 的项目节点表示。 可使用 Visual Studio 代码编辑器来检查项目文件。
检查项目文件
在“解决方案资源管理器” 中,单击项目节点“BuildApp” 。
请注意,在“属性” 浏览器中,“项目文件” 属性是“BuildApp.csproj” 。 所有项目文件名称中都带有后缀“proj” 。 如果创建了 Visual Basic 项目,则项目文件名称将为“BuildApp.vbproj” 。
再次右键单击项目节点,然后单击“编辑 BuildApp.csproj” 。
该项目文件出现在代码编辑器中。
备注
对于某些项目类型(例如 C++),需要卸载项目(右键单击项目文件,然后选择“卸载项目”)才能打开和编辑项目文件 。
项目文件是 XML 格式的文件,带有根节点项目 。
<?xml version='1.0' encoding='utf-8'?>
<Project ToolsVersion='15.0' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'>
大多数 .NET 项目都具有 Sdk
属性。 这些项目称为 SDK 风格的项目。
<Project Sdk='Microsoft.NET.Sdk'>
有许多用于特殊目的的 .NET SDK 的变体;.NET 项目 SDK 中对它们进行了介绍。
生成应用程序的工作由 Target 和 Task 元素完成。
任务是工作的最小单位,换言之,它是生成的“原子”。 任务是可单独执行的组件,具有输入和输出。 目前尚没有在项目文件中引用或定义的任务。 以下各部分介绍如何将项目添加到项目文件。 有关详细信息,请参阅任务 主题。
目标是任务的已命名序列。 有关详细信息,请参阅目标 主题。
[它可以是一个已命名的任务序列,但实际上,它表示要生成或完成的内容,因此应以面向目标的方式进行定义]
默认目标不是在项目文件中定义的。 而是在导入的项目中指定的。 Import 元素可指定导入的项目。 例如在 C# 项目中,默认目标是从“Microsoft.CSharp.targets” 文件中导入的。
<Import Project='$(MSBuildToolsPath)\Microsoft.CSharp.targets' />
无论是否使用导入的文件,都会将其有效插入项目文件。
在 SDK 样式的项目中,不会显示此 Import 元素,因为 SDK 特性会导致此文件被隐式导入。
MSBuild 跟踪生成的目标,并保证每个目标生成次数不超过一次。
将目标添加到项目文件。 将任务添加到打印出消息的目标。
添加目标和任务
将这些行添加到项目文件中,具体位于 Import 语句或打开的 Project 元素之后。
<Target Name='HelloWorld'>
</Target>
这将创建名为 HelloWorld 的目标。 请注意,编辑项目文件时会拥有 IntelliSense 支持。
将行添加到 HelloWorld 目标,以便生成如下所示的结果:
<Target Name='HelloWorld'>
<Message Text='Hello'></Message> <Message Text='World'></Message>
</Target>
保存项目文件。
Message
任务是 MSBuild 所附带的许多任务之一。 有关可用任务的完整列表以及用法信息,请参阅任务参考 。
Message
任务将文本属性的字符串值作为输入并显示在输出设备上(或者如果适用,将其写入一个或多个日志)。 HelloWorld 目标执行 Message 任务两次:第一次显示“Hello”,第二次显示“World”。
如果尝试从 Visual Studio 生成此项目,则不会生成定义的目标。 这是因为 Visual Studio 选择了默认目标,该目标仍是导入的 .targets 文件中的目标 。
从 Visual Studio 的“开发人员命令提示符”运行 MSBuild,生成上面定义的 HelloWorld 目标 。 使用 -target 或 -t 命令行开关选择目标。
备注
以下各部分将“开发人员命令提示”称为“命令窗口” 。
生成目标:
打开“命令窗口” 。
在任务栏的搜索框中,开始键入工具的名称,例如 dev
或 developer command prompt
。 然后显示一个列表,其中包含与搜索模式匹配的已安装应用。
如需手动查找,可在 <visualstudio 安装文件夹>\Common7\Tools 文件夹中找到 LaunchDevCmd.bat 文件。
从命令窗口导航到包含项目文件的文件夹,此例中为 D:\BuildApp\BuildApp 。
使用命令开关 -t:HelloWorld
运行 msbuild。 这将选择并生成 HelloWorld 目标:
msbuild buildapp.csproj -t:HelloWorld
在“命令窗口” 检查输出。 应看到两行“Hello”和“World”:
Hello
World
备注
如果出现的是 The target 'HelloWorld' does not exist in the project
,则可能是忘记将项目文件保存到代码编辑器中。 请保存文件并重试。
通过在代码编辑器和命令窗口之间进行交替,可更改项目文件并快速查看结果。
生成属性是引导生成的名称/值对。 已在项目文件顶部定义了几个生成属性:
<PropertyGroup>
...
<ProductVersion>10.0.11107</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{30E3C9D5-FD86-4691-A331-80EA5BA7E571}</ProjectGuid>
<OutputType>WinExe</OutputType>
...
</PropertyGroup>
所有属性都是 PropertyGroup 元素的子元素。 属性的名称是子元素的名称,属性的值是子元素的文本元素。 例如,应用于对象的
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
定义名为 TargetFrameworkVersion 的属性,并为其指定字符串值“v4.5”。
可能会随时重新定义生成属性。 如果
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
稍后出现在项目文件中,或稍后出现在项目文件中的导入文件中,则 TargetFrameworkVersion 会采用新值“v3.5”。
若要获取属性值,请使用以下语法,其中 PropertyName
是属性的名称:
$(PropertyName)
使用此语法可检查项目文件中的一些属性。
检查属性值
从代码编辑器中使用以下代码替换 HelloWorld 目标:
<Target Name='HelloWorld'>
<Message Text='Configuration is $(Configuration)' />
<Message Text='MSBuildToolsPath is $(MSBuildToolsPath)' />
</Target>
保存项目文件。
在“命令窗口” 输入并执行此行:
msbuild buildapp.csproj -t:HelloWorld
检查输出。 应看到这两行(输出可能不同):
Configuration is Debug
MSBuildToolsPath is C:\Program Files\Microsoft Visual Studio\2022\MSBuild\Current\Bin\amd64
Configuration is Debug
MSBuildToolsPath is C:\Program Files (x86)\Microsoft Visual Studio\2019\MSBuild\16.0\Bin
许多属性(如 Configuration
)都是按条件进行定义的,也就是说,Condition
属性出现在 property 元素中。 仅当条件评估结果为“true”时才定义或重新定义条件属性。 请注意,会向未定义的属性给定空字符串的默认值。 例如,应用于对象的
Debug
'><Configuration Condition=' '$(Configuration)' == '' '>Debug</Configuration>
表示“如果尚未定义配置属性,请定义该属性并为其指定'Debug’值”。
几乎所有 MSBuild 元素都可以具有条件属性。 有关使用条件属性的详细讨论,请参阅条件 。
MSBuild 保留了一些属性名称,用于存储有关项目文件和 MSBuild 二进制文件的信息。 MSBuildToolsPath 就是保留属性的一个示例。 与其他属性一样,可使用 $ 符号引用保留属性。 有关详细信息,请参阅如何:引用项目文件的名称或位置 和 MSBuild 保留和常见属性 。
可使用与生成属性相同的方式引用项目文件中的环境变量。 例如,若要使用项目文件中的 PATH 环境变量,可使用 $(Path)。 如果项目包含与环境变量具有相同名称的属性定义,则项目中的属性将替代环境变量的值。 有关详细信息,请参阅如何:在生成中使用环境变量 。
可使用 -property 或 -p 命令行开关在命令行中定义属性。 从命令行接收的属性值将替代在项目文件和环境变量中设置的属性值。
在命令行中设置属性值:
在“命令窗口” 输入并执行此行:
msbuild buildapp.csproj -t:HelloWorld -p:Configuration=Release
检查输出。 应看到此行:
Configuration is Release.
MSBuild 创建配置属性并赋予其“发布”值。
某些字符在 MSBuild 项目文件中具有特殊意义。 这些字符的示例包括分号 (;) 和星号 (*)。 要将这些特殊字符用作项目文件中的文本,必须使用语法 %<xx> 来指定它们,其中 <xx> 表示字符的 ASCII 十六进制值。
更改 Message 任务以显示具有特殊字符的配置属性的值,使其更易读。
在 Message 任务中使用特殊字符:
从代码编辑器中使用此行替换这两个 Message 任务:
<Message Text='%24(Configuration) is %22$(Configuration)%22' />
保存项目文件。
在“命令窗口” 输入并执行此行:
msbuild buildapp.csproj -t:HelloWorld
检查输出。 应看到此行:
$(Configuration) is 'Debug'
有关详细信息,请参阅 MSBuild 特殊字符 。
项是一段信息,通常是文件名,用作生成系统的输入。 例如,表示源文件的项集合可能会传递到名为“Compile”的任务,以将它们编译为程序集。
所有项都是 ItemGroup 元素的子元素。 项名称是子元素的名称,项值是子元素的包含属性的值。 具有相同名称的项值将收集到该名称的项类型中。 例如,应用于对象的
<ItemGroup>
<Compile Include='Program.cs' />
<Compile Include='Properties\AssemblyInfo.cs' />
</ItemGroup>
定义包含两个项的项组。 项类型编译有两个值:Program.cs 和 Properties\AssemblyInfo.cs 。
以下代码通过在一个 Include
属性中声明这两个文件(用分号分隔)来创建相同的项目类型。
<ItemGroup>
<Compile Include='Program.cs;Properties\AssemblyInfo.cs' />
</ItemGroup>
有关详细信息,请参阅项 。
备注
文件路径是包含 MSBuild 项目文件的文件夹的相对路径,即使项目文件是导入的项目文件也是如此。 但存在一些例外情况,例如,在使用 Import 和 UsingTask 元素时。
若要获取项目类型的值,请使用以下语法,其中 ItemType
是项目类型的名称:
@(ItemType)
使用此语法可检查项目文件中的 Compile
项目类型。
检查项类型值:
从代码编辑器中使用以下代码替换 HelloWorld 目标任务:
<Target Name='HelloWorld'>
<Message Text='Compile item type contains @(Compile)' />
</Target>
保存项目文件。
在“命令窗口” 输入并执行此行:
msbuild buildapp.csproj -t:HelloWorld
检查输出。 应看到这一长行:
Compile item type contains Form1.cs;Form1.Designer.cs;Program.cs;Properties\AssemblyInfo.cs;Properties\Resources.Designer.cs;Properties\Settings.Designer.cs
默认情况下,用分号分隔项类型的值。
若要更改项类型的分隔符,请使用以下语法,其中 ItemType 是项类型,Separator 是一个或多个分隔字符的字符串:
@(ItemType, Separator)
更改 Message 任务以使用回车和换行 (%0A%0D) 显示每行的编译项。
每行显示一个项类型值
从代码编辑器中使用此行替换 Message 任务:
'><Message Text='Compile item type contains @(Compile, '%0A%0D')' />
保存项目文件。
在“命令窗口” 输入并执行此行:
msbuild buildapp.csproj -t:HelloWorld
检查输出。 应看到这些行:
Compile item type contains Form1.cs
Form1.Designer.cs
Program.cs
Properties\AssemblyInfo.cs
Properties\Resources.Designer.cs
Properties\Settings.Designer.cs
可配合使用通配符“*”、“**”和“?”和 Include 属性将项添加到项类型。 例如,应用于对象的
<Photos Include='images\*.jpeg' />
将“图片” 文件夹中所有文件扩展名为“.jpeg” 的文件添加到照片项类型,而
<Photos Include='images\**\*.jpeg' />
将“图片” 文件夹和其所有子文件夹中所有文件扩展名为“.jpeg” 的文件添加到照片项类型。 有关更多示例,请参见如何:选择要生成的文件 。
注意,项在声明时会被添加到项类型。 例如,应用于对象的
<Photos Include='images\*.jpeg' />
<Photos Include='images\*.gif' />
创建一个名为“照片”的项类型,其中包含“图片” 文件夹中的所有文件,这些文件的扩展名为“.jpeg” 或“.gif” 。 这等效于以下行:
<Photos Include='images\*.jpeg;images\*.gif' />
可使用 Exclude 属性从项类型中排除项。 例如,应用于对象的
<Compile Include='*.cs' Exclude='*Designer*'>
将所有文件扩展名为“.cs” 的文件添加到编译项类型,除了名称中包含字符串“Designer” 的文件。 有关更多示例,请参见如何:从生成中排除文件 。
Exclude 属性只会影响由 Include 属性添加的项(这两个属性均位于项元素中)。 例如,应用于对象的
<Compile Include='*.cs' />
<Compile Include='*.res' Exclude='Form1.cs'>
不会排除在之前的项元素中添加的文件 Form1.cs 。
包含和排除项
从代码编辑器中使用此行替换 Message 任务:
<Message Text='XFiles item type contains @(XFiles)' />
在 Import 元素后添加此项组:
<ItemGroup>
<XFiles Include='*.cs;properties/*.resx' Exclude='*Designer*' />
</ItemGroup>
保存项目文件。
在“命令窗口” 输入并执行此行:
msbuild buildapp.csproj -t:HelloWorld
检查输出。 应看到此行:
XFiles item type contains Form1.cs;Program.cs;Properties/Resources.resx
除了从 Include 和 Exclude 属性收集的信息外,项还可能包含元数据。 对于需要关于项的详细信息而不仅仅是项值的任务,可使用此元数据。
项元数据可通过创建元素(其中元数据的名称作为项的子元素)在项目文件中进行声明。 项可以有零个或零个以上的元数据值。 例如,以下 CSFile 项具有值为“Fr”的区域性元数据:
<ItemGroup>
<CSFile Include='main.cs'>
<Culture>Fr</Culture>
</CSFile>
</ItemGroup>
若要获取项目类型的元数据值,请使用以下语法,其中 ItemType
是项目类型的名称,MetaDataName 是元数据的名称:
%(ItemType.MetaDataName)
检查项元数据:
从代码编辑器中使用此行替换 Message 任务:
<Message Text='Compile.DependentUpon: %(Compile.DependentUpon)' />
保存项目文件。
在“命令窗口” 输入并执行此行:
msbuild buildapp.csproj -t:HelloWorld
检查输出。 应看到这些行:
Compile.DependentUpon:
Compile.DependentUpon: Form1.cs
Compile.DependentUpon: Resources.resx
Compile.DependentUpon: Settings.settings
请注意,短语“Compile.Dependent Upon”会多次出现。 在目标中使用具有此语法的元数据会造成“批处理”。 批处理是指针对每个唯一元数据值执行一次目标中的任务。 这是等效于常见的“for 循环”编程结构的 MSBuild 脚本。 有关详细信息,请参阅批处理 。
无论何时向项列表添加项时,都会向该项分配一些常见元数据。 例如,%(Filename) 会返回任何项的文件名。 若要了解完整的常见元数据列表,请参阅常见项元数据 。
检查常见元数据:
从代码编辑器中使用此行替换 Message 任务:
<Message Text='Compile Filename: %(Compile.Filename)' />
保存项目文件。
在“命令窗口” 输入并执行此行:
msbuild buildapp.csproj -t:HelloWorld
检查输出。 应看到这些行:
Compile Filename: Form1
Compile Filename: Form1.Designer
Compile Filename: Program
Compile Filename: AssemblyInfo
Compile Filename: Resources.Designer
Compile Filename: Settings.Designer
通过比较上面两个示例,可以看到,虽然并非每个编译项类型中的项都有 DependentUpon 元数据,但所有项都具有常见 Filename 元数据。
项列表可以转换为新的项列表。 若要转换项列表,请使用以下语法,其中 <ItemType> 是项类型的名称,<MetadataName> 是元数据的名称:
@(ItemType -> '%(MetadataName)')
例如,可使用表达式 @(SourceFiles -> '%(Filename).obj')
将源文件的项列表转换为对象文件的集合。 有关详细信息,请参阅转换 。
使用元数据转换项:
从代码编辑器中使用此行替换 Message 任务:
'><Message Text='Backup files: @(Compile->'%(filename).bak')' />
保存项目文件。
在“命令窗口” 输入并执行此行:
msbuild buildapp.csproj -t:HelloWorld
检查输出。 应看到此行:
Backup files: Form1.bak;Form1.Designer.bak;Program.bak;AssemblyInfo.bak;Resources.Designer.bak;Settings.Designer.bak
请注意,此语法中表示的元数据不会造成批处理。
要了解如何在 Windows 上一步步创建一个简单的项目文件,请尝试演练:从头开始创建 MSBuild 项目文件 中的步骤。
如果你主要是使用 .NET SDK,你可能希望继续阅读 .NET SDK 项目的 MSBuild 参考 。