How does Visual Studio know my project is up to date so it can skip running MSBuild?

前端 未结 4 1381
青春惊慌失措
青春惊慌失措 2020-12-16 23:39

I have a custom MSBuild target included in my C++ project that produces a data file in the $(OutDir) folder for each item of a given item type. I have the item type hooked u

相关标签:
4条回答
  • 2020-12-17 00:29

    You can find out why a project is being rebuilt by enabling the verbosity of the fast up to date checker in the registry key:

    New-ItemProperty              `
     -Name U2DCheckVerbosity      `
     -PropertyType DWORD -Value 1 `
     -Path HKCU:\Software\Microsoft\VisualStudio\14.0\General -Force
    

    You should be able to see in the build log messages like

    Project 'Caliburn.Micro.Silverlight.Extensions' is not up to date. Project item 'C:\dev\projects\Caliburn.Micro.Silverlight.Extensions\NavigationBootstrapperSample.cs.pp' has 'Copy to Output Directory' attribute set to 'Copy always'.

    [1] https://blogs.msdn.microsoft.com/kirillosenkov/2014/08/04/how-to-investigate-rebuilding-in-visual-studio-when-nothing-has-changed/

    0 讨论(0)
  • 2020-12-17 00:38

    MsBuild/VS indeed have a mechanism to determine what is up-to-date with respect to the input files, it revolves around an executable tracker.exe which scans .tlog files to figure out what a project's output files are. There might be more to it, and if you look around on the internet you can probably get more info about this.

    But the thing is you don't really need to understand every single detail of it: you can find a simple usage example for it when inspecting how the built-in CustomBuildStep works and apply that to your case. I'll briefly explain how I got to this because I think it might be useful for you as well in dealing with msbuild questions like these.

    If you add

    <ItemDefinitionGroup>
      <CustomBuildStep>
        <Command>echo foo &gt; $(OutDir)\foo.txt</Command>
        <Outputs>$(OutDir)\foo.txt</Outputs>
      </CustomBuildStep>
    </ItemDefinitionGroup>
    

    either manually or via the project's property pages for Custom Build Step you'll see the beahviour is eactly what you need: if foo.txt is deleted a build will start, while a build is marked up-to-date if it is not (well, and when the rest of the outputs are also up-to-date).

    Hence the key is to do what CustomBuildStep does under the hood, and figuring that out is just a matter of using your tool of choice to search all occurrences of CustomBuildStep in all files under C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120 (adjust path for platform/VS version used).

    This leads us to Microsoft.CppCommon.Targets where the target named CustomBuildStep (mind you, that's the same name as the entry in the ItemDefinitionGroup above) invokes the actual CustomBuildStep command. It also has this particularily interesting bit:

    <!-- Appended tlog to track custom build events -->
    <WriteLinesToFile Encoding="Unicode"
      File="$(TLogLocation)$(ProjectName).write.1u.tlog"
      Lines="@(CustomBuildStep->'^%(Identity)');@(CustomBuildStep->MetaData('Outputs')->FullPath()->Distinct())"/>
    

    So this writes the path of the Outputs to a .tlog file in the directory used by the tracker and makes it work as desired. In my experience the line starting with ^ is just a comment - I don't use it myself and my custom targets work ok and the same is said here.

    tl;dr Use WriteLinesToFile to append full paths of your targets' outputs to a file like $(TLogLocation)$(ProjectName).write.1u.tlog. I'm saying like because write.tlog, write.u.tlog etc also work.

    0 讨论(0)
  • 2020-12-17 00:38

    The original question here relates to C++ projects, but for anyone finding this while searching for information about modern C#/VB/F# projects, you can customise Visual Studio's fast up-to-date check as described in this document:

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

    In a nutshell, you specify inputs and outputs as items:

    • UpToDateCheckInput — Describes an input file that MSBuild would not otherwise know about
    • UpToDateCheckBuilt — Describes an output file that MSBuild would not otherwise know about

    It can be very helpful to increase the diagnostic logging level for the up-to-date check via this setting:

    0 讨论(0)
  • 2020-12-17 00:42

    Visual Studio uses something called Visual Studio Common Project System (CPS) (https://github.com/Microsoft/VSProjectSystem) (VS 2017) to manage projects, including build process.

    Within CPS anything that implements IBuildUpToDateCheckProvider interface can be used as a 'UpToDateChecker' for a project. 'UpToDateChecker' is invoked before invoking MsBuild. Its main purpose is to determine whether or not invoke MsBuild to build project, or to mark project as 'Up To Date' and skip msbuild all along.

    This 'UpToDateChecker' is exactly what prints into diagnostic build output:

    1>------ Up-To-Date check: Project: "ProjectName", Configuration: Debug x86 ------ Project is not up-to-date: build input 'header.h' was modified after build output 'a.out'. Input time: 12/27/2018 4:43:08 PM, Output time: 1/1/0001 2:00:00 AM

    As for C++ Projects, for VS 2017 its default 'UpToDateChecker' is VCProjectBuildUpToDateCheck ( Microsoft.VisualStudio.Project.VisualC.VCProjectEngine.dll ). As starter, it looks into tlogs directory ( usually something like Debug\x86\.tlog) for these files:

    • .lastbuildstate
    • unsuccessfulbuild
    • all '.read..tlog' - input files, marked as 'build input' in diagnostic build output
    • all '.write..tlog' - output files, marked as 'build output' in diagnostic build output

    There's actually more checks, but most fails occur when checking these 4 types

    0 讨论(0)
提交回复
热议问题