Visual Studio 2012 - Incremental MSBuild Build Does Not Detect Changes

I set up the MSBuild project, so the default target is a new target, named just like "BuildWithExternalReference". This new goal names two other goals; the first is a custom target called "BuildExternalReference", which creates a DLL using an external tool. The DLL that is built is a reference for the main project, which is built using the usual Build target. I am setting the Inputs and Outputs attributes for the 'BuildExternalReference' target, so the inputs refer to the source files, and the outputs refer to the resulting DLL.

In Visual Studio 2012 and Visual Studio 2010, the assembly works correctly on the first call. However, in subsequent builds, if I change the external source files (referenced by the Attaching Inputs attribute "BuildExternalReference"), Visual Studio 2012 simply reports "Build: 0 successful, 0 failed, 1 updated, 0 skipped." Visual Studio 2010 continues to work fine. In addition, creating MSBuild.exe from the command line works fine.

I know that the build system in Visual Studio 2012 has changed, but I cannot find information about the changes in how incremental builds are performed.

Has anything changed in Visual Studio 2012 to cause incremental edits to change?

Here's the clipped version of the csproj file I'm using:

<?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> 

Update November 1, 2012

Here is a complete self-sufficient example that reproduces the problem:

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

This is a single project solution. The MSBuildIssueExample \ MSBuildIssueExample.csproj file has been configured so that there is a default target. This default target invokes the custom target (called "ExternalTool"), and then the default target assembly.

The ExternalTool custom target object writes some messages to make sure that it works, and also copies the contents of the MSBuildIssueExample \ ExternalTool \ Input.txt file on top of the MSBuildIssueExample \ ExternalTool \ Output.txt file.

The Input.txt file represents the input for the ExternalTool object, and the Output.txt file represents the output.

To recreate the problem, follow these steps:

1) Open the solution in the specified version of Visual Studio

2) Build the solution once to make sure the outputs are updated relative to the inputs

3) Modify the MSBuildIssueExample \ ExternalTool \ Input.txt file so that its contents do not match Output.txt

4) Again again

When you go through this process in Visual Studio 2010, the ExternalTool object will be called again, and the Input.txt file will be copied through Output.txt.

When you go through this process in Visual Studio 2012, the ExternalTool target will not be called even if the inputs are newer than the outputs, and as a result, the contents of Input.txt will not be written to Output.txt.

However, if you are rebuilding (not just Build), then both versions of Visual Studio work as expected.

+13
visual-studio-2012 msbuild incremental-build
Oct 30 '12 at 12:18
source share
3 answers

This feedback from Microsoft answers the question:

β€œThis is due to a change in VS 2012, where C # / VB projects now perform aβ€œ quick updated check ”, which allows them to skip the assembly rather than force the assembly all the time. One drawback, however, is that the quick modern check does not take into account user goals, therefore your incremental changes were not detected. If you want to disable the "quick update check", set "DISABLEFASTUPTODATECHECK" to true either as the MSBuild property in the project file or as the environment variable in the environment from which you are launching VS. "

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

So basically this is a terrific change in Visual Studio 2012, which, unfortunately, is not well documented.

+10
Nov 16 '12 at 10:25
source share

This is an old problem, but relevant. Thank you so much for being here.

I would like to present the results of my research.

The example you showed shows abnormal behavior both when building inside the Visual Studio GUI and on the devenv command line ( devenv .\MSBuildIssueExample.sln /build )

However, if you replace the csproj file as follows:

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> 

Then the behavior is different!

The Visual Studio GUI continues to behave badly, however building a command line with devenv recognizes input changes!

Also note that running msbuild on the command line instead of devenv works correctly in both versions. Although msbuild has other problems ...

EDIT

There is a solution for building a GUI, which is applicable only when the number of external files is small. You will add them to the project as links and make sure that the Build Action is None . Then it works great in the GUI.

Although, I just checked with Custom.Targets , but I'm sure that it will work with the original version.

+3
Sep 12 '14 at 21:26
source share

To expand on the Edit label, and since None elements do not work for me, here is an example of a custom goals file that I can import into other projects that reads a text file into a property (which I can then use in the DefineConstants property) and will mark text file as input for the purpose of 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 elements are taken as input Microsoft.Csharp.Core.targets .

0
Sep 01 '16 at 13:43 on
source share



All Articles