Подтвердить что ты не робот

Visual Studio 2012 - инкрементная сборка MSBuild не обнаруживает изменений

Я настроил проект MSBuild, так что цель по умолчанию - это новая цель, названная так же, как "BuildWithExternalReference". Эта новая цель называет две другие цели; первая - это настраиваемая цель, называемая "BuildExternalReference", которая создает DLL с помощью внешнего инструмента. DLL, которая построена, является ссылкой для основного проекта, который построен с использованием обычной цели "Build". Я настраиваю атрибуты Inputs and Outputs для цели 'BuildExternalReference', поэтому входы ссылаются на исходные файлы, а выходы ссылаются на полученную DLL.

В Visual Studio 2012 и Visual Studio 2010 сборка работает правильно при первом вызове. Тем не менее, при последующих сборках, если я изменю внешние исходные файлы (на которые ссылается атрибут Attaching Inputs "BuildExternalReference" ), Visual Studio 2012 просто сообщает "Build: 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>

Обновление 1 ноября 2012

Вот полный самодостаточный пример, который воспроизводит проблему:

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.

Однако, если вы перестраиваете (а не просто Build), то обе версии Visual Studio работают как ожидалось.

4b9b3361

Ответ 1

Эта обратная связь от Microsoft отвечает на вопрос:

"Это связано с изменением VS 2012, где проекты С#/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, так и в командной строке 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 Action - None. Тогда он отлично работает в графическом интерфейсе.

Хотя, я только проверил с Custom.Targets, но я уверен, что он будет работать и с исходной версией.

Ответ 3

Чтобы развернуть по метке Edit, а так как 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 -элементы берутся как входные данные Microsoft.Csharp.Core.targets.