当前位置: 首页 > news >正文

如何编写基于 Microsoft.NET.Sdk 的跨平台的 MSBuild Target(附各种自带的 Task)

我之前写过一篇 理解 C# 项目 csproj 文件格式的本质和编译流程,其中,Target 节点就是负责编译流程的最关键的节点。但因为篇幅限制,那篇文章不便详说。于是,我在本文说说 Target 节点。


本文内容

    • Target 的节点结构
    • Target 执行的时机和先后顺序
    • Microsoft.NET.Sdk 为我们提供的现成可用的 Task
    • 使用自己写的 Task
    • 差量编译

Target 的节点结构

<Target> 内部几乎有着跟 <Project> 一样的节点结构,内部也可以放 PropertyGroupItemGroup,不过还能放更加厉害的 Task。按照惯例,我依然用思维导图将节点结构进行了总结:

在这里插入图片描述
▲ 上面有绿线和蓝线区分,仅仅是因为出现了交叉,怕出现理解歧义

<Hash><WriteCodeFragment> 都是 Task。我们可以看到,Task 是多种多样的,它可以占用一个 xml 节点。而本例中,WriteCodeFragment Task 就是生成代码文件,并且将生成的文件作为一项 Compile 的 Item 和 FileWrites 的 Item。在 理解 C# 项目 csproj 文件格式的本质和编译流程 中我们提到 ItemGroup 的节点,其作用由 Target 指定。所有 Compile 会在名为 CoreCompileTarget 中使用,而 FileWrites 在 Microsoft.NET.Sdk 的多处都生成了这样的节点,不过目前从我查看到的全部 Microsoft.NET.Sdk 中,发现内部并没有使用它。

Target 执行的时机和先后顺序

既然 <Target> 内部节点很大部分跟 <Project> 一样,那区别在哪里呢?<Project> 里的 <PropertyGroup><ItemGroup> 是静态的状态,如果使用 Visual Studio 打开项目,那么所有的状态将会直接在 Visual Studio 的项目文件列表和项目属性中显示;而 <Target> 内部的 <PropertyGroup><ItemGroup> 是在编译期间动态生成的,不会在 Visual Studio 中显示;不过,它为我们提供了一种在编译期间动态生成文件或属性的能力。

总结起来就是——Target 是在编译期间执行的

不过,同样是编译期间,那么多个 Target,它们之间的执行时机是怎么确定的呢?

一共有五个属性决定了 Target 之间的执行顺序:

  • Project 的属性
    • InitialTargets 项目初始化的时候应该执行的 Target
    • DefaultTargets 如果没有指定执行的 Target,那么这个属性将指定执行的 Target
  • Target 的属性
    • DependsOnTargets 在执行此 Target 之前应该执行的另一个或多个 Target
    • BeforeTargets 这是 MSBuild 4.0 新增的,指定应该在另一个或多个 Target 之前执行
    • AfterTargets 这也是 MSBuild 4.0 新增的,指定应该在另一个或多个 Target 之后执行

通过指定这些属性,我们的 Target 能够被 MSBuild 自动选择合适的顺序进行执行。例如,当我们希望自定义版本号,那么就需要赶在我们此前提到的 GenerateAssemblyInfo 之前执行。

Microsoft.NET.Sdk 为我们提供的现成可用的 Task

有 Microsoft.NET.Sdk 的帮助,我们可以很容易地编写自己的 Target,因为很多功能它都帮我们实现好了,我们排列组合一下就好。

  • Copy 复制文件 Rosyln 如何使用 MSBuild Copy 复制文件
  • Move 移动文件 Move Task
  • Delete 删除文件
  • Message 显示一个输出信息(我在 如何创建一个基于 MSBuild Task 的跨平台的 NuGet 工具包 中利用这个进行调试)
  • Warning 显示一个警告信息
  • Error 报错(这样,编译就会以错误结束)
  • CombinePath, ConvertToAbsolutePath 拼接路径,转成绝对路径
  • CreateItem, CreateProperty 创建项或者属性
  • Csc 调用 csc.exe 编译 Csc Task
  • MSBuild 编译一个项目 MSBuild Task
  • Exec 执行一个外部命令(我在 如何创建一个基于命令行工具的跨平台的 NuGet 工具包 一文中利用到了这个 Task 执行命令)
  • WriteCodeFragment 生成一段代码 WriteCodeFragment Task
  • WriteLinesToFile 向文件中写文字 WriteLinesToFile Task

提供的 Task 还有更多,如果上面不够你写出想要的功能,可以移步至官方文档翻阅:MSBuild Task Reference - Visual Studio - Microsoft Docs。

使用自己写的 Task

我有另外的一篇文章来介绍如何创建一个基于 MSBuild Task 的跨平台的 NuGet 工具包 - 吕毅。如果希望自己写 Ta

差量编译

如果你认为自己写的 Target 执行比较耗时,那么就可以使用差量编译。我另写了一篇文章专门来说 Target 的差量编译:每次都要重新编译?太慢!让跨平台的 MSBuild/dotnet build 的 Target 支持差量编译 - 吕毅。


参考资料

  • Target Build Order - Visual Studio - Microsoft Docs
  • MSBuild Task Reference - Visual Studio - Microsoft Docs

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • 让你编写的控件库在 XAML 中有一个统一的漂亮的命名空间(xmlns)和命名空间前缀
  • Sdk 风格的 csproj 对 WPF/UWP 支持不太好?有第三方 SDK 可以用!MSBuild.Sdk.Extras
  • 为博客或个人站点的 Markdown 添加 LaTeX 公式支持
  • 如何让 .NET Core 命令行程序接受密码的输入而不显示密码明文
  • 如何编写 WPF 的标记扩展 MarkupExtension,即便在 ControlTemplate/DataTemplate 中也能生效
  • PasswordVault —— 在 UWP 应用中安全地保存密码
  • 如何在 MSBuild Target(Exec)中报告编译错误和编译警告
  • 将 .NET Core 项目打一个最简单的 NuGet 源码包,安装此包就像直接把源码放进项目一样
  • 使用 LINQ to XML,.NET 让生成 XML 文件变得和直接写 XML 一样轻松
  • git subtree 不断增加的推送时间,解不玩的冲突!这篇文章应该能救你
  • 阻止某个 NuGet 包意外升级
  • 解读 Microsoft.NET.Sdk 的源码,你能定制各种奇怪而富有创意的编译过程
  • 在 Visual Studio 的解决方案资源管理器中隐藏一些文件
  • 长期支持 LTS(Long-term Support)是怎样的一种支持方式
  • .NET Standard 的管理策略
  • [nginx文档翻译系列] 控制nginx
  • 【React系列】如何构建React应用程序
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • CAP理论的例子讲解
  • CentOS 7 修改主机名
  • Consul Config 使用Git做版本控制的实现
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • CSS居中完全指南——构建CSS居中决策树
  • Java多态
  • js 实现textarea输入字数提示
  • PaddlePaddle-GitHub的正确打开姿势
  • PhantomJS 安装
  • Python连接Oracle
  • redis学习笔记(三):列表、集合、有序集合
  • 基于Android乐音识别(2)
  • 技术发展面试
  • 面试总结JavaScript篇
  • 使用 QuickBI 搭建酷炫可视化分析
  • 收藏好这篇,别再只说“数据劫持”了
  • 微信小程序:实现悬浮返回和分享按钮
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • (3)选择元素——(17)练习(Exercises)
  • (AngularJS)Angular 控制器之间通信初探
  • (第61天)多租户架构(CDB/PDB)
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (剑指Offer)面试题34:丑数
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (四)Linux Shell编程——输入输出重定向
  • (转)创业的注意事项
  • ******IT公司面试题汇总+优秀技术博客汇总
  • *上位机的定义
  • [.NET]桃源网络硬盘 v7.4
  • [《百万宝贝》观后]To be or not to be?
  • [ARC066F]Contest with Drinks Hard
  • [AutoSAR 存储] 汽车智能座舱的存储需求
  • [C++] 默认构造函数、参数化构造函数、拷贝构造函数、移动构造函数及其使用案例
  • [C++随笔录] 红黑树
  • [codevs] 1029 遍历问题
  • [Excel]如何找到非固定空白格數列的條件數據? 以月份報價表單為例