Essential MSBuild: .NET 工具生成引擎概述

过去几年大家一直都在使用 .NET Core(有这么久吗?)并且都知道“生成系统”经历了重大改变,不论是终止对 Gulp 的内置支持,还是放弃 Project.json。对于我这个专栏作家来说,这些变化一直很棘手,因为我不想我亲爱的读者花了很多时间来了解这些功能和详情,最后却只能使用短短几个月。这就是为什么我所有的 .NET Core 相关文章都以基于 Visual Studio .NET 4.6 的 *.CSPROJ 文件为基础撰写,这些文件引用 .NET Core 中的 NuGet 包,而非实际编译的 .NET Core 项目。

本月,我很荣幸向大家宣布 .NET Core 项目的项目文件已经确定为(你会相信吗) MSBuild 文件。但这是与前几代 Visual Studio 不同的 MSBuild 文件,是经过改进和简化的 MSBuild 文件。这是一个包括 Project.json 所有功能(而不陷入波形括号与尖括号的宗教战争),但是配备自 Visual Studio 2005 以来我们知晓(并且可能喜爱?)的传统 MSBuild 文件的工具支持的文件。总之,这些功能包括开源、跨平台兼容性、简化的人类可编辑的格式以及完全现代的 .NET 工具支持(包括通配符文件引用)。

工具支持

要清楚,MSBuild 始终支持通配符等功能,但是现在 Visual Studio 工具也同样支持。换句话说,MSBuild 最大的亮点在于它被紧密集成为所有新 .NET 工具—DotNet.exe、Visual Studio 2017、Visual Studio Code 和 Visual Studio for Mac—的生成系统基础并且支持 .NET Core 1.0 和 .NET Core 1.1 运行时。

.NET 工具和 MSBuild 之间强大耦合的巨大优势在于你创建的任何 MSBuild 文件与所有 .NET 工具兼容,并且可从任何系统生成。

用于 MSBuild 集成的 .NET 工具通过 MSBuild API 而非命令行过程耦合。例如,执行 .NET CLI command Dotnet.exe Build 不会在内部生成 msbuild.exe 过程。但是,这不会调用过程中的 MSBuild API 来执行工作(MSBuild.dll 和 Microsoft.Build.* 程序集)。即便如此,不论工具如何,输出在各平台之间均相似,因为存在共享的日志记录框架,所有 .NET 工具均在其中注册。

*.CSPROJ/MSBuild 文件结构

正如我所提到的,文件格式本身被简化为极简。它支持通配符、项目和 NuGet 包引用以及多个框架。此外,在 Visual Studio 过去创建的项目文件中发现的项目类型 GUID 已经消失。

图 1 显示 *.CSPROJ/MSBuild 文件示例。

图 1 CSProj/MSBuild 文件基本示例

<Project>  <PropertyGroup>    <TargetFramework>netcoreapp1.0</TargetFramework>  </PropertyGroup>  <ItemGroup>    <Compile Include="**\*.cs" />    <EmbeddedResource Include="**\*.resx" />  </ItemGroup>  <ItemGroup>    <PackageReference Include="Microsoft.NETCore.App">      <Version>1.0.1</Version>    </PackageReference>    <PackageReference Include="Microsoft.NET.Sdk">      <Version>1.0.0-*</Version>      <PrivateAssets>All</PrivateAssets>    </PackageReference>  </ItemGroup>  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /></Project>

让我们来详细地回顾下结构和功能:

简化了的标头: 首先要注意的是根元素仅仅是一个项目元素。甚至对命名空间和版本属性的需要也已经消失:

ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"

(尽管它们是通过候选发布版本工具创建的。)  同样地,甚至导入常见属性的需要也是可选的:

<Import Project=  "$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" />

项目引用: 从项目文件可以将条目添加到项目组元素:

  • NuGet 包:

<PackageReference Include="Microsoft.Extensions.Configuration">  <Version>1.1.0</Version></PackageReference>
  • 项目引用:

<ProjectReference Include="..\ClassLibrary\ClassLibrary.csproj" />
  • 程序集引用:

<Reference Include="MSBuild">  <HintPath>...</HintPath></Reference>

直接的程序集引用应该属于例外情况,因为通常优先采用 NuGet 引用。

通配符包括: 可以通过通配符将编译的代码文件和资源文件均包括在内。

<Compile Include="**\*.cs" /><EmbeddedResource Include="**\*.resx" /><Compile Remove="CodeTemplates\**" /><EmbeddedResource Remove="CodeTemplates\**" />

但是,你仍可使用删除属性选择要忽略的特定文件。(注意对通配符的支持很多时候被称为通配。)

多重目标: 要找出你所针对的平台,可以使用属性组、TargetFramework 元素以及输出类型(可选):

<PropertyGroup>  <TargetFramework>netcoreapp1.0</TargetFramework>  <TargetFramework>netstandard1.3</TargetFramework></PropertyGroup>

鉴于这些条目,每个目标的输出将被生成到 bin\Debug or bin\Release 目录(取决于你指定的配置)。如果目标不止一个,则生成执行会将输出置于与目标框架名称对应的文件夹中。

无项目类型 GUID: 注意不再需要包括识别项目类型的项目类型 GUID。

Visual Studio 2017 集成

至于 Visual Studio 2017,Microsoft 继续提供用于编辑 CSPROJ/MSBuild 项目文件的富 UI。例如,图 2 显示了使用 CSPROJ 文件列表加载的 Visual Studio 2017,它在图 1 的基础上稍做修改,包括 netcoreapp1.0 和 net45 的目标框架元素、Microsoft.Extensions.Configuration、Microsoft.NETCore.App 和 Microsoft.NET.Sdk 的包引用以及对 MSBuild 的程序集引用和对 SampleLib 的项目引用。                                                                                                           

 
图 2 解决方案资源管理器是基于 CSProj 文件的富 UI

注意在解决方案资源管理器中的依赖项树中,每个依赖项类型—程序集、NuGet 包或项目引用—如何拥有相应的组节点。

此外,Visual Studio 2017 支持项目和解决方案的动态重新加载。例如,如果新文件被加载到项目目录—与其中一个通配符相匹配的目录—Visual Studio 2017 会自动检测更改并在解决方案资源管理器中显示文件。同样地,如果你从 Visual Studio 项目排除一个文件(通过 Visual Studio 菜单选项或 Visual Studio 属性窗口),Visual Studio 将相应地自动更新项目文件。(例如,它将添加一个 <Compile Remove="CommandLine.cs" /> 元素来避免编译项目中的 CommandLine.cs 文件。) 

此外,将自动检测对项目文件的编辑并将其重新加载到 Visual Studio 2017。事实上,解决方案资源管理器中的 Visual Studio 项目节点现在支持内置编辑 <Project File> 菜单选项,通过此选项可在 Visual Studio 编辑窗口中打开项目文件,而无需首先请求卸载项目。

还支持在 Visual Studio 2017 中进行内置迁移,将项目转换为新的 MSBuild 格式。如果你接受其提示,你的项目将自动从 Project.json/*.XPROJ 类型升级到 MSBUILD/*.CSPROJ 类型。注意此类升级将破坏与 Visual Studio 2015 .NET Core 的向后兼容性,所以在他人使用 Visual Studio 2015 的同时,不能让团队成员在 Visual Studio 2017 中处理同一个 .NET Core 项目。

MSBuild

有一点需要提醒你注意的是,2016 年 3 月,Microsoft 在 GitHub 上将 MSBuild 发布为开源 (github.com/Microsoft/msbuild) 并将其贡献给了 .NET Foundation (dotnetfoundation.org)。对于到 Mac 和 Linux 的平台可移植性,将 MSBuild 设为开源有利于回到正轨,最终允许其成为所有 .NET 工具的基础生成引擎。

与之前发现的 CSPROJ\MSBuild 文件 PackageReference 元素不同,MSBuild 版本 15 除了开源和跨平台未引入太多其他功能。实际上,通过比较命令行帮助,结果显示选项相同。对于那些尚不熟悉它的人来说,下面列出了你应熟悉的 syntax MSBuild.exe [options] [project file] 的最常用选项:

/target:<target>:在项目文件中找出要与其可能拥有的任何依赖项一起执行的生成目标(缩写为 /t)。

/property:<n>=<v>: 设置或替代任何项目属性(在项目文件的 ProjectGroup 元素中找到)。例如,你可以使用该属性来更改配置或输出目录,如在 /property:Configuration=Release;OutDir=bin\ 中(缩写为 /p)。

/maxcpucount[:n]: 指定要使用的 CPU 的数量。默认情况下,msbuild 在单个 CPU 上运行(单线程)。如果可以同步的话,则可以通过指定并发级别来增加数量。如果在不提供值的情况下指定 /maxcpucount 选项,msbuild 将使用计算机上的处理器数量。

/preprocess[:file]: 通过初始化所有包含的目标来生成聚合的项目文件。这样在出现问题时有利于调试。

@file: 提供一个(或多个)包含选项的响应文件。此类文件在单独的行上拥有命令行选项(注释要添加“#”前缀)。默认情况下,MSBuild 将从生成的第一个项目或解决方案导入名为 msbuild.rsp 的文件。响应文件有助于找出不同的生成属性和目标,具体取决于生成的环境(研发、测试、生产)等。

Dotnet.exe

大约一年前引入了 .NET 的 dotnet.exe 命令行并将其作为生成、构建和运行基于 .NET Core 的项目的跨平台机制。正如我所提到的,dotnet.exe 已经得到更新,现在很大程度上依赖于MSBuild 作为内部引擎来在可行的情况下处理大量工作。

以下是对各种命令的概述:

dotnet new: 创建你的初始项目。此项目生成器开箱即用,支持 Console、Web、Lib、MSTest 和 XUnitTest 项目类型。但是将来有望提供自定义模板,从而能够生成你自己的项目类型。(这一功能可用时,新的命令将不再依赖于 MSBuild 生成项目。)

dotnet restore: 读取在项目文件中指定的项目依赖项并下载任何缺失的 NuGet 包和其中发现的工具。项目文件本身可以被指定为参数或从当前目录暗示(如果当前目录中的项目文件不止一个,则要求指定要使用哪个)。注意因为恢复利用 MSBuild 引擎处理工作,所以 dotnet 命令允许其他 MSBuild 命令行选项。

dotnet build: 在项目文件中调用 MSBuild 引擎执行生成目标(默认情况下)。如同恢复命令一样,你可以将 MSBuild 参数传递到 dotnet 生成命令。例如,命令 dotnet build /property:configuration=Release 将触发要输出的 Release 生成,而不是 Debug 生成(默认情况下)。同样地,你可以使用 /target(或 /t)指定 MSBuild 目标。例如,dotnet build /t:compile 命令将运行编译目标。

dotnet clean: 删除所有生成输出,以便执行完全生成而非增量生成。

dotnet migrate: 将基于 Project.json/*.XPROJ 的项目升级为 *.CSPROJ/MSBuild 格式。

dotnet publish: 连同任何依赖项将所有生成输出组合到单个文件夹,从而将其暂存以部署到另一台计算机。这对不仅包含编译输出和依赖包,而且包含 .NET Core 运行时本身的自包含部署来说尤其有用。自包含应用程序没有设定特定版本的 .NET 平台已经安装到了目标计算机上的任何前提条件。

dotnet run: 启动 .NET 运行时并托管项目和/或编译的程序集以执行你的程序。注意对于 ASP.NET 来说,编译并不如可以托管项目本身一样必要。

在执行 msbuild.exe 和 dotnet.exe 之间存在重大重叠,需要你选择运行哪个。如果你生成的是默认 msbuild 目标,则仅可从项目目录内执行命令“msbuild.exe”,它将为你编译并输出目标。等同的 dotnet.exe 命令为“otnet.exe msbuild”。 另一方面,如果你运行的是“清理”目标,则命令是“msbuild.exe /t:clean”(对于 MSBuild)和“dotnet.exe clean”(对于 dotnet)。此外,两个工具均支持扩展名。MSBuild 拥有在项目文件本身内和通过 .NET 程序集的综合性扩展性框架(请参阅 bit.ly/2flUBza)。同样地,可以扩展 dotnet,但对此的建议基本都涉及扩展 MSBuild 和一些规定的步骤。

虽然我喜欢 dotnet.exe 这个想法,但是最后它似乎未提供太多的 MSBuild 优势,MSBuild 不支持的除外(其中 dotnet new 和 dotnet run 可能是最重要的)。最后,我认为通过 MSBuild,可以轻松地执行简单的操作,同时在需要时仍可执行复杂的操作。此外,通过提供合理的默认值,即使是 MSBuild 中复杂的操作也可以被简化。最后,是 dotnet 还是 MSBuild 更可取由个人喜好决定,而时间将会告诉我们通常会为 CLI 前端选用哪个开发社区。

global.json:

虽然 Project.json 功能已迁移到 CSPROJ,但仍完全支持 global.json。文件允许指定项目目录和包目录并识别要使用的 SDK 版本。下面是 global.json 文件的示例:

{"projects": [ "src", "test" ],"packages": "packages","sdk": {"version": "1.0.0-preview3","runtime": "clr","architecture": "x64"  }
}

有三个部分与 global.json 文件的主要目的一致:

projects: 识别 .NET 项目所在的根目录。项目节点对于调试 .NET Core 源代码来说极为关键。在克隆源代码后,你可以将目录添加到项目节点,然后 Visual Studio 将在解决方案中自动将其作为项目上载。

packages: 指示 NuGet 包文件夹的位置。

sdk: 指定要使用的运行时的版本。

总结

在本文中,我宽泛地概述了在 .NET 工具套件中使用 MSBuild 的所有情形。结束之前,请允许我基于我使用成千上万行 MSBuild 处理项目的经验,为大家提供些许建议。别落入使用 XML MSBuild 架构等松散类型声明性语言编写脚本的圈套。这不是它的用途。项目文件应该是相对较薄的包装器,能够识别生成目标之间的顺序和依赖项。如果你的 MSBuild 项目文件太大,那么维护起来可能会比较痛苦。请勿耽搁太久,立即将其重构为可调试和可轻松通过装置测试的 C# MSBuild 任务。

原文地址:https://msdn.microsoft.com/zh-cn/magazine/mt791801


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/326808.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单片机中存储器扩展位地址线怎么算_51单片机存储器小结

存储器分为程序存储器(ROM)和数据存储器(RAM)&#xff0c;两种又都可以分为片内和片外&#xff0c;片外即需要自己在单片机外部扩展。8051单片机的片内程序存储器有4K&#xff0c;片内数据存储器有256个字节&#xff0c;其中又分为高128字节位特殊功能寄存器区&#xff0c;真正…

[Java]对double变量进行四舍五入,并保留小数点后位数

[Java]对double变量进行四舍五入&#xff0c;并保留小数点后位数 - 雾霾王者 - 博客园 [Java]对double变量进行四舍五入&#xff0c;并保留小数点后位数 1.功能 将double类型变量进行四舍五入&#xff0c;并保留小数点后位数 2.代码 import java.math.BigDecimal; import ja…

尊贵豪礼:微软2017最有价值专家MVP奖套件开箱图集

IT之家编者按&#xff1a;台湾省某科技网站站长获得了微软2017年度最有价值专家&#xff08;Most Valuable Professional&#xff0c;MVP&#xff09;奖&#xff0c;得奖的领域则是 Windows and Devices for IT。这位站长于是就展示了这份MVP的礼包开箱&#xff0c;从照片上看&…

echart vue 图表大小_vue之将echart封装为组件

最近的新项目里&#xff0c;有大量数据图表类的需求&#xff0c;为了增强代码的复用性&#xff0c;减少冗余&#xff0c;我开始思考如何将echart封装为组件调用。本文将会以雷达图为案例&#xff0c;一步步讲解在vue项目中如何使用echart&#xff0c;如何将其封装为能重复调用的…

个性化配置你的SQL Server on Linux

问题引入 这天老鸟满面春风找到菜鸟&#xff1a;“鸟儿啊&#xff0c;看你最近研究SQL Server On Linux如鱼得水&#xff0c;干得不错啊。不过呢&#xff0c;这是一个张扬个性的年代&#xff0c;要创新&#xff0c;要与众不同&#xff0c;那你怎么在Linux平台对SQL Server做个性…

idea查看读取的那个nacos配置和yaml配置 naocos 日志

logging.level.com.alibaba.cloud.nacos.client.NacosPropertySourceBuilderdebug

二叉树的前中后序查找+思路分析

思路分析 代码实现 package com.atguigu.tree;/*** 创建人 wdl* 创建时间 2021/3/24* 描述*/ public class BinaryTreeDemo {public static void main(String[] args) {//先需要创建一颗二叉树BinaryTree binaryTree new BinaryTree();//创建需要的节点HeroNode root new He…

spark sql uv_使用Spark Streaming SQL进行PV/UV统计

作者&#xff1a;关文选&#xff0c;花名云魄&#xff0c;阿里云E-MapReduce 高级开发工程师&#xff0c;专注于流式计算&#xff0c;Spark Contributor1.背景介绍PV/UV统计是流式分析一个常见的场景。通过PV可以对访问的网站做流量或热点分析&#xff0c;例如广告主可以通过PV…

二叉树删除节点+思路分析

思路分析 代码实现 ![在这里插入代码片](https://img-blog.csdnimg.cn/20210325193201194.png?x-oss-processimage/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1NzgzNjYw,size_16,color_FFFFFF,t_70)

ddm模型公式_简单判断目前行情——从股利贴现模型切入

本文目录&#xff1a;1.介绍股利贴现模型&#xff1b;2.以贵州茅台为例根据现有情况估计模型内部各参数&#xff1b;3.得出结论&#xff1b;一、股利贴现模型&#xff08;DDM&#xff09;我们知道给一项资产定价最朴素的想法是将它未来产生的所有现金流以一定的贴现率贴现至当前…

分布式事务与一致性算法Paxos amp; raft amp; zab

1.CAP原理 要想数据高可用&#xff0c;就得写多份数据写多分数据就会导致数据一致性问题数据一致性问题会引起性能问题 2.一致性模型 弱一致性最终一致性&#xff08;一段时间达到一致性&#xff09;强一致 1、2 异步冗余&#xff1b;3是同步冗余 3. 扩展服务的方案 数据分区&…

打开数据库_数据库客户端navicat遇到问题怎么办?

前面的文章介绍了&#xff1a;mysql数据库如何安装&#xff0c;客户端navicat如何安装。下面是客户端navicat使用过程中常见问题的解决办法。【问】使用navicat连接数据库报错信息&#xff1a;12511251Client does not support authentication protocol requested by server,co…

遍历线索化二叉树+图解

图解 代码实现 package com.atguigu.tree.threadedbinarytree;/*** 创建人 wdl* 创建时间 2021/3/25* 描述*/ public class ThreadedBinaryTreeDemo {public static void main(String[] args) {//测试一把中序线索化二叉树的功能HeroNode root new HeroNode(1, "tom&quo…

JS实现星星评分功能实例代码(两种方法)

转载自 JS实现星星评分功能实例代码(两种方法) 一、方法1 1、用到图片 2、结构和样式 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title><style>ul {padding-left: 0;…

SQL on Linux Run on Docker

摘要 SQL Server 2016以及SQL on Linux版本已经支持跑在Docker容器中&#xff0c;也展示微软拥抱开源的决心和勇气。这篇博文就是以SQL on Linux为例&#xff0c;看看如何将SQL Server实例部署在Docker容器中。 背景 大概在两个月之前&#xff0c;在SQL On Linux刚发布预览版本…

三条中线分的六个三角形_八年级数学上册:三角形已知两条边如何求第三边

三角形一、定义&#xff1a;由不在同一条直线上的三条线段首尾顺次相接所组成的平面图形叫做三角形。1、三角形的内角&#xff1a;三角形的没两条边所组成的角叫做三角形的内角2、三角形的外角&#xff1a;三角形的任意一边与另一边的反向延长线所组成的角叫做三角形的外角。二…

Xamarin的坑 - 绑定(二) - 高德iOS SDK(.Framework)绑定的一些事

编者语&#xff1a;入门总是用一个hello world&#xff0c;总会让人觉得写code会是很容易的事。开篇绑定了一下微信SDK,不会有太多的难点&#xff0c;可是接下来的这个例子如果欠缺一些耐心&#xff0c;估计你整个人就崩溃了(我从来不会放弃任何的事)。ps这里得谢谢CSDN回帖的人…

android 监听安装来源_Flutter插件开发之APK自动安装

点击上方的终端研发部&#xff0c;右上角选择“设为星标”每日早9点半&#xff0c;技术文章准时送上公众号后台回复“学习”&#xff0c;获取作者独家秘制精品资料往期文章记五月的一个Android面试经今日头条屏幕适配方案落地研究图解算法&#xff1a;说一道字节跳动的算法题除…

JavaScript学习总结(一)——JavaScript基础

转载自 JavaScript学习总结(一)——JavaScript基础 一、JavaScript语言特点 1.1、JavaScript是基于对象和事件驱动的(动态的) 它可以直接对用户或客户输入做出响应&#xff0c;无须经过Web服务程序。它对用户的响应&#xff0c;是采用以事件驱动的方式进行的。所谓事件驱动…

idea下使用springinitializr创建项目时 初始化失败的解决

idea自带的地址无使用使用阿里的就可以了 idea下使用springinitializr创建项目时 初始化失败的解决 周山 关注 2020.08.05 13:32:26字数 10阅读 1,085 image.png 修改初始化创建时Custom处 https://start.aliyun.com/ image.png