7

I have a VS2017 csharp project and the .csproj file looks like the following:

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>netcoreapp2.0</TargetFramework>
    </PropertyGroup>
  
    <ItemGroup>
        <MyItem Include="file.dat" />
    </ItemGroup>

    <PropertyGroup>
        <PrepareResourcesDependsOn>
            $(PrepareResourcesDependsOn);
            MyCompileTarget
         </PrepareResourcesDependsOn>
        <CoreCompileDependsOn>
            $(CoreCompileDependsOn);
            MyCompileTarget
        </CoreCompileDependsOn>
    </PropertyGroup>

    <Target Name="MyCompileTarget" Inputs="@(MyItem)" Outputs="@(MyItem->'%(FileName).out')">
    ...
    </Target>
 </Project>

Where MyCompileTarget is a target that generates the file.out from file.dat (in the actual code the incremental build target and properties are in a target file automatically included via a NuGet package).

The issue is that if I change file.dat and press on Build, no target is executed at all, (but MyTarget is correctly executed with Rebuild or when running with msbuild). I would expect the MyCompileTarget to be executed so that the file.out file is updated.

The same issue occurs if I use BeforeBuild or AfterBuild instead of PrepareResourcesDependsOn etc.

It seems that Visual Studio incremental build won't start unless some file in @(Compile) or @(EmbeddedResource) is changed. Indeed, if I add the following

<EmbeddedResource>file.dat</EmbeddedResource>

the incremental build works as expected (but clearly I do not want to embeed the file.dat into the generated assembly).

Is it possible to force Visual Studio to enable incremental build if file.dat is modified, and if the corresponding generated file is older than file.dat or it does not exist?

Note: the same issue occurs using VS2015, with .NET CORE or .NET FRAMEWORK. Also, incremental build will be triggered if I change a csharp file, and it will therefore trigger MyTask, but only if file.dat is newer than the generated file (as expected).

Thanks in advance, Fabio.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
Fabio Strocco
  • 300
  • 4
  • 14
  • If you run this with verbose output, does it say why the target gets skipped? What might help is adding a record to the file tracker mechanism in your target, something like `` – stijn Apr 25 '18 at 17:35
  • Thanks for the reply. I tried your solution but still didn't work. When I change the source file it still won't recompile, unless I delete the output file. Is there a way to instert the file in some list so that the 'fast-up-to-date' in Visual Studio will catch the change (difference between source and output file)? – Fabio Strocco Apr 26 '18 at 09:22

2 Answers2

9

Is it possible to force Visual Studio to enable incremental build if file.dat is modified

You can set the property DisableFastUpToDateCheck to true in the project file to disable FastUpToDateCheck for Visual Studio build manager:

<PropertyGroup>
    <DisableFastUpToDateCheck>True</DisableFastUpToDateCheck>
</PropertyGroup>

Check MSDN about DisableFastUpToDateCheck:

A boolean value that applies to Visual Studio only. The Visual Studio build manager uses a process called FastUpToDateCheck to determine whether a project must be rebuilt to be up to date. This process is faster than using MSBuild to determine this. Setting the DisableFastUpToDateCheck property to true lets you bypass the Visual Studio build manager and force it to use MSBuild to determine whether the project is up to date

Update:

Also, we can set the UpToDateCheckInput to the item:

<UpToDateCheckInput Include="file.dat" />
Leo Liu
  • 71,098
  • 10
  • 114
  • 135
  • Thanks a lot for the reply :) Is there a way to do that without disabling the fast-up-to-date-check? I tried this `` but it won't work. – Fabio Strocco Apr 26 '18 at 10:36
  • The issue is that I need to keep fast up to date checks enabled for performance reasons, and the solution above (UpToDateCheckInput) won't work, at least not when the item is in a .target file, which is automatically included in VS2017 projects via NuGet package reference. – Fabio Strocco Apr 26 '18 at 10:45
  • @FabioStrocco, Not sure I understand you clear. You should add `True` in the .csproj file under the line `netcoreapp2.0` not in the .target file in the nuget package. Besides, if you want keep build performance and the file could not be set file in `@(Compile)` or `@(EmbeddedResource)`, I am afraid there is no better way to solve this problem. – Leo Liu Apr 26 '18 at 10:59
  • My fault, I placed the item group in the wrong place. `` solves the issue while still keeping fast-up-to-date-check enabled, so I suggest you include it in your answer so I can close the topic. – Fabio Strocco Apr 26 '18 at 11:04
  • What I am saying is that it seems to work when I add the following under `ItemGroup`: ``, even whith fast-track-update-check set to true. Apparently it will now include file.dat in the fast-up-to-date checks, therefore triggering the build when file.dat changes (it will then be my build script that decides which targets to run). Does it make sense to you? I found this post below. https://stackoverflow.com/questions/50026355/how-to-avoid-that-visual-studio-incremental-build-does-not-run-when-files-outsid?noredirect=1#comment87072582_50026355 – Fabio Strocco Apr 26 '18 at 11:09
  • The reason why I want to place all this into a NuGet target file is that I want to distribute a compiler as a NuGet package, which will automatically trigger compilation on build, without the NuGet package user has to include anything else than `MyItem` in its .csproj file. – Fabio Strocco Apr 26 '18 at 11:21
  • You should never have to disable the up to date check. This is bad advice, and I suggest deleting or editing this answer. People will copy/paste that property to their projects and suffer through slow builds. – Drew Noakes Oct 11 '21 at 21:41
2

Disabling the VS fast up-to-date check will make your builds much slower. Don't do it!

Instead, make sure the up-to-date check knows about the items in your project and how they relate to build. There are two kinds of item you can add to your project for this:

  • UpToDateCheckInput for inputs
  • UpToDateCheckBuilt for outputs

In your case you need the second option as there is both an input and an output. You need to ensure that if you delete the output, it is rebuilt.

<PropertyGroup>
  <UpToDateCheckBuilt Original="@(MyItem)" Include="@(MyItem->'%(FileName).out')">
</PropertyGroup>

For more information, see the documentation:

https://github.com/dotnet/project-system/blob/main/docs/up-to-date-check.md

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742