Visual Studio 2019 中更改的目录的自定义构建的 <Outputs> 标记检查规则?

问题描述

让晦涩的问题变得简单...

我们有一个由许多项目组成的解决方案,其中一些项目使用 3rd 方的东西来设置自定义构建事件以进行一些黑魔法编译,看起来像这样:

<CustomBuild Include="..\folder\somestuff.xyz">
  <FileType>Document</FileType>
  <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">C:\Tcl\bin\tclsh.exe $(APP_PATH)\modules\APP\bin\generator.tcl -o %(RelativeDir)%(Filename) %(RelativeDir)%(Filename).xyz</Command>
  <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">APPGEN %(RelativeDir)%(Filename)</Message>
  <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(RelativeDir)%(Filename).cpp;%(RelativeDir)%(Filename).h;%(RelativeDir)%(Outputs)</Outputs>
</CustomBuild>

在我们将 VS2015 切换到 VS2019 之前,这一直正常工作,因为现在在编译期间它报告: Project is not up-to-date: build output 'd:\projects\program\app\src\plugins\shared\' is missing。这或多或少是可以的,但它会强制编译器重新编译该项目的依赖项,这开始非常烦人,因为即使没有进行任何更改,您每次也需要重建多个项目。

我发现问题源于这行自定义构建:

<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(RelativeDir)%(Filename).cpp;%(RelativeDir)%(Filename).h;%(RelativeDir)%(Outputs)</Outputs>

更确切地说,从这部分来看:%(RelativeDir)%(Outputs) 作为对 .cpp.h 文件的检查相同的标签不会产生任何问题。所以我删除了这个目录检查。删除这块代码后,项目将正确编译,并且不会整天重新编译。

那么为什么自定义构建的输出检查现在可以正常工作,只是文件和目录会产生这种问题?

是的,检查的目录存在并且它指的是现有的正确路径。

解决方法

真正的问题是您的真实项目总是由于元数据 Outputs 而重建。

特别的一点是,您应该确保 Outputs 的值的有效性和合法性。

问题在 %(RelativeDir)%(RelativeDir)%(Outputs) 下。当您添加它时,outputs 具有非法文件夹结构,而不是一个文件,这使得 outputs 始终会找到丢失的非法文件夹结构,从而导致项目始终重建。

让我详细描述一下,

当msbuild读取outputs属性时,当读取到%(RelativeDir)%(Filename).cpp;%(RelativeDir)%(Filename).h;%(RelativeDir)时,Outputs的值是这样的:

..\folder\somestuff.cpp;..\folder\somestuff.h;..\folder\

然后,它读取%(Outputs)(读取自身),这更像是将上述值复制两次:

..\folder\somestuff.cpp;..\folder\somestuff.h;..\folder\..\folder\somestuff.cpp;..\folder\somestuff.h;..\folder\

您会发现最后一部分 ..\folder\ 不是文件,而是一个文件夹结构,对于 outputs 来说是非法的。

这就是原因。

而且更像是您的问题,缺少文件夹结构 d:\projects\program\app\src\plugins\shared\

建议

因此您不应再次添加 outputs

<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(RelativeDir)%(Filename).cpp;%(RelativeDir)%(Filename).h;</Outputs>