In my last two posts (here and here) I showed how to enable the unsupported MSBuild debugger to debug a build started on the command line with MSBuild.exe. In this final post, I'll mention some other variations.
Note that this blog is rather narrow, so some of the screenshots may be hard to see – you can click on them to see the full size version.
In the previous example, I launched msbuild.exe against a project file. You well might want to start with a solution file instead. If you do, you may get an error that looks like this:
Microsoft.Build.Shared.InternalErrorException: MSB0001: Internal MSBuild Error: Mismatched leave was C:\Users\danmose\Do cuments\visual studio 2010\Projects\WindowsFormsApplication1\WindowsFormsApplication1.sln.metaproj expected C:\Users\dan mose\Documents\visual studio 2010\Projects\WindowsFormsApplication1\WindowsFormsApplication1.csproj (2,1)
The workaround is as follows. First, set an environment variable MSBUILDEMITSOLUTION=1. Then do a build of the solution in the regular way: if you want, you can cancel it after it starts building projects. Next to the solution file, you should see a file with the extension ".sln.metaproj". This is essentially the solution file translated into MSBuild-format. Now do the usual debugging procedure, but this time launch msbuild.exe against this sln.metaproj file instead of the original solution file.
When you're debugging your build process or tasks, it's much easier to follow if only one project is building at a time, and you'll probably do it that way whenever you can. What's more, debugging slows down the build so much that it may not help you diagnose a timing problem anyway.
If however for some reason you do need to debug a multiprocessor build, it's possible.
As you probably know, MSBuild launches child processes to build more than one project at once, and they persist for a while to be ready for another build. The /debug switch doesn't propagate to them. To get this to work, first terminate any msbuild.exe processes that are still alive. Then in a command window set an environment variable MSBUILDDEBUGGING=1. That environment variable is equivalent to the /debug switch, but unlike the switch it will get propagated to any child processes.
From this command window now start msbuild.exe with the /debug switch as usual. Everything will work much the same as before, but you'll get a new JIT prompt as each child process starts to do its work, and you'll have to use a new instance of Visual Studio for each one of them.
For example, I'm building a solution here, using the .metaproj workaround I mentioned above. Attaching at the first JIT prompt, I can see I am starting in the .metaproj itself:
If I hit Continue (F5) I'll get to the top of the next project, and stop there as usual. In the callstack window, I can see that the solution has invoked that project, and I can double click on the lower frame in the callstack to see where it did that – it's an MSBuild task, of course:
While I'm stopped here, I get a JIT prompt again. This time it's for the other project in my solution, which has already started to load in parallel in another msbuild.exe process. I'll go through the JIT prompts as I did before, and select to start a new instance of Visual Studio. That will in turn break in at the top of that other project.
Here's what I see now:
Visual Studio supports debugging more than one process at the same time, which would be more convenient, but I don't think the JIT launcher will let you do that. If you have a lot of child processes, it could get rather cumbersome. Remember that the "/m" switch defaults to the same number of processes as you have CPU's, so you may want to cut it down with "/m:2".
When I wrote the prototype, it was also possible to debug the evaluation and building of projects loaded in Visual Studio.
Unfortunately in walking through this scenario to write this blog post, I was sorry to find that it's somewhat broken in the release version of Visual Studio 2010. In my experiments debugging works through the first evaluation, as the projects are loaded, but then it hits a bug and terminates. Since it's an untested feature there's always the chance something can break without detection and that's apparently what happened here.
Given that, you'll most likely have to stick with msbuild.exe. However, I'll go ahead and explain a little about how one would do this in Visual Studio, in case you have better luck than I do.
Start off by setting the registry key as described at the start of my first post and kill any lingering instances of MSBuild.exe as you did in the last scenario.
Make sure the environment variable MSBUILDDEBUGGING is not set and open your first Visual Studio to act as your debugger. You can do this from the start menu. As before make sure Just-My-Code is switched on in this instance.
Open a command prompt and set the environment variable MSBUILDDEBUGGING=1 again. Then launch Visual Studio from that command prompt -- most likely you'd start it with a command like "%ProgramFiles%\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe". This second instance is your debuggee, which you will load your projects into.
Go back to the debugger process, and attach to that debuggee, choosing the "Managed (v4.0)" engine as always. In this debugger process, open up the project or targets file you want to start debugging through. Make sure you open it with "Open File" into the XML editor, rather than loading it as an actual project.
Debugging may not start automatically on the first line this time, so set a breakpoint where you want to begin. I opened the "WindowsFormsApplication1.csproj" file I used before into the XML editor, and set a breakpoint on the first line to get hit when the project is first loaded.
Open up your project or projects in the normal way in the debuggee now and you should see your breakpoint is hit. Step a little further, and for me, Visual Studio terminates.
Now I've shown you all the features of the MSBuild debugger, I hope you'll try it out.
If you have feedback, do post it here. In particular, how important is it to be able to debug projects loaded inside Visual Studio? Also, as you've seen, MSBuild must be in "debugging mode" from launch -- it's not possible to walk up to a regular build that's in progress and attach to it. Is it important to be able to do that?
Most of all, how useful is this to you, and how problematic are the bugs and limitations you run into?
Thanks for reading
Visual Studio Project & Build Dev Lead