diff --git a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs index d063ba7b9ceb4..3072ca7c03450 100644 --- a/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs +++ b/src/Compilers/CSharp/Portable/CommandLine/CSharpCommandLineParser.cs @@ -9,8 +9,10 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; +using System.Threading; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -282,7 +284,22 @@ internal sealed override CommandLineArguments CommonParse(IEnumerable ar #if DEBUG case "attachdebugger": - Debugger.Launch(); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Debugger.Launch() only works on Windows. + _ = Debugger.Launch(); + } + else + { + var timeout = TimeSpan.FromMinutes(2); + Console.WriteLine($"Compiler started with process ID {Environment.ProcessId}"); + Console.WriteLine($"Waiting {timeout:g} for a debugger to attach"); + using var timeoutSource = new CancellationTokenSource(timeout); + while (!Debugger.IsAttached && !timeoutSource.Token.IsCancellationRequested) + { + Thread.Sleep(100); + } + } continue; #endif } diff --git a/src/Compilers/CSharp/Portable/Utilities/EnvironmentExtensions.cs b/src/Compilers/CSharp/Portable/Utilities/EnvironmentExtensions.cs new file mode 100644 index 0000000000000..590bdc0ed79e9 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Utilities/EnvironmentExtensions.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; + +namespace Microsoft.CodeAnalysis.CSharp; + +internal static class EnvironmentExtensions +{ + extension(Environment) + { + public static int ProcessId + { + get + { +#if NET + return Environment.ProcessId; +#else + return System.Diagnostics.Process.GetCurrentProcess().Id; +#endif + } + } + } +} diff --git a/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb b/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb index 707f5b985cd23..a53023f771cd8 100644 --- a/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb +++ b/src/Compilers/VisualBasic/Portable/CommandLine/VisualBasicCommandLineParser.vb @@ -8,6 +8,7 @@ Imports System.IO Imports System.Runtime.InteropServices Imports System.Security.Cryptography Imports System.Text +Imports System.Threading Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.Emit Imports Microsoft.CodeAnalysis.PooledObjects @@ -446,7 +447,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic #If DEBUG Then Case "attachdebugger" - Debugger.Launch() + If RuntimeInformation.IsOSPlatform(OSPlatform.Windows) Then + ' Debugger.Launch() only works on Windows + Debugger.Launch() + Else + Dim timeout = TimeSpan.FromMinutes(2) +#If NET Then + Dim processId = Environment.ProcessId +#Else + Dim processId = System.Diagnostics.Process.GetCurrentProcess().Id +#End If + Console.WriteLine($"Compiler started with process ID {processId}") + Console.WriteLine($"Waiting {timeout:g} for a debugger to attach") + Using timeoutSource = New CancellationTokenSource(timeout) + While Not Debugger.IsAttached AndAlso Not timeoutSource.Token.IsCancellationRequested + Thread.Sleep(100) + End While + End Using + End If Continue For #End If End Select