Debugging MSBuild can be difficult, here's the step by step process I usually take.
- Understand which MSBuild you want to debug into.
- Set up Visual Studio for Debugging.
- Set up the MSBuild repo if you're unable to step into MSBuild code for some reason.
- Replace MSBuild Binaries if you want to customize MSBuild.
- Reproduce Your Scenario.
- Break Into the Right Function.
- Open VS
- Tools -> Options -> Debugging
- Uncheck "Enable Just My Code"
- Check .NET Framework source stepping
- Uncheck "Require source files to exactly match the original version)
- This may be necessary if you're using the MSBuild repo's source to step through, and the source doesn't match 1:1.
You may want to set a custom symbol path to force Visual Studio to use your binaries for source-stepping. To do this, Tools -> Options -> Symbols -> + -> C:/Path/To/MSBuild
. You may want to point it to your SDK folder when debugging an SDK build. Remember to undo this afterward.
cd <wherever you place your code>
git clone https://github.com/dotnet/msbuild
cd msbuild
build.cmd
devenv MSBuild.Dev.slnf
Note: Say you want to make sure your MSBuild source code matches the version that's in the .NET SDK or Visual Studio exactly. Run msbuild --version
(dev cmd prompt) or dotnet msbuild --version
to figure out which commit hash to checkout. You should see a message like MSBuild version 17.4.0+18d5aef85 for .NET Framework
, 18d5aef85
is the hash to checkout.
This is for those very complex scenarios where you need to manually modify MSBuild and test builds using those new binaries. I typically do this when logging isn't an option and I need a task to spit out some Console.WriteLine
s.
- Set up the MSBuild Repo.
- Make changes and rerun
build.cmd
- run
scripts/Deploy-MSBuild.ps1 -Destination:"C:/Path/To/VS/Or/Sdk
(run as admin) - Repro your scenario / debug into msbuild / etc.
- Don't forget to replace your custom bits with the originals afterward. The
Deploy-MSBuild.ps1
automatically creates a backup folder
If you're manually replacing binaries, they should exist at: <msbuild-repo-root>/artifacts/bin/bootstrap/<yourTargetFramework>/MSBuild/
. Use net472 for MSBuild under VS, and net* for .NET SDK.
You want at least one instance of Visual Studio open, ideally with the MSBuild.Dev.slnf
project open. If your repro scenario requires VS, you'll have two instances of VS open at the same time.
- Launch a developer command prompt
- Set the right environment variable:
set MSBUILDDEBUGONSTART=1
- 1 = Show a prompt that displays which debuggers to attach to.
- 2 = Display a process ID, manually attach to it, then continue the build.
- Run your scenario, break into the process using the Visual Studio that has the MSBuild source open.
- Launch a developer command prompt
- Set the right environment variable:
set MSBUILDDEBUGONSTART=1
- 1 = Show a prompt that displays which debuggers to attach to.
- 2 = Display a process ID, manually attach to it, then continue the build.
devenv YourProject.sln
- Attach with the other instance of Visual Studio.
Once your debugger (I'm assuming Visual Studio) is attached to MSBuild, it should be somewhere in XMake.cs at Debugger.Launch();
. Now it's time to set breakpoints.
If you have the MSBuild source setup locally, you can manually place breakpoints as needed, otherwise:
- Debug -> Windows -> Breakpoints
- New -> Function Breakpoint
It's easiest to include the fully-qualified name as your function breakpoint. That means Namespace.ClassName.FunctionName
.
All MSBuild tasks, custom or not, have the same entrypoint, Execute()
. Hooking into official MSBuild tasks might look like Microsoft.Build.Tasks.Message.Execute
, where custom tasks have unique namespaces & class names.
Relevant links for custom MSBuild tasks:
- Tutorial: Creating a custom task. The most recent doc on writing tasks.
- Task Writing. A slightly older doc, but still useful.
- Creating an inline task. How to write a task directly into your project file!
- Debugging An MSBuild Build. For debugging into MSBuild itself.
When debugging, it helps to know exactly which dll's are loaded to debug into.
To check this, Debug -> Windows -> Modules. Sort by name, and look for Microsoft.Build.*.dll
or MSBuild.dll
to see which dll's are loaded and where they are. If it's pointing to the wrong dll, you can always set custom symbol paths to manually correct the issue.
This is mostly the same as debugging regular MSBuild, but all the relevant binaries are going to be in your SDK directory. Typically this is C:\Program Files\dotnet\sdk\your-version
.
If you want to debug using a specific version of the SDK, I recommend downloading and using a standalone SDK (click on the version you're looking for, download from the "binaries" column). This will prevent you from ruining your own SDK install. Remember to use scripts/Deploy-MSBuild.ps1
from the MSBuild repo.
Note the .NET SDK does not have the different flavors of MSBuild.
Sometimes you need to make a change in the SDK and msbuild at the same time. This is tricky but doable. In a Developer Command Prompt
, build the SDK repo and run eng\dogfood.cmd
. The relevant MSBuild binaries will be under <repo-root>\artifacts\bin\redist\Debug\dotnet\
.
Reproduce your scenario from this dev command prompt.