Visual Studio如何知道我的项目是最新的,所以它可以跳过运行MSBuild?

时间:2016-01-30 21:25:51

标签: visual-studio msbuild visual-studio-2015

我的C ++项目中包含一个自定义MSBuild目标,它在$(OutDir)文件夹中为给定项类型的每个项目生成一个数据文件。我有一个项目类型与一个属性页面模式连接,所以你可以在解决方案资源管理器中的文件上选择它,我的目标声明输入和输出,所以增量构建工作。我还将目标添加到$(BuildDependsOn)属性中,以便在构建目标Visual Studio调用期间自动评估它。

除了一件事之外,一切似乎都有效:如果我删除$(OutDir)中的一个输出数据文件,然后构建Visual Studio什么也不做,并说我的项目是最新的。如果删除exe文件,项目生成或触摸其中一个MSBuild脚本的修改时间,Visual Studio将重新评估targ并查找输出文件丢失,导致使用我的目标重建它。

从MSBuild诊断日志记录中,似乎Visual Studio在内部维护一些输出文件和输入文件列表,它会检查以避免评估MSBuild脚本。如何将输出文件添加到此列表中?

4 个答案:

答案 0 :(得分:7)

MsBuild / VS确实有一种机制来确定输入文件的最新内容,它围绕一个可执行的tracker.exe,它扫描.tlog文件以找出项目的输出文件是什么。可能还有更多,如果你在互联网上环顾四周,你可能会得到更多关于此的信息。

但问题是你真的不需要了解它的每一个细节:在检查内置 CustomBuildStep 的工作方式时,可以找到一个简单的用法示例,并将其应用于你的情况。我将简要解释一下我是如何做到这一点的,因为我认为它对你和处理像这样的msbuild问题一样有用。

如果你添加

<ItemDefinitionGroup>
  <CustomBuildStep>
    <Command>echo foo &gt; $(OutDir)\foo.txt</Command>
    <Outputs>$(OutDir)\foo.txt</Outputs>
  </CustomBuildStep>
</ItemDefinitionGroup>

手动或通过项目的自定义构建步骤的属性页面,您将看到beahviour正是您所需要的:如果删除了foo.txt,则构建将开始,而构建将被标记如果不是最新的(好的,其余的输出也是最新的)。

因此,关键是要完成CustomBuildStep的工作,并确定这只是使用您选择的工具在下的所有文件中搜索所有 CustomBuildStep 的问题。 C:\ Program Files(x86)\ MSBuild \ Microsoft.Cpp \ v4.0 \ V120 (调整所用平台/ VS版本的路径)。

这导致我们 Microsoft.CppCommon.Targets ,其中名为CustomBuildStep的目标(请注意,与上面ItemDefinitionGroup中的条目名称相同)调用实际的CustomBuildStep命令。它也特别有趣:

<!-- Appended tlog to track custom build events -->
<WriteLinesToFile Encoding="Unicode"
  File="$(TLogLocation)$(ProjectName).write.1u.tlog"
  Lines="@(CustomBuildStep->'^%(Identity)');@(CustomBuildStep->MetaData('Outputs')->FullPath()->Distinct())"/>

因此,这将输出的路径写入跟踪器使用的目录中的.tlog文件,并使其按预期工作。根据我的经验,从^开始的行只是一个注释 - 我自己不使用它,我的自定义目标工作正常,同样的是here

tl; dr 使用WriteLinesToFile将目标输出的完整路径追加到$(TLogLocation)$(ProjectName).write.1u.tlog等文件中。我说喜欢,因为write.tlog,write.u.tlog等也可以。

答案 1 :(得分:1)

Visual Studio使用称为Visual Studio通用项目系统(CPS)(https://github.com/Microsoft/VSProjectSystem)(VS 2017)的名称 管理项目,包括构建过程。

在CPS内,可以使用任何实现IBuildUpToDateCheckProvider接口的东西 作为项目的“ UpToDateChecker”。 在调用MsBuild之前,将调用“ UpToDateChecker”。其主要目的是确定是否调用MsBuild来构建项目,或将项目标记为“最新”并始终跳过msbuild。

此“ UpToDateChecker”正是打印到诊断构建输出中的内容:

  

1> ------最新检查:项目:“ ProjectName”,配置:   调试x86 ------项目不是最新的:构建输入“ header.h”为   在生成输出“ a.out”之后进行修改。输入时间:12/27/2018 4:43:08   PM,输出时间:1/1/0001 2:00:00 AM

对于C ++项目,对于VS 2017,其默认“ UpToDateChecker”为VCProjectBuildUpToDateCheck (Microsoft.VisualStudio.Project.VisualC.VCProjectEngine.dll)。 首先,它将查看以下文件的tlogs目录(通常类似于Debug \ x86 \ .tlog之类):

  • .lastbuildstate
  • 构建失败
  • 所有' .read。 .tlog'-输入文件,在诊断版本输出中标记为'build input'
  • 所有' .write。 .tlog'-输出文件,在诊断版本输出中标记为'build output'

实际上检查更多,但是大多数失败都会在检查这4种类型时发生

答案 2 :(得分:0)

您可以通过在注册表项中启用快速更新检查器的详细信息来找出为什么要重建项目:

New-ItemProperty              `
 -Name U2DCheckVerbosity      `
 -PropertyType DWORD -Value 1 `
 -Path HKCU:\Software\Microsoft\VisualStudio\14.0\General -Force

您应该能够在构建日志消息中看到

  

项目“ Caliburn.Micro.Silverlight.Extensions”不是最新的。项目项“ C:\ dev \ projects \ Caliburn.Micro.Silverlight.Extensions \ NavigationBootstrapperSample.cs.pp”的“复制到输出目录”属性设置为“始终复制”。

[1] https://blogs.msdn.microsoft.com/kirillosenkov/2014/08/04/how-to-investigate-rebuilding-in-visual-studio-when-nothing-has-changed/

答案 3 :(得分:0)

这里的原始问题与C ++项目有关,但是对于在搜索有关现代C#/ VB / F#项目的信息时发现此问题的任何人,您可以按照本文档中的描述自定义Visual Studio的快速最新检查:

https://github.com/dotnet/project-system/blob/master/docs/up-to-date-check.md

简而言之,您将输入和输出指定为项目:

  • UpToDateCheckInput —描述了MSBuild不会知道的输入文件
  • UpToDateCheckBuilt —描述了MSBuild不会知道的输出文件

通过此设置为最新检查提高诊断日志记录级别将非常有帮助:

enter image description here