对 MSBuild 问题进行故障排除并为其创建日志

以下过程可以帮助你诊断 Visual Studio 项目中的生成问题,并在必要时创建日志以发送给 Microsoft 进行调查。

一个属性值被忽略

如果项目属性看上去设置为特定值,但对生成没有影响,请按照下列步骤进行操作:

  1. 打开与你的 Visual Studio 版本对应的 Visual Studio 开发人员命令提示符。

  2. 在替换解决方案路径、配置和项目名称的值后,运行以下命令:

    MSBuild /p:SolutionDir="c:\MySolutionDir\";Configuration="MyConfiguration";Platform="Win32" /pp:out.xml MyProject.vcxproj
    

    此命令将生成一个“预处理”MSBuild 项目文件 (out.xml)。 你可以在该文件中搜索特定属性以查看其定义位置。

属性的最后一个定义是生成使用了什么。 如果设置了两次属性,则第二个值将覆盖第一个值。 此外,MSBuild 还会评估多个传递中的项目:

  • PropertyGroups 和 Imports
  • ItemDefinitionGroups
  • ItemGroups
  • 目标

因此,给定以下顺序:

<PropertyGroup>
   <MyProperty>A</MyProperty>
</PropertyGroup>
<ItemGroup>
   <MyItems Include="MyFile.txt"/>
</ItemGroup>
<ItemDefinitionGroup>
  <MyItems>
      <MyMetadata>$(MyProperty)</MyMetadata>
  </MyItems>
</ItemDefinitionGroup>
<PropertyGroup>
   <MyProperty>B</MyProperty>
</PropertyGroup>

MyFile.txt 项的 MyMetadata 值在生成期间计算为 B(不是 A 且不为空)。

增量生成的生成超出预期

如果 MSBuild 不必要地重新生成项目或项目项,请创建详细的生成日志或二进制生成日志。 你可以在该日志中搜索不必要地生成或编译的文件。 输出的内容与以下类似:

  Task "CL"

  Using cached input dependency table built from:

  F:\test\Project1\Project1\Debug\Project1.tlog\CL.read.1.tlog

  Outputs for F:\TEST\PROJECT1\PROJECT1\PROJECT1.CPP:
  F:\TEST\PROJECT1\PROJECT1\DEBUG\PROJECT1.OBJ
  Project1.cpp will be compiled because F:\TEST\PROJECT1\PROJECT1\PROJECT1.H was modified at 6/5/2019 12:37:09 PM.

  Outputs for F:\TEST\PROJECT1\PROJECT1\PROJECT1.CPP:
  F:\TEST\PROJECT1\PROJECT1\DEBUG\PROJECT1.OBJ

  Write Tracking Logs:
  Debug\Project1.tlog\CL.write.1.tlog

如果是在 Visual Studio IDE 中生成(输出窗口详细程度为详细),输出窗口将显示每个项目不是最新的原因:

1>------ Up-To-Date check: Project: Project1, Configuration: Debug Win32 ------

1>Project is not up-to-date: build input 'f:\test\project1\project1\project1.h' was modified after the last build finished.

创建详细的日志

  1. 从 Visual Studio 主菜单中,转到“工具”>“选项”>“项目和解决方案”>“生成并运行”。

  2. 在两个组合框中,将“MSBuild 项目生成详细程度”设置为“详细”。 上面的组合框控制“输出窗口”中的生成详细程度,第二个组合框控制生成期间在每个项目的中间目录中创建的 {projectname}.log 文件中的生成详细程度

  3. 从 Visual Studio 开发人员命令提示符中,输入以下命令之一,替换你的实际路径和配置值:

    MSBuild /p:Configuration="MyConfiguration";Platform="x86" /fl MySolution.sln
    

    MSBuild /p:/p:SolutionDir="c:\MySolutionDir\";Configuration="MyConfiguration";Platform="Win32" /fl MyProject.vcxproj
    

    将在运行 MSBuild 的目录中创建 MSBuild.log 文件。

提供 MSBuild 二进制日志以供调查

MSBuild 能够捕获详细的二进制日志文件。 如果遇到生成问题并且能够提供二进制日志,日志会有助于调查问题。

但是,应注意二进制日志中捕获的信息类型,以确保不会无意中共享超出你预期的信息。 二进制日志几乎捕获生成操作所做的一切,包括项目文件的内容以及导入的任何文件(如 .props.targets),以及生成期间运行的所有任务以及输入和输出,还有在该 MSBuild 会话中访问的环境变量。 它通常不包括编译的源文件的内容,但它会捕获其全名和路径。

注意

某些生成环境使用环境变量提供机密。 在共享二进制日志之前,请确保它不会公开 API 令牌或其他重要机密。

捕获命令行生成的二进制日志

可以通过将 -bl 参数传递给 MSBuild(MSBuild.exedotnet build),来创建二进制日志。 可以使用 MSBuild 结构化日志查看器或在浏览器中使用实时结构化日志查看器浏览生成的 .binlog 文件的内容。 MSBuild 不会从浏览器中查看的二进制日志中捕获任何数据。

示例

dotnet build -bl
dotnet build -bl:SpecificStep.binlog
MSBuild.exe -bl:ServiceRelease.binlog -p:Configuration=Release

另请参阅有关二进制日志的更多详细信息

通过 Visual Studio 捕获二进制日志

若要捕获所有 MSBuild 调用的日志:

MSBUILDDEBUGENGINE 环境变量设置为 '1'(可选),将 MSBUILDDEBUGPATH 设置为现有目标文件夹以存储捕获的日志。 然后,从同一 shell 启动 Visual Studio 以继承环境:

SET MSBUILDDEBUGENGINE=1
SET MSBUILDDEBUGPATH=C:\MSBuildReproLogs
devenv.exe MySolution.sln
$env:MSBUILDDEBUGENGINE = 1
$env:MSBUILDDEBUGPATH="C:\MSBuildReproLogs"
& "devenv.exe" MySolution.sln

然后,MSBuild 二进制日志捕获到通过 MSBUILDDEBUGPATH 环境变量指定的位置(或者默认为MSBuild_Logs当前文件夹或 %temp% 的子文件夹,具体根据访问权限而定)。

注意

记录每个 MSBuild 调用(包括设计时生成)的日志,并保存在文件夹中,而无需删除较旧的日志 - 因此日志文件数量会迅速增长。 建议仅在复制要调查的问题的短时间内设置需要加入的环境变量(尽管一些不确定的问题可能需要多次复制尝试,这是可以理解的)。

使用项目系统工具扩展创建二进制 MSBuild 日志

请参阅本指南的 Project System Tools 存储库部分,了解如何通过 Visual Studio 捕获 binlog。

  1. 下载并安装项目系统工具扩展

  2. 安装扩展后,某些新项将显示在“查看”>“其他窗口”菜单中。

    Other Windows menu

  3. 选择“查看”>“其他窗口”>“生成日志记录”,以在 Visual Studio 中显示“生成日志记录”窗口。 选择第一个工具栏图标,在项目系统中开始记录常规和设计时生成。

    Build logging window

  4. 记录生成后,它将显示在“生成日志”窗口中。 右键单击该项,然后在上下文菜单中选择“保存日志”以保存 .binlog 文件。

    Build logging context menu

可以使用 MSBuild 结构化日志查看器查看和搜索 .binlog 文件。