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

Luc*_*cas 5 msbuild visual-studio visual-studio-2015

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

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

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

sti*_*ijn 9

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

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

如果你添加

<ItemDefinitionGroup>
  <CustomBuildStep>
    <Command>echo foo &gt; $(OutDir)\foo.txt</Command>
    <Outputs>$(OutDir)\foo.txt</Outputs>
  </CustomBuildStep>
</ItemDefinitionGroup>
Run Code Online (Sandbox Code Playgroud)

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

因此,关键是要完成CustomBuildStep的工作,并确定这只是使用您选择的工具在C:\ Program Files(x86)\ MSBuild\Microsoft下的所有文件中搜索所有出现的CustomBuildStep的问题. 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())"/>
Run Code Online (Sandbox Code Playgroud)

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

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


小智 6

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
  • 不成功的构建
  • 所有' .阅读。.tlog' - 输入文件,在诊断构建输出中标记为“构建输入”
  • 所有' .写。.tlog' - 输出文件,在诊断构建输出中标记为“构建输出”

实际上还有更多的检查,但是在检查这 4 种类型时大多数都失败了

  • @roli09 `csproj.dll` 是 C# 项目的旧项目系统。它不基于 CPS,是闭源的,并且不支持 SDK 式项目等较新的功能。正如 Mariia N 所说,实现 CPS 的“IBuildUpToDateCheckProvider”的更现代的项目系统位于“Microsoft.VisualStudio.ProjectSystem.Managed.VS.dll”中。它也是开源的。您可以在 https://github.com/dotnet/project-system 找到实现。 (2认同)