从 GitHub 上 Clone 下来 aspnetcore 源码后,要进行各种编译,出错~
为自己不了解错误背后的原因而感到难受,所以下定决心好好学习一下 MSBuild~
MSBuild 初体验
安装完 Visual Studio 2019 后,在下面两个目录下有 MSBuild.exe
:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\amd64
由于官方文档说一般情况下不使用 64版本,
所以我们将 C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin 添加到 环境变量 PATH
中
1 | >msbuild |
创建一个 HelloWorld.xml 的内容为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22<?xml version="1.0" encoding="utf-8"?>
<!-- 根元素,表示一个项目 -->
<!-- DefaultTargets 用于定默认执行的目标 -->
<Project DefaultTargets="build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- 属性都要包含在 PropertyGroup 元素内部 -->
<PropertyGroup>
<!-- 声明一个自定义"greeting"属性,其值为"hello world" -->
<greeting>hello world</greeting>
</PropertyGroup>
<!-- 目标 -->
<Target Name="build"> <!--DefaultTargets 指定的就是我-->
<!-- MSBuild 提供的一个内置任务,用于生成记录信息用 $(属性名) 来引用属性的值 -->
<Message Text="$(greeting)"></Message>
<!-- 使用 MSBuild 提供的保留属性,输出全路径 -->
<Message Text="$(MSBuildThisFileDirectory)$(MSBuildProjectFile)"></Message>
</Target>
</Project>
1 | D:\MSBuildDemo>msbuild HelloWorld.xml |
创建最小的应用程序
在 D:\MSBuildDemo
下创建 Helloworld.cs
文件,内容为:
1 | using System; |
在 Windows 任务栏的搜索框中进行搜索 Developer Command Prompt for VS 2019
,演示
以管理员身份运行 Developer Command Prompt for VS 2019
,启动后应该是:
1 | ********************************************************************** |
在命令提示符下,键入 csc D:\MSBuildDemo\HelloWorld.cs
来生成应用程序。
1 | C:\Windows\System32>csc D:\MSBuildDemo\HelloWorld.cs |
编译成功后,在 C:\Windows\System32
会生成 HelloWorld.exe
在命令提示符下,键入 helloworld 测试应用程序。
1 | C:\Windows\System32>helloworld |
将在 C:\Windows\System32
会生成的 HelloWorld.exe
删除1
C:\Windows\System32>del helloworld.exe
创建最小的 MSBuild 项目文件
在 D:\MSBuildDemo
下创建 Helloworld.csproj
文件,内容为:
1 | <!-- 必需的根 Project 节点。 --> |
运行 Developer Command Prompt for VS 2019
,后:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17C:\Windows\System32>msbuild D:\MSBuildDemo\HelloWorld.csproj
用于 .NET Framework 的 Microsoft (R) 生成引擎版本 16.7.0+b89cb5fde
版权所有(C) Microsoft Corporation。保留所有权利。
生成启动时间为 yyyy/MM/DD HH:mm:ss。
节点 1 上的项目“D:\MSBuildDemo\HelloWorld.csproj”(默认目标)。
Build:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Roslyn\csc.exe /out:HelloWorld.exe
HelloWorld.cs
已完成生成项目“D:\MSBuildDemo\HelloWorld.csproj”(默认目标)的操作。
已成功生成。
0 个警告
0 个错误
已用时间 00:00:00.54
主要的是,HelloWorld.exe
是生成在与 HelloWorld.csproj
同一个目录。
新开一个 CMD 窗口,CD 到 D:\MSBuildDemo
,运行 helloworld
:
1 | D:\MSBuildDemo>helloworld |
如果不使用 Developer Command Prompt for VS 2019
启动的窗口,
请注意 -t:Build
部分:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17D:\MSBuildDemo>msbuild helloworld.csproj -t:Build
用于 .NET Framework 的 Microsoft (R) 生成引擎版本 16.7.0+b89cb5fde
版权所有(C) Microsoft Corporation。保留所有权利。
生成启动时间为 yyyy/MM/DD HH:mm:ss。
项目“D:\MSBuildDemo\helloworld.csproj”在节点 1 上(Build 个目标)。
Build:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\Roslyn\csc.exe /out:HelloWorld.exe
HelloWorld.cs
已完成生成项目“D:\MSBuildDemo\helloworld.csproj”(Build 个目标)的操作。
已成功生成。
0 个警告
0 个错误
已用时间 00:00:00.52
添加生成属性
可以将生成属性添加到项目文件中,从而进一步控制生成。 现在添加以下属性:
一个 AssemblyName
属性,用于指定应用程序的名称。
一个 OutputPath
属性,用于指定要包含应用程序的文件夹。
1 |
|
1 | D:\MSBuildDemo>msbuild helloworld.csproj -t:Build |
备注
在 OutputPath 元素中指定文件夹名称时,建议在文件夹名称的末尾添加反斜杠 () 路径分隔符,而不是将其添加到 Csc 任务的 OutputAssembly 属性中。 因此,
\<OutputPath>Bin\\ 推荐有 \OutputAssembly==”\$(OutputPath)\$(AssemblyName).exe” /> 不推荐有 \
优于
\<OutputPath>Bin\OutputAssembly==”$(OutputPath)\$(AssemblyName).exe” />
1 | <!-- 既然有多个 Target,就可以将 Build 目标设置为默认目标。 --> |
测试生成目标
在命令提示符处,键入msbuild helloworld.csproj -p:AssemblyName=Greetings。
- 由于未使用 -t 开关显式设置目标,因此 MSBuild 运行默认 Build 目标。
- -p 开关替代 AssemblyName 属性,并为它指定新值 Greetings。 这将导致在“\Bin\”文件夹中创建一个新应用程序 Greetings.exe。
要验证“\Bin\”文件夹是否同时包含 MSBuildSample 应用程序和新的 Greetings 应用程序,请键入“dir Bin”。
键入 Bin\Greetings 测试 Greetings 应用程序。
- 显示的消息应为 Hello, world! 。
通过键入 msbuild helloworld.csproj -t:clean,删除 MSBuildSample 应用程序。
- 这将运行 Clean 任务,以删除具有默认 AssemblyName 属性值 MSBuildSample 的应用程序。
通过键入 msbuild helloworld.csproj -t:clean -p:AssemblyName=Greetings,删除 Greetings 应用程序。
- 这将运行 Clean 任务,以删除具有指定 AssemblyName 属性值 Greetings 的应用程序。
要验证“\Bin\”文件夹现在是否为空,请键入“dir Bin”。
键入 msbuild。
- 尽管未指定项目文件,但 MSBuild 会生成 helloworld.csproj 文件,因为当前文件夹中只有一个项目文件。 这将导致在“\Bin\”文件夹中创建 MSBuildSample 应用程序。
小结一下:
- 可以通过给
-t
传递Target
的Name
,来指定运行该Target
下的任务。 - 可以通过
-p:
来设置PropertyGroup
节点中的参数值。
增量生成
可以指示 MSBuild 仅在目标所依赖的源文件或目标文件发生更改时才生成目标。 MSBuild 使用文件的时间戳来确定文件是否已更改。
将 Target Name="Build"
节点修改成如下:
1 | <Target Name="Build" Inputs="@(Compile)" Outputs="$(OutputPath)$(AssemblyName).exe"> |
1 | D:\MSBuildDemo>msbuild -v:d |
难道是比较 HelloWorld.cs
文件最后的修改时间与 Bin\MSBuildSample.exe
文件最后的修改时间?
总结
最后按 https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild?view=vs-2019 小结一下我们了解到的内容~
1 | <!-- 在 MSBuild 中,元素和特性名称区分大小写。 但是,属性、项和元数据名称不区分大小写。 --> |
心中的迷茫渐渐消去~
然后,当我们打开通过 Visual Studio 2019 创建一个 Web项目的时候,csproj 文件却是这样子的:
1 | <Project Sdk="Microsoft.NET.Sdk.Web"> |
为何内容如此不同,感觉这一篇的内容都白学了,有没有~
参考资料
https://www.cnblogs.com/linianhui/archive/2012/08/30/2662648.html
https://docs.microsoft.com/zh-cn/visualstudio/msbuild/walkthrough-creating-an-msbuild-project-file-from-scratch?view=vs-2019
https://docs.microsoft.com/zh-cn/visualstudio/msbuild/msbuild?view=vs-2019