How does MSBuild decide whether it needs to rebuil

2020-04-01 21:52发布

问题:

How does MSBuild decide whether it needs to rebuild a library (that is, invoke csc), or not, when it is run against a C# project file?

I imagine (but want to confirm):

  • If there's no output directory, rebuild (duh :) )
  • If a C# file has changed, rebuild
  • If an included file marked copy-always has changed, rebuild
    • Or is it smart enough to not rebuild, but just copy the file to the existing output?
  • If an included file marked copy-if-newer has changed, rebuild
    • Same question as above

回答1:

If you look in Microsoft.CSharp.targets (the MSBuild file for compiling C# projects) the CoreCompile target has a set of Inputs and Outputs defined. These are used to do the dependency checking to see if CoreCompile needs to run. The list of inputs include the C# files, resource files, application icon, strong name key file, and other custom inputs you can define.

If you have a solution and run MSBuild on it with diagnostic logging enabled (/v:diag command line parameter), you might see this message if the outputs are up to date:

Skipping target "CoreCompile" because all output files are up-to-date with respect to the input files.

The targets file is located in the .NET Framework directory (C:\windows\Microsoft.NET\Framework\v3.5 or v4.0.30319).



回答2:

MSBuild has built-in functionality to do it.

Target has two properties, Inputs and Outputs.

Whenever Input changes or Output is older or missing the Target is executed.



回答3:

The things is, any heuristic that might sound plausible is probably not going to cut it. And when you're asking your compiler (build system) to produce an output you better damn guarantee that the output is what you expect it is.

As far as I know, MSBuild doesn't do this. It always rebuilds (from scratch) the entire solution/project. However, when MSBuild is being invoked from within Visual Studio temporary compilation units are maintained in the \obj folder of your project. Emptying that folder is the same as rebuilding.

That said if the compiler or build system was to reuse outputs it would use checksums of the actual file contents to determine whether a compiled output can be retrieved from some other place. This is basically the only reliable way you could determine whether a file actually needs to be recompiled from scratch. FYI, this is done by the Visual C# compiler not MSBuild.

The file system "last modified date" attribute wouldn't be consistent cross systems and therefore not ultimately used to determined whether to build with cached output or build from scratch.