【问题标题】:How does Visual Studio determine whether it has to start MSBuild or not?Visual Studio 如何确定是否必须启动 MSBuild?
【发布时间】:2017-08-28 09:12:24
【问题描述】:

过去,我为我的 C++ 项目做了很多 MSBuild 定制。 MSBuild 目标的 InputOutput 属性用于确定是否必须执行目标。此外,Visual Studio 使用 .tlog 文件(位于中间目录中)来确定是否必须调用 MSBuild。

现在我正在处理一个 C# 项目。我写了一个简单的 MSBuild 目标,它将文件复制到输出目录:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="CopyMyFile" BeforeTargets="AfterBuild" Inputs="$(ProjectDir)File.dat" Outputs="$(TargetDir)FileRenamed.dat">
    <Copy SourceFiles="$(ProjectDir)File.dat" DestinationFiles="$(TargetDir)FileRenamed.dat" OverwriteReadOnlyFiles="true">
    </Copy>
  </Target>
</Project>

如果通过 MSBuild.exe 调用构建,目标将按预期工作。如果目标文件不存在或源文件已被修改,则复制该文件。

如果我在 Visual Studio 中调用构建,它不会按预期工作。如果我从输出目录中删除文件,Visual Studio 不会调用 MSBuild。另一方面,每次我在修改源文件后构建项目时都会调用 MSBuild,即使没有进行其他更改。

Visual Studio 似乎只是将项目中的每个文件与输出文件(.exe、.dll 或 .pdb)进行比较。如果项目中的任何文件比输出文件新,则调用 MSBuild。就我而言,MSBuild 不会更新 .exe 文件,因此会一次又一次地调用 MSBuild。

在 C++ 项目中,此行为由 .t​​log 文件控制。在 C# 项目中是否有类似的东西?

非常感谢!

【问题讨论】:

  • MSBuild 不直接使用 .tlog 文件,而是由 Visual Studio 决定是否必须调用 MSBuild。我曾经为我的自定义构建目标创建自己的 .tlog 文件,以控制 Visual Studio 何时必须调用 MSBuild,何时不需要。我希望 C# 项目也有类似的技术。
  • 你确定吗?即使不使用 VS 构建 C++ 项目,而只是创建 msbuild tlog 文件(并且可能在下一次构建时再次读取)
  • 你是对的。对不起,错误的评论。但希望 Visual Studio 使用 .tlog 文件来决定是否必须调用 MSBuild 的假设仍然正确。但无论如何,这并不重要。我需要一种方法来告诉 Visual Studio 何时调用 MSBuild,何时不调用,因为 Visual Studio 对我的自定义构建目标一无所知。
  • 我现在没有时间想出答案,但我相当确定 VS 仅使用时间戳来比较文件。因此,您必须以某种方式指示它“查看”您的文件。要弄清楚如何做到这一点,您将不得不看看如何实现内容,例如:如果您只是将一个文本文件添加到项目中,它会添加到 Content ItemGroup 中,如果您将其 CopyToOutputDirectory 元数据设置为 PreserveNewest它会在 VS 中自动获取您所追求的行为,因此可能有一种方法可以模仿自定义目标。

标签: c# visual-studio msbuild


【解决方案1】:

答案可能是不,与 tlog 机制没有任何相似之处。不过我不是 100% 确定,也因为奇怪的是你不能做一些非常基本的事情,因为这意味着 MS 基本上放弃了 C#(和类似)项目的跟踪器东西,但没有用可以挂钩的东西代替它由用户。

使用 procmon 您可以看到 VS 获取输出和输入文件的时间戳,但我没有找到一种方法来干扰它视为输入和输出文件的内容。看起来 VS 获得了直接包含在项目文件中的所有内容的列表(即参考/内容/编译/.. VS 中显示的项目组),而不是 Taget 的输入/输出中列出的内容,并且在开始时构建仅比较这些项目的时间戳。如果一切(好吧,考虑到 VS 的一切)都是最新的,则不会为构建启动 msbuild 进程。

有一个解决方法,虽然不是很好:如果您添加一个“虚拟”内容项(例如,右键单击项目->添加新项->文本文件)并将其设置为始终被复制(右键单击文本文件刚刚添加->属性->复制到输出目录->总是复制)然后VS将总是开始构建,因此检查目标的输入与输出,如果你删除了FileRenamed.dat,则运行。

【讨论】:

  • 我最近遇到了解决这个问题的IBuildUpToDateCheckProvider 接口。我不知道这是否是要走的路。我不喜欢的是你必须扩展 Visual Studio 和 MSBuild 才能达到目标..
  • stackoverflow.com/q/43283613 与此类似。如果不编写 VS 扩展,VS 项目中的简单操作在 C# 项目中似乎是不可能的。
【解决方案2】:

看起来这只是没有很好的记录。 This site 表明您可以轻松连接命令行工具,同时提升 tlog 文件的增量功能。

为了确保信息不会丢失,我将复制他们的用例,但看看那个,我认为它很容易转化为您的需求。 dcx 的每次出现都可以替换为例如data

1。创建定义.xml文件

  • 定义一个ItemType
  • ContentType 链接到ItemType
  • 连接FileExtension
<?xml version="1.0" encoding="utf-8"?>
<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties">
  <!-- Associate DXCShader item type with .hlsl files -->
  <ItemType Name="DXCShader" DisplayName="DXC Shader" />
  <ContentType Name="DXCShader" ItemType="DXCShader" DisplayName="DXC Shader" />
  <FileExtension Name=".hlsl" ContentType="DXCShader" />
</ProjectSchemaDefinitions>

2。创建一个.targets 文件

  • 包含.xml 定义文件
  • 创建一个Target,它取决于您的构建挂钩之一(此处:ClCompile
  • 在目标中创建一个ItemGroup,作为CustomBuild 的参数。 MessageCommandAdditionalInputsOutput 是相关的元属性。
  • 使用 MinimalRebuildFromTracking="true"TrackerLogDirectory 调用 CustomBuild 以包含 tlog 文件。 这部分是神奇的成分,如果您的依赖项是最新的,则使 MSBuild 跳过构建。
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <!-- Include definitions from dxc.xml, which defines the DXCShader item. -->
    <PropertyPageSchema Include="$(MSBuildThisFileDirectory)dxc.xml" />
    <!-- Hook up DXCShader items to be built by the DXC target. -->
    <AvailableItemName Include="DXCShader">
      <Targets>DXC</Targets>
    </AvailableItemName>
  </ItemGroup>

  <Target
    Name="DXC"
    Condition="'@(DXCShader)' != ''"
    BeforeTargets="ClCompile">

    <Message Importance="High" Text="Building shaders!!!" />

    <!-- Find all shader headers (.hlsli files) -->
    <ItemGroup>
      <ShaderHeader Include="*.hlsli" />
    </ItemGroup>
    <PropertyGroup>
      <ShaderHeaders>@(ShaderHeader)</ShaderHeaders>
    </PropertyGroup>

    <!-- Setup metadata for custom build tool -->
    <ItemGroup>
      <DXCShader>
        <Message>%(Filename)%(Extension)</Message>
        <Command>
          "$(WDKBinRoot)\x86\dxc.exe" -T vs_6_0 -E vs_main %(Identity) -Fh %(Filename).vs.h -Vn %(Filename)_vs
          "$(WDKBinRoot)\x86\dxc.exe" -T ps_6_0 -E ps_main %(Identity) -Fh %(Filename).ps.h -Vn %(Filename)_ps
        </Command>
        <AdditionalInputs>$(ShaderHeaders)</AdditionalInputs>
        <Outputs>%(Filename).vs.h;%(Filename).ps.h</Outputs>
      </DXCShader>
    </ItemGroup>

    <!-- Compile by forwarding to the Custom Build Tool infrastructure,
         so it will take care of .tlogs and error/warning parsing -->
    <CustomBuild
      Sources="@(DXCShader)"
      MinimalRebuildFromTracking="true"
      TrackerLogDirectory="$(TLogLocation)"
      ErrorListRegex="(?'FILENAME'.+):(?'LINE'\d+):(?'COLUMN'\d+): (?'CATEGORY'error|warning): (?'TEXT'.*)" />
  </Target>
</Project>

【讨论】:

    猜你喜欢
    • 2011-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-17
    • 1970-01-01
    • 2016-05-16
    相关资源
    最近更新 更多