14

我已经自定义了一个 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 的两个版本都可以按预期工作。

4

3 回答 3

13

来自 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 中的一个重大变化,不幸的是似乎没有很好地记录。

于 2012-11-16T10:25:03.033 回答
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>

自定义目标

<?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,但我很确定它也可以与原始版本一起使用。

于 2014-09-12T21:26:46.603 回答
0

为了扩展标记的编辑,并且由于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

于 2016-09-01T13:43:23.270 回答