【问题标题】:Visual Studio 2012 - MSBuild incremental build not detecting changesVisual Studio 2012 - MSBuild 增量构建未检测到更改
【发布时间】:2012-10-19 18:46:30
【问题描述】:

我已经自定义了一个 MSBuild 项目,因此默认目标是一个类似于“BuildWithExternalReference”的新目标。这个新目标调用了另外两个目标;第一个是名为“BuildExternalReference”的自定义目标,它使用外部工具构建 DLL。构建的 DLL 是对主项目的引用,它是使用普通的“构建”目标构建的。我已经为“BuildExternalReference”目标设置了输入和输出属性,因此输入引用源文件,输出引用生成的 DLL。

在 Visual Studio 2012 和 Visual Studio 2010 中,构建在第一次被调用时可以正常工作。但是,在后续构建中,如果我更改外部源文件(由“BuildExternalReference”目标输入属性引用),那么 Visual Studio 2012 只会报告“构建:0 成功,0 失败,1 最新,0 跳过”。 Visual Studio 2010 继续完美运行。此外,使用 MSBuild.exe 从命令行构建也可以完美运行。

我知道 Visual Studio 2012 中的构建系统已更改,但我找不到有关更改执行增量构建方式的信息。

Visual Studio 2012 中是否有任何变化导致增量构建发生变化?

这是我正在使用的 csproj 文件的精简版:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="BuildWithExternalTool" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <ExternalSourceFiles Include="..\ExternalSourceFiles\\*\*.cs" />
    <ExternalDll Include="..\ExternalSource\External.dll" />
  </ItemGroup>
  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
  <Target Name="BuildExternalTool" Inputs="@(ExternalSourceFiles);" Outputs="@(ExternalDll)">
    <Exec Command="C:\External\Path\To\Tool.exe" />
  </Target>
  <Target Name="BuildWithExternalTool">
    <CallTarget Targets="BuildExternalTool" />
    <CallTarget Targets="Build" />
  </Target>
</Project>

2012 年 11 月 1 日更新

这是一个完整的自包含示例,它重现了该问题:

https://skydrive.live.com/redir?resid=EA1DD6ACA92F9EFF!155&authkey=!ANhuqF_rrCgxpLE

这是一个项目的解决方案。 MSBuildIssueExample\MSBuildIssueExample.csproj 文件已自定义,因此有一个自定义默认目标。此默认目标调用自定义目标(称为“ExternalTool”),然后调用默认构建目标。

自定义 ExternalTool 目标会写出一些消息以确保其正常工作,还会将 MSBuildIssueExample\ExternalTool\Input.txt 文件的内容复制到 MSBuildIssueExample\ExternalTool\Output.txt 文件上。

Input.txt 文件是 ExternalTool 目标的输入,Output.txt 是输出。

要重新创建问题,请按以下步骤操作:

1) 在指定版本的Visual Studio中打开解决方案

2) 构建解决方案一次,以确保输出相对于输入是最新的

3) 修改 MSBuildIssueExample\ExternalTool\Input.txt 使其内容与 Output.txt 不匹配

4) 再次构建

当您在 Visual Studio 2010 中完成此过程时,将再次调用 ExternalTool 目标,并且 Input.txt 文件将被复制到 Output.txt。

当您在 Visual Studio 2012 中执行此过程时,不会调用 ExternalTool 目标,即使输入比输出新,因此 Input.txt 的内容不会写入 Output.txt。

但是,如果您执行 Rebuild(而不仅仅是 Build),那么 Visual Studio 的两个版本都会按预期工作。

【问题讨论】:

  • 没有答案,但是一个非常有趣的问题。来自stackoverflow.com/questions/1198555/… 的预构建 aspnet_compiler 指令在 2012 年的工作方式与 2010 年的工作方式相同。
  • 感谢您的评论。至少我知道 aspnet_compiler 有一个解决方案,即使它比我想要的慢。

标签: msbuild visual-studio-2012 incremental-build


【解决方案1】:

来自 Microsoft 的反馈回答了这个问题:

“这是由于 VS 2012 中的更改,其中 C#/VB 项目现在执行“快速更新检查”,允许它们跳过构建,而不是一直强制构建。一个缺点,但是,快速更新检查不考虑自定义目标,这就是未检测到您的增量更改的原因。如果您希望禁用“快速更新检查”,请将“DISABLEFASTUPTODATECHECK”设置为true 作为项目文件中的 MSBuild 属性或作为启动 VS 的环境中的环境变量。"

http://connect.microsoft.com/VisualStudio/feedback/details/770784/visual-studio-2012-msbuild-incremental-build-not-detecting-changes#details

所以基本上这是 Visual Studio 2012 中的一个重大变化,不幸的是似乎没有很好地记录。

【讨论】:

    【解决方案2】:

    这是一个老问题,但仍然相关。非常感谢您在这里提出。

    我想提供我的研究结果。

    您分享的示例显示了在 Visual Studio GUI 中构建和通过 devenv 命令行 (devenv .\MSBuildIssueExample.sln /build) 构建时的异常行为

    但是,如果您将 csproj 文件替换为以下内容:

    MSBuildIssueExample.csproj

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
        <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
        <ProductVersion>8.0.30703</ProductVersion>
        <SchemaVersion>2.0</SchemaVersion>
        <ProjectGuid>{4EA8847D-262C-4937-8536-E526E9BAB1C7}</ProjectGuid>
        <OutputType>Library</OutputType>
        <AppDesignerFolder>Properties</AppDesignerFolder>
        <RootNamespace>MSBuildIssueExample</RootNamespace>
        <AssemblyName>MSBuildIssueExample</AssemblyName>
        <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
        <FileAlignment>512</FileAlignment>
      </PropertyGroup>
      <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
        <OutputPath>bin\Debug\</OutputPath>
        <DefineConstants>DEBUG;TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
      </PropertyGroup>
      <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
        <DebugType>pdbonly</DebugType>
        <Optimize>true</Optimize>
        <OutputPath>bin\Release\</OutputPath>
        <DefineConstants>TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
      </PropertyGroup>
      <ItemGroup>
        <Reference Include="System" />
        <Reference Include="System.Core" />
        <Reference Include="System.Xml.Linq" />
        <Reference Include="System.Data.DataSetExtensions" />
        <Reference Include="Microsoft.CSharp" />
        <Reference Include="System.Data" />
        <Reference Include="System.Xml" />
      </ItemGroup>
      <ItemGroup>
        <Compile Include="Class1.cs" />
        <Compile Include="Properties\AssemblyInfo.cs" />
      </ItemGroup>
      <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
      <Import Project="Custom.Targets" />
    </Project>
    

    Custom.Targets

    <?xml version="1.0" encoding="utf-8" ?>
    <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <CompileDependsOn>ExternalTool;$(CompileDependsOn)</CompileDependsOn>
        <CleanDependsOn>CleanOutput;$(CleanDependsOn)</CleanDependsOn>
      </PropertyGroup>
      <ItemGroup>
        <ExternalToolInputs Include="ExternalTool\Input.txt">
          <InProject>false</InProject>
        </ExternalToolInputs>
        <ExternalToolOutputs Include="ExternalTool\Output.txt">
          <InProject>false</InProject>
        </ExternalToolOutputs>
      </ItemGroup>
      <Target Name="ExternalTool" Inputs="@(ExternalToolInputs)" Outputs="@(ExternalToolOutputs)">
        <Message Text="ExternalTool target start, copying input file over output..." />
        <Copy SourceFiles="@(ExternalToolInputs)" DestinationFiles="@(ExternalToolOutputs)" />
        <Message Text="ExternalTool target end, copy successful" />
      </Target>
      <Target Name="CleanOutput">
        <Delete Files="@(ExternalToolOutputs)" ContinueOnError="true" />
      </Target>
    </Project>
    

    那么行为就不一样了!

    Visual Studio GUI 继续出现异常,但是,使用 devenv 构建的命令行确实可以识别输入中的更改!

    另请注意,在命令行上运行 msbuild 而不是 devenv 在两个版本中都能正常工作。虽然msbuild还有其他问题...

    编辑

    GUI构建有一个解决方案,仅适用于外部文件量较小的情况。您将它们作为链接添加到项目中,并确保Build ActionNone。然后它在 GUI 中运行良好。

    虽然,我只检查了Custom.Targets,但我很确定它也适用于原始版本。

    【讨论】:

      【解决方案3】:

      为了扩展标记的编辑,由于None-items 对我不起作用,这里有一个我可以在其他项目中导入的自定义目标文件的示例,它将一个文本文件读入一个属性(我然后可以在DefineConstants 属性中使用),这会将文本文件标记为CoreCompile 目标的输入:

      <?xml version="1.0" encoding="utf-8"?>
      <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      
        <PropertyGroup>
          <CommonDefines>$([System.IO.File]::ReadAllText('$(SolutionDir)\_meta\definesFlags.txt'));$(CommonDefines)</CommonDefines>
        </PropertyGroup>
      
        <ItemGroup>
          <CustomAdditionalCompileInputs Include="$(SolutionDir)\_meta\definesFlags.txt" />
        </ItemGroup>
      
      </Project>
      

      CustomAdditionalCompileInputs-items 被Microsoft.Csharp.Core.targets 作为输入。

      【讨论】:

        猜你喜欢
        • 2012-10-24
        • 2017-03-14
        • 1970-01-01
        • 2016-12-27
        • 1970-01-01
        • 2012-10-05
        • 2015-10-28
        • 2017-10-18
        相关资源
        最近更新 更多