Visual Studio 2012 - MSBuild增量构建未检测到更改

14

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

在Visual Studio 2012和Visual Studio 2010中,第一次调用构建时都能正常工作。但是,在以后的构建中,如果我更改了外部源文件(由“BuildExternalReference”目标的Inputs属性引用),则Visual Studio 2012仅报告“Build: 0 succeeded, 0 failed, 1 up-to-date, 0 skipped”。而Visual Studio 2010仍然完美地工作。此外,使用MSBuild.exe从命令行构建也可以正常工作。

我知道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”),然后调用默认的Build目标。

自定义的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。

但是,如果您执行重新生成(而不仅仅是构建),则两个版本的Visual Studio都按预期工作。


没有为您提供答案,但这是一个非常有趣的问题。来自https://dev59.com/AHM_5IYBdhLWcg3w2XLw#10386480的预构建aspnet_compiler指令在2012年与2010年一样有效。 - Brian White
感谢您的评论。至少我知道有一个使用 aspnet_compiler 的解决方案,即使它比我想要的更慢。 - Ian Newson
3个回答

14

这个反馈来自微软,回答了这个问题:

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

因此,基本上这是Visual Studio 2012中的一个破坏性变化,不幸的是似乎没有很好的记录。


4

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

我想提供我的研究结果。

您分享的示例显示了在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,但我非常确定原始版本也能够正常工作。


0
进一步扩展Mark的编辑,由于None项目对我无效,这里提供一个自定义目标文件的示例,我可以在其他项目中导入该文件,将文本文件读入属性(然后可以在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 作为输入接收的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接