22

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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Peter Mounce
  • 4,105
  • 3
  • 34
  • 65

3 Answers3

12

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).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brian Walker
  • 8,658
  • 2
  • 33
  • 35
4

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rohit
  • 3,610
  • 7
  • 45
  • 76
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.

John Leidegren
  • 59,920
  • 20
  • 131
  • 152
  • I guess this would explain why dependency checking is so slow.. Do you have a reference for the statement regarding the compilers use of checksums? – Jørn Jensen Nov 23 '11 at 16:05
  • 2
    I might have been going out on a limb there, and I'm not really sure as to how I made that conclusion. The only reference I could find was this: http://msdn.microsoft.com/en-us/library/ms173226.aspx and it clearly states that these checksums are used by the debugger, not the compiler or MSBuild. I might have been wrong on this one... – John Leidegren Nov 24 '11 at 07:56