每次都要重新编译?太慢!让跨平台的 MSBuild/dotnet build 的 Target 支持差量编译
如果你干预到了项目的编译过程,可能就需要考虑到差量编译了。不然——当你的项目大起来的时候,就会感受到每次都重新编译时,每次重复调试的过程都要进行漫长等待时的绝望和无奈。
如果你正遭遇差量编译失效,每次都要重新编译的问题,那么阅读本文应该能够帮助你解决问题。
msbuild.exe
和 dotnet build
编译项目的方式是一样的,只不过前者使用完整的 .NET Framework,而后者使用 .NET Core。所以后面我们说到 Target 的差量编译的时候,就不再区分这两者了。
一个差量编译的例子
先看一个 Target
的例子,这里例子来源于我的另一篇文章如何创建一个基于 MSBuild Task 的跨平台的 NuGet 工具包 - 吕毅。在例子中,我没有加入任何的差量编译支持。
<Target Name="WalterlvDemo" BeforeTargets="CoreCompile">
<DemoTool IntermediateOutputPath="$(IntermediateOutputPath)">
<Output TaskParameter="AdditionalCompileFile" PropertyName="WalterlvDemo_AdditionalCompileFile" />
</DemoTool>
<ItemGroup>
<Compile Include="$(WalterlvDemo_AdditionalCompileFile)" />
</ItemGroup>
</Target>
上述例子的作用是在编译期间执行一个名为 DemoTool
的 Task
,在 Task
执行结束之后,将生成的临时文件 $(WalterlvDemo_AdditionalCompileFile)
加入编译。
如果你觉得上面的写法非常陌生,或者说不清楚那个 Target
节点的作用,建议先阅读:
差量编译的关键
每一个 Target
都有 Inputs
和 Outputs
属性,可以设置,也可以不用设置。
当没有指定时,MSBuild 会认定为此 Target
在每次编译时都会执行;当指定时,MSBuild 会认定为此 Target
需要进行差量执行。不存在只指定其中一个而不指定另一个的情况——MSBuild 直接会提示此 Target 没有正确指定 Inputs
和 Outputs
Inputs
和 Outputs
的格式都是一组用 ;
分隔的字符串,每一项都是一个文件的路径。不过不用特别考虑如何使用 ;
拼接,因为当我们使用 @
符号时,收集到的每一项便是使用 ;
分隔的。例如 @(Compile)
表示在 <ItemGroup>
中每一个 Compile
类型的节点。如果不清楚 <ItemGroup>
和 <Compile>
的作用,建议建议先阅读理解 C# 项目 csproj 文件格式的本质和编译流程 - 吕毅。
假设我们指定 Inputs
为 @(Compile)
,Outputs
指定为某个 xxx.exe 生成的临时文件的位置(在 如何创建一个基于命令行工具的跨平台的 NuGet 工具包 一文中,我假定为了 $(IntermediateOutputPath)Doubi.cs
),那么 MSBuild 就会在执行此 Target 之前检查所有这些输入输出文件。如果所有 <Compile>
节点中对应的文件都没有改变,而且 $(IntermediateOutputPath)Doubi.cs
存在且没改变,那么此 Target
将不需要执行。任何一个文件不满足此条件,则 Target
都将重新执行。
现在,回到我们刚开始的例子,你觉得如何设置 Inputs
和 Outputs
可以获得最佳的差量编译效果呢?答案是——Inputs
设置为空字符串(因为我们没有输入文件),Outputs
设置为 $(WalterlvDemo_AdditionalCompileFile)
应该有的值(特别注意:我指的是这个属性对应的值,而不是属性本身——因为此属性的值在编译之前不能确认,也就无法进行差量分析)。
不是所有的 Target 都适合差量编译
注意!不是所有的 Target
都适合设置 Inputs
和 Outputs
属性!
在本文前面的例子中,我们的 Target
是有明确的输入和输出文件的;然而有些 Target
是没有输入输出文件的——他们的输出依赖于其他 Target 的输出。
例如我们有另一个 <Target>
,它的作用是生成一个属性的值,或者一组文件的名字;而另外一个 <Target>
使用这个属性的值和这组文件。典型的例子如我在如何创建一个基于命令行工具的跨平台的 NuGet 工具包 中写的那个 NuGet 工具。
<Target Name="WalterlvDemo" BeforeTargets="CoreCompile">
<Exec Command="dotnet $(NuGetWalterlvToolPath) -i $(IntermediateOutputPath)Doubi.cs" />
</Target>
<Target Name="WalterlvDemoUseResult" AfterTargets="WalterlvDemo" BeforeTargets="CoreCompile">
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)Doubi.cs" />
</ItemGroup>
</Target>
WalterlvDemo
生成文件,而 WalterlvDemoUseResult
使用文件。这时,WalterlvDemo
适合使用差量编译,而 WalterlvDemoUseResult
却不适合!
因为前者已经生成了文件,如果不执行,文件依然存在;但后者一旦不执行,那么我们就会少一个编译的文件。这将导致后续名为 CoreCompile
的 Target 执行时,发现少了一个文件,将重新执行编译。
所以前者的 Inputs
指定为空字符串,Outputs
指定为 $(IntermediateOutputPath)Doubi.cs
;但是后者不应该指定 Inputs
和 Outputs
。
每次都要重新编译?太慢!让跨平台的 MSBuild/dotnet build 的 Target 支持差量编译的更多相关文章
- 编写 Target 检测 MSBuild / dotnet build 此次编译是否是差量编译
MSBuild 或 Roslyn 编译项目时均支持差量编译,毕竟为了性能.我在 每次都要重新编译?太慢!让跨平台的 MSBuild/dotnet build 的 Target 支持差量编译 一文中介绍 ...
- Git push 时每次都需要密码的疑惑
2015.1.13更新: 在本地搭建Git服务器时,也是有每次操作需要密码的情况. 是因为每次做推送动作时,Git需要认证你是好人.所以需要密码. 可以在 /home/username/.ssh/au ...
- 为什么每个请求都要有用户名密码呢,那不是每次都要查询一下了,token,表示这个用户已经验证通过了,在token有效期内,只需要判断token是否有效就可以了
为什么每个请求都要有用户名密码呢,那不是每次都要查询一下了,token,表示这个用户已经验证通过了,在token有效期内,只需要判断token是否有效就可以了
- LISTVIEW嵌套GRIDVIEW的一些处理(点击GRIDVIEW的条目,能够显示他在LISTVIEW中的位置)(对这篇文章的优化处理,不每次都new onItemClickListener)
前几天写了点击GRIDVIEW的条目,能够显示他在LISTVIEW中的位置,当时的处理是在ListView的适配器里的GetView方法里每次都new GridView的onItemClickList ...
- git 设置不需要输入密码, 去除 fetch / pull 代码每次都需要输入密码的烦恼
https方式每次都要输入密码,按照如下设置即可输入一次就不用再手输入密码的困扰而且又享受https带来的极速 设置记住密码(默认15分钟): git config --global credenti ...
- 使用git提交到github,每次都要输入用户名和密码的解决方法
使用git提交文件到github,每次都要输入用户名和密码,操作起来很麻烦,以下方法可解决,记录以下. 原因:在clone 项目的时候,使用了 https方式,而不是ssh方式. 默认clone 方式 ...
- 使用git提交代码到github,每次都要输入用户名和密码的解决方法
自从使用git提交代码到github后,发现自己使用git的功力增长了不少,但也遇到不少问题.比如,使用git提交代码到github的时候,经常要求输入用户名和密码,类似这种: 网上有这么一种解决方法 ...
- Jupyter Notebook启动不会自动打开浏览器,每次都要自己打开浏览器输入网址
今天在使用jupyter 时,已启动服务,但每次都需要手动去浏览器 输入网址才可以, 最好找了好久才解决了. 去cmd 命令窗口执行jupyter notebook --generate-config ...
- 【转载】win10解决设置默认打开方式不生效问题(双击每次都要选择默认打开程序)
win10解决设置默认打开方式不生效问题(双击每次都要选择默认打开程序) 以下文章 部分选自 https://blog.csdn.net/shan165310175/article/details/8 ...
随机推荐
- mac 下测试各种IE版本
背景 作为前端开发,在谈到兼容性时不得不谈到IE浏览器,那么,如果在mac上该怎么测试各种版本的IE呢 方法 1. 下载VirtualBox虚拟器 2. 下载安装了对应版本的windows系统,htt ...
- 刷完了leetcode的数据库题目~
很久很久很久之前,我上传了几条数据库题目,并没有坚持,今天跟新一下进度吧,其实没啥难度w(* ̄︶ ̄)
- 对于"第一次创业者"应该给什么样的建议
转:其实我创业也不是很成功(目前属于第二次).目前为止,基本保证家里足够温饱和足够温馨,偶尔奢侈,但是我坚持走技术路线,不做土豪(因为做不了). 我创业的口号是:成全别人,累死自己!! 有人问 ...
- ubuntu 14.04 解决apt-get update报错
apt-get update 报如下错误: 忽略 http://cn.archive.ubuntu.com trusty-backports/multiverse Translation-zh 忽略 ...
- Mysql5.7-CentOS7安装
下载Mysql 官网地址,点击download,找到Community 选择MySQL Community Server 选择平台和版本下载即可 安装mysql 查看安装文档 在下载页面上面有安装指南 ...
- leetcode算法总结
算法思想 二分查找 贪心思想 双指针 排序 快速选择 堆排序 桶排序 搜索 BFS DFS Backtracking 分治 动态规划 分割整数 矩阵路径 斐波那契数列 最长递增子序列 最长公共子系列 ...
- UVALive-5135 Mining Your Own Business (无向图的双连通分量)
题目分析:在一张无向图中,将一些点涂上黑色,使得删掉图中任何一个点时,每个连通分量至少有一个黑点.问最少能涂几个黑点,并且在涂最少的情况下有几种方案. 题目分析:显然,一定不能涂割点.对于每一个连通分 ...
- iOS Layout机制相关方法
iOS Layout机制相关方法 - (CGSize)sizeThatFits:(CGSize)size - (void)sizeToFit ——————- - (void)layoutSubview ...
- day5-logging模块
一.概述 好的程序开发,往往会兼顾到日志输出的需求,以便给用户提供必要的日志信息便于确认程序运行状态.排错等等.这些日志一般包括程序的正常运行日志.访问日志.错误日志.数据保存日志等类型.在pytho ...
- 控制语句2:循环:for 与 while
循环是所有编程语言的必备利器,用于重复的动作等等. python中的循环有何特殊性:for 与 while 都有自己的else分支. 要学会刹车: 1.条件的控制次数 2.break 与 contin ...