MSBuild 如何决定是不是需要重建 C# 库?

Posted

技术标签:

【中文标题】MSBuild 如何决定是不是需要重建 C# 库?【英文标题】:How does MSBuild decide whether it needs to rebuild a C# library or not?MSBuild 如何决定是否需要重建 C# 库? 【发布时间】:2011-07-02 04:23:03 【问题描述】:

在针对 C# 项目文件运行时,MSBuild 如何决定是否需要重新构建库(即调用 csc)?

我想(但想确认):

如果没有输出目录,请重建 (duh :)) 如果 C# 文件已更改,请重建 如果标记为始终复制的包含文件已更改,请重建 或者它足够聪明而不重建,而只是将文件复制到现有输出? 如果标记为 copy-if-newer 的包含文件已更改,请重新构建 与上述相同的问题

【问题讨论】:

【参考方案1】:

如果您查看 Microsoft.CSharp.targets(用于编译 C# 项目的 MSBuild 文件),CoreCompile 目标定义了一组输入和输出。这些用于执行依赖关系检查以查看 CoreCompile 是否需要运行。输入列表包括 C# 文件、资源文件、应用程序图标、强名称密钥文件以及您可以定义的其他自定义输入。

如果您有解决方案并在其上运行 MSBuild 并启用诊断日志记录(/v:diag 命令行参数),如果输出是最新的,您可能会看到此消息:

跳过目标“CoreCompile”,因为 所有输出文件都是最新的 关于输入文件。

目标文件位于 .NET Framework 目录 (C:\windows\Microsoft.NET\Framework\v3.5 or v4.0.30319)。

【讨论】:

【参考方案2】:

MSBuild 具有执行此操作的内置功能。

Target 有两个属性,InputsOutputs

每当Input 更改或Output 更旧或丢失时,都会执行Target

【讨论】:

【参考方案3】:

问题是,任何听起来似乎合理的启发式方法都可能不会削减它。当你要求你的编译器(构建系统)产生一个输出时,你最好保证输出是你所期望的。

据我所知,MSBuild 不这样做。它总是重建(从头开始)整个解决方案/项目。但是,当从 Visual Studio 中调用 MSBuild 时,临时编译单元会保留在项目的 \obj 文件夹中。清空该文件夹与重建相同。

也就是说,如果编译器或构建系统要重用输出,它将使用实际文件内容的校验和来确定是否可以从其他地方检索已编译的输出。这基本上是您可以确定文件是否真的需要从头开始重新编译的唯一可靠方法。 仅供参考,这是由 Visual C# 编译器完成的,而不是 MSBuild。

文件系统的“最后修改日期”属性不会是跨系统一致的,因此最终不会用于确定是使用缓存输出构建还是从头开始构建。

【讨论】:

我想这可以解释为什么依赖检查这么慢。你有关于编译器使用校验和的声明的参考吗? 我可能一直在那儿冒险,我不确定我是如何得出这个结论的。我能找到的唯一参考是:msdn.microsoft.com/en-us/library/ms173226.aspx,它明确指出这些校验和由调试器使用,而不是编译器或 MSBuild。我可能在这件事上错了……

以上是关于MSBuild 如何决定是不是需要重建 C# 库?的主要内容,如果未能解决你的问题,请参考以下文章

在 MSBuild 中确定 ProjectReference 的输出而不触发冗余重建

Visual Studio 在构建、重建和清理解决方案时使用啥 dotnet core cli 命令(或 msbuild 命令)?

如何将 msbuild 升级到 C# 6?

Roslyn 如何使用 MSBuild Copy 复制文件

msbuild 中动态生成的 C# 文件的问题

从命令行仅在解决方案中构建一个项目