Home

Ensuring MSBuild and devenv build identically

MSBuild and devenv (ie building from inside Visual Studio 10) are not necessarily synchronous. That is, you build your project in the IDE, and then when you build it off the command line from MSBuild, it causes a full rebuild if only a single CPP source is out of date. It should only be compiling that single file. What is wrong?

On my machines, it boiled down to subtly different CL command lines. Luckily finding the exact difference is easy enough.
For this example, let's say we're using the Debug build:

  1. Build your solution from the IDE. Save Debug/cl.command.1.tlog to a temporary place.
  2. Touch one source file (a CPP file for me) in your project - basically to poke MSBuild into action.
  3. Build your solution on the command line with MSBuild.
  4. Compare the current Debug/cl.command.1.tlog to the one you saved from the IDE build.

In my particular case, I had the following:

msbuild-diff

Bingo. /errorReport:queue for MSBuild and /errorReport:prompt for MSVC. I don't understand the origin of the MSVC parameter - the IDE tells me in the Compiler Settings 'Command Line' window that it is going to compile with :queue, but instead it is actually compiling with :prompt. Hmm.. I don't know why.

Anyway, a solution that worked for me was to change my Win32 property sheet (the one in C:\Users\ben\AppData\Local\Microsoft\MSBuild\v4.0) so that the setting is forced to /errorReport:send. That's the property sheet that you get to if you go View > Other Windows > Property Manager in the IDE - I'm refering to the property sheet called 'Microsoft.Cpp.Win32.user'.

Is that it?

Not quite -- I then discovered that MSBuild would reference my $(ProjectDir) as c:\devx86, whereas the IDE was calling it C:\devx86. That is, the case of the letter 'c' in C:\ was different for the two builds. Since my $(ProjectDir) makes it into my CL command line, this also needed fixing. A solution to this is to explicitly pass in the full solution filename to MSBuild, rather than a relative one. So

  C:\devx86>msbuild           projects\Albion\Albion.sln /t:Rebuild /p:Configuration=Debug;Platform=Win32      -- $(ProjectDir) ends up c:\devx86\... (lower case)
  C:\devx86>msbuild C:\devx86\projects\Albion\Albion.sln /t:Rebuild /p:Configuration=Debug;Platform=Win32      -- This is good (upper case)

That fixed it for me. Some days I feel like all I do is wait around for my compiler. I hope this helps...

ps. Last but definitely not least -- you can get great traces about dependencies from the IDE by doing this:

Edit C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe.config, ensuring that you have the following tag in there (It goes under the root. Mine is directly beneath <configSections>, but I doubt the order matters):

<system.diagnostics>
<switches>
<add name="CPS" value="4" />
</switches>
</system.diagnostics>

Now keep DebugView (by sysinternals) open, and you'll see the IDE tell you exactly why it decides that the project needs to be built.