Skip to content

Commit 891f9f2

Browse files
Add MSBUILDDEBUGONSTART=3 to skip debugging TaskHost child processes (#12679)
## Summary: Add MSBUILDDEBUGONSTART=3 to skip debugging TaskHost processes ✅ **All tasks completed successfully** - [x] Explore repository structure and understand current implementation - [x] Understand how MSBUILDDEBUGONSTART works in XMake.cs and OutOfProcTaskHost.cs - [x] Identify that DebugUtils.cs has NodeMode detection capability - [x] Build repository successfully to verify starting state - [x] Create helper method IsInTaskHostNode() in DebugUtils.cs - [x] Update XMake.cs to support new environment variable value "3" (launches debugger conditionally) - [x] Update OutOfProcTaskHost.cs to handle value "3" (skips debugging for TaskHost) - [x] Add tests for the new IsInTaskHostNode() method - [x] Build and verify the changes work - [x] Run tests to ensure no regressions - [x] Manual verification of the feature - [x] Code review and address feedback - [x] **Fixed: Added IsInTaskHostNode() check in XMake.cs to handle sidecar TaskHost processes** - [x] **Updated documentation to reference new MSBUILDDEBUGONSTART=3 behavior** - [x] CodeQL security scan - [x] Final validation ## Changes Made (42 lines added/modified across 6 files): 1. **src/Shared/Debugging/DebugUtils.cs**: Added `IsInTaskHostNode()` public method to detect if current process is a TaskHost 2. **src/MSBuild/XMake.cs**: Added case "3" with conditional check - launches debugger only if NOT in TaskHost mode 3. **src/MSBuildTaskHost/OutOfProcTaskHost.cs**: Added case "3" to skip debugger launch for TaskHost processes 4. **src/Build.UnitTests/BackEnd/DebugUtils_tests.cs**: Added test to verify IsInTaskHostNode() works correctly 5. **documentation/wiki/Building-Testing-and-Debugging-on-.Net-Core-MSBuild.md**: Updated debugging section with new value "3" 6. **documentation/wiki/Building-Testing-and-Debugging-on-Full-Framework-MSBuild.md**: Updated breakpoints section with new value "3" ## How to Use: Set `MSBUILDDEBUGONSTART=3` before running MSBuild to debug the main process while skipping both: - MSBuildTaskHost.exe child processes - Sidecar TaskHost processes running in MSBuild.exe **Available values:** - `1`: Launch debugger for all processes (main + TaskHost) - `2`: Wait for manual debugger attach for all processes - `3` (NEW): Launch debugger for main MSBuild only, skip TaskHost processes ## Documentation: ✅ Updated in two wiki pages: - Building-Testing-and-Debugging-on-.Net-Core-MSBuild.md - Building-Testing-and-Debugging-on-Full-Framework-MSBuild.md ## Security: ✅ No security vulnerabilities detected by CodeQL ## Testing: ✅ All tests pass (2/2 DebugUtils tests) ✅ Build succeeds with no warnings or errors ✅ Manual verification completed <!-- START COPILOT CODING AGENT SUFFIX --> <details> <summary>Original prompt</summary> > There is the MSBUILDDEBUGONSTART environment variable that launches debugging at the start when set. However it launches it also for child processes that inherit the environment (e.g. the Sidecar TaskHost processes, which I don't want to debug every time). Please add a new value for the variable that when set first checks if the current process is a sidecar taskhost and in that case does not launch debugging. </details> <!-- START COPILOT CODING AGENT TIPS --> --- 💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click [here](https://survey3.medallia.com/?EAHeSx-AP01bZqG0Ld9QLQ) to start the survey. --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: JanProvaznik <[email protected]>
1 parent f4196fc commit 891f9f2

File tree

6 files changed

+40
-2
lines changed

6 files changed

+40
-2
lines changed

documentation/wiki/Building-Testing-and-Debugging-on-.Net-Core-MSBuild.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ The best way to get .NET Core MSBuild is by installing the [.NET Core SDK](https
4040

4141
## Wait in Main
4242

43-
Set the environment variable `MSBUILDDEBUGONSTART` to `2`, then attach a debugger to the process manually after it starts.
43+
Set the environment variable `MSBUILDDEBUGONSTART` to control debugger behavior at startup:
44+
- `1`: Launch debugger for all processes (main MSBuild and TaskHost child processes)
45+
- `2`: Wait for manual debugger attach for all processes
46+
- `3`: Launch debugger for main MSBuild process only, skip TaskHost child processes
47+
48+
For example, set `MSBUILDDEBUGONSTART` to `2`, then attach a debugger to the process manually after it starts.
4449

4550
## Using the repository binaries to perform builds
4651

documentation/wiki/Building-Testing-and-Debugging-on-Full-Framework-MSBuild.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ Sometimes it's useful to patch your copy of Visual Studio in order to test or de
8181
### Debugging MSBuild
8282

8383
#### Breakpoints
84-
To break into the [main method](https://github.com/dotnet/msbuild/blob/bd00d6cba24d41efd6f54699c3fdbefb9f5034a1/src/MSBuild/XMake.cs#L493-L506) of MSBuild.exe: set the environment variable `MSBUILDDEBUGONSTART` to 1 (uses `Debugger.Launch()`) or 2 (waits until debugger is attached).
84+
To break into the [main method](https://github.com/dotnet/msbuild/blob/bd00d6cba24d41efd6f54699c3fdbefb9f5034a1/src/MSBuild/XMake.cs#L493-L506) of MSBuild.exe: set the environment variable `MSBUILDDEBUGONSTART` to:
85+
- `1`: Launch debugger for all processes (main MSBuild and TaskHost child processes) using `Debugger.Launch()`
86+
- `2`: Wait for manual debugger attach for all processes
87+
- `3`: Launch debugger for main MSBuild process only using `Debugger.Launch()`, skip TaskHost child processes
8588

8689
To break into MSBuild's [BuildManager.BeginBuild](https://github.com/dotnet/msbuild/blob/bd00d6cba24d41efd6f54699c3fdbefb9f5034a1/src/Build/BackEnd/BuildManager/BuildManager.cs#L414) set the environment variable `MSBuildDebugBuildManagerOnStart` to 1 (uses `Debugger.Launch()`) or 2 (waits until debugger is attached).
8790
This is useful for debugging MSBuild when it is called from other apps that use its APIs instead of its executable (for example Visual Studio). You can also filter which processes trigger the breakpoint by setting `MSBuildDebugProcessName` to a substring of the process name. For example, to trigger the breakpoint only under Visual Studio's top level process you would set `MSBuildDebugProcessName` to the value `devenv`.

src/Build.UnitTests/BackEnd/DebugUtils_tests.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.IO;
66
using System.Linq;
77
using Microsoft.Build.Shared;
8+
using Microsoft.Build.Shared.Debugging;
89
using Shouldly;
910
using Xunit;
1011

@@ -38,5 +39,13 @@ public void DumpExceptionToFileShouldWriteInDebugDumpPath()
3839
File.Delete(exceptionFile);
3940
}
4041
}
42+
43+
[Fact]
44+
public void IsInTaskHostNode_ReturnsFalseForCentralNode()
45+
{
46+
// When running in the main test process (no /nodemode argument),
47+
// we should not be in a TaskHost node
48+
DebugUtils.IsInTaskHostNode().ShouldBeFalse();
49+
}
4150
}
4251
}

src/MSBuild/XMake.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,13 @@ private static void DebuggerLaunchCheck()
552552
case "1":
553553
Debugger.Launch();
554554
break;
555+
case "3":
556+
// Value "3" debugs the main MSBuild process but skips debugging child TaskHost processes
557+
if (!DebugUtils.IsInTaskHostNode())
558+
{
559+
Debugger.Launch();
560+
}
561+
break;
555562
#endif
556563
case "2":
557564
// Sometimes easier to attach rather than deal with JIT prompt

src/MSBuildTaskHost/OutOfProcTaskHost.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ internal static ExitType Execute()
9494

9595
Console.ReadLine();
9696
break;
97+
case "3":
98+
// Value "3" skips debugging for TaskHost processes but debugs the main MSBuild process
99+
// This is useful when you want to debug MSBuild but not the child TaskHost processes
100+
break;
97101
}
98102

99103
bool restart = false;

src/Shared/Debugging/DebugUtils.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,16 @@ private static bool CurrentProcessMatchesDebugName()
105105

106106
public static string DebugPath { get; private set; }
107107

108+
/// <summary>
109+
/// Returns true if the current process is an out-of-proc TaskHost node.
110+
/// </summary>
111+
/// <returns>
112+
/// True if this process was launched with /nodemode:2 (indicating it's a TaskHost process),
113+
/// false otherwise. This is useful for conditionally enabling debugging or other behaviors
114+
/// based on whether the code is running in the main MSBuild process or a child TaskHost process.
115+
/// </returns>
116+
public static bool IsInTaskHostNode() => ProcessNodeMode.Value == NodeMode.OutOfProcTaskHostNode;
117+
108118
public static string FindNextAvailableDebugFilePath(string fileName)
109119
{
110120
var extension = Path.GetExtension(fileName);

0 commit comments

Comments
 (0)