diff --git a/NuGet.config b/NuGet.config
index e0e61bbbfd..687b1bf8e6 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -6,6 +6,7 @@
+
diff --git a/Roslyn-SDK.sln b/Roslyn-SDK.sln
index 2715ebfa91..ef1484fb0b 100644
--- a/Roslyn-SDK.sln
+++ b/Roslyn-SDK.sln
@@ -189,6 +189,8 @@ Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Microsoft.CodeAnalysis.Visu
EndProject
Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing.XUnit.UnitTests", "tests\Microsoft.CodeAnalysis.Testing\Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing.XUnit.UnitTests\Microsoft.CodeAnalysis.VisualBasic.SourceGenerators.Testing.XUnit.UnitTests.vbproj", "{92BD1781-5DB4-4F72-BCCB-0D64C0790A2B}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roslyn.ComponentDebugger", "src\VisualStudio.Roslyn.SDK\ComponentDebugger\Roslyn.ComponentDebugger.csproj", "{421DE59C-8246-4679-9D69-79F16A7187BE}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -539,6 +541,10 @@ Global
{92BD1781-5DB4-4F72-BCCB-0D64C0790A2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{92BD1781-5DB4-4F72-BCCB-0D64C0790A2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{92BD1781-5DB4-4F72-BCCB-0D64C0790A2B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {421DE59C-8246-4679-9D69-79F16A7187BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {421DE59C-8246-4679-9D69-79F16A7187BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {421DE59C-8246-4679-9D69-79F16A7187BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {421DE59C-8246-4679-9D69-79F16A7187BE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -635,6 +641,7 @@ Global
{7D9C0EF5-7383-4E35-811B-3288B3C806F3} = {9905147E-CC1F-42A0-BD27-05586C583DF7}
{7C3FE60E-055B-4E0C-BB85-C7E94A640074} = {9905147E-CC1F-42A0-BD27-05586C583DF7}
{92BD1781-5DB4-4F72-BCCB-0D64C0790A2B} = {9905147E-CC1F-42A0-BD27-05586C583DF7}
+ {421DE59C-8246-4679-9D69-79F16A7187BE} = {F9B73995-76C6-4056-ADA9-18342F951361}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {56695AA9-EA80-47A7-8562-E51285906C54}
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/CommandLineArgumentsDataSource.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/CommandLineArgumentsDataSource.cs
new file mode 100644
index 0000000000..64174d3a25
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/CommandLineArgumentsDataSource.cs
@@ -0,0 +1,70 @@
+// 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;
+using System.Collections.Immutable;
+using System.ComponentModel.Composition;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Dataflow;
+using Microsoft.VisualStudio.ProjectSystem;
+using Microsoft.VisualStudio.ProjectSystem.VS;
+
+namespace Roslyn.ComponentDebugger
+{
+ [Export]
+ [AppliesTo("(" + ProjectCapabilities.CSharp + " | " + ProjectCapabilities.VB + ") & !" + ProjectCapabilities.SharedAssetsProject)]
+ public class CommandLineArgumentsDataSource : UnconfiguredProjectHostBridge, IProjectVersionedValue>, IProjectVersionedValue>>
+ {
+ private readonly IActiveConfiguredProjectSubscriptionService _activeProjectSubscriptionService;
+
+ [ImportingConstructor]
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "MEF ensures not null")]
+ public CommandLineArgumentsDataSource(IProjectThreadingService projectThreadingService, IActiveConfiguredProjectSubscriptionService activeProjectSubscriptionService)
+ : base(projectThreadingService.JoinableTaskContext)
+ {
+ _activeProjectSubscriptionService = activeProjectSubscriptionService;
+ }
+
+ public async Task> GetArgsAsync()
+ {
+ using (JoinableCollection.Join())
+ {
+ await this.InitializeAsync().ConfigureAwait(true);
+ return this.AppliedValue?.Value ?? ImmutableArray.Empty;
+ }
+ }
+
+ protected override bool BlockInitializeOnFirstAppliedValue => true;
+
+ protected override Task InitializeInnerCoreAsync(CancellationToken cancellationToken) => Task.CompletedTask;
+
+ protected override IDisposable LinkExternalInput(ITargetBlock> targetBlock)
+ {
+ JoinUpstreamDataSources(_activeProjectSubscriptionService.ProjectBuildRuleSource);
+ return _activeProjectSubscriptionService.ProjectBuildRuleSource.SourceBlock.LinkTo(target: targetBlock,
+ linkOptions: new DataflowLinkOptions { PropagateCompletion = true },
+ initialDataAsNew: true,
+ suppressVersionOnlyUpdates: true,
+ ruleNames: Constants.CommandLineArgsRuleName);
+ }
+
+ protected override Task>> PreprocessAsync(IProjectVersionedValue input, IProjectVersionedValue>? previousOutput)
+ {
+ if (input is null)
+ {
+ throw new ArgumentNullException(nameof(input));
+ }
+
+ var description = input.Value.ProjectChanges[Constants.CommandLineArgsRuleName];
+ return Task.FromResult>>(new ProjectVersionedValue>(description.After.Items.Keys.ToImmutableArray(), input.DataSourceVersions));
+ }
+
+ protected override Task ApplyAsync(IProjectVersionedValue> value)
+ {
+ AppliedValue = value;
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Constants.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Constants.cs
new file mode 100644
index 0000000000..3c8bb093d3
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Constants.cs
@@ -0,0 +1,17 @@
+// 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.
+
+namespace Roslyn.ComponentDebugger
+{
+ internal static class Constants
+ {
+ public const string RoslynComponentCapability = "RoslynComponent";
+
+ public const string CommandName = "DebugRoslynComponent";
+
+ public const string TargetProjectKeyName = "targetProject";
+
+ public const string CommandLineArgsRuleName = "CompilerCommandLineArgs";
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebugProfileProvider.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebugProfileProvider.cs
new file mode 100644
index 0000000000..5f2ca2b3e9
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebugProfileProvider.cs
@@ -0,0 +1,97 @@
+// 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;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.ComponentModel.Composition;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio;
+using Microsoft.VisualStudio.ProjectSystem;
+using Microsoft.VisualStudio.ProjectSystem.Debug;
+using Microsoft.VisualStudio.ProjectSystem.VS.Debug;
+using Microsoft.VisualStudio.Shell;
+using Microsoft.VisualStudio.Shell.Interop;
+using Microsoft.VisualStudio.Threading;
+using Task = System.Threading.Tasks.Task;
+
+namespace Roslyn.ComponentDebugger
+{
+ [Export(typeof(IDebugProfileLaunchTargetsProvider))]
+ [AppliesTo(Constants.RoslynComponentCapability)]
+ public class DebugProfileProvider : IDebugProfileLaunchTargetsProvider
+ {
+ private readonly ConfiguredProject _configuredProject;
+ private readonly LaunchSettingsManager _launchSettingsManager;
+ private readonly IProjectThreadingService _threadingService;
+ private readonly AsyncLazy _compilerRoot;
+
+ [ImportingConstructor]
+ [Obsolete("This exported object must be obtained through the MEF export provider.", error: true)]
+ public DebugProfileProvider(ConfiguredProject configuredProject, LaunchSettingsManager launchSettingsManager, SVsServiceProvider? serviceProvider, IProjectThreadingService threadingService)
+ {
+ _configuredProject = configuredProject;
+ _launchSettingsManager = launchSettingsManager;
+ _threadingService = threadingService;
+
+ _compilerRoot = new AsyncLazy(() => GetCompilerRootAsync(serviceProvider), _threadingService.JoinableTaskFactory);
+ }
+
+ public Task OnAfterLaunchAsync(DebugLaunchOptions launchOptions, ILaunchProfile profile) => Task.CompletedTask;
+
+ public Task OnBeforeLaunchAsync(DebugLaunchOptions launchOptions, ILaunchProfile profile) => Task.CompletedTask;
+
+ public bool SupportsProfile(ILaunchProfile? profile) => Constants.CommandName.Equals(profile?.CommandName, StringComparison.Ordinal);
+
+ public async Task> QueryDebugTargetsAsync(DebugLaunchOptions launchOptions, ILaunchProfile? profile)
+ {
+ // set up the managed (net fx) debugger to start a process
+ // https://github.com/dotnet/roslyn-sdk/issues/729
+ var settings = new DebugLaunchSettings(launchOptions)
+ {
+ LaunchDebugEngineGuid = Microsoft.VisualStudio.ProjectSystem.Debug.DebuggerEngines.ManagedOnlyEngine,
+ LaunchOperation = DebugLaunchOperation.CreateProcess
+ };
+
+ var compilerRoot = await _compilerRoot.GetValueAsync().ConfigureAwait(true);
+ if (compilerRoot is object)
+ {
+ // try and get the target project
+ var targetProjectUnconfigured = await _launchSettingsManager.TryGetProjectForLaunchAsync(profile).ConfigureAwait(true);
+ if (targetProjectUnconfigured is object)
+ {
+ settings.CurrentDirectory = Path.GetDirectoryName(targetProjectUnconfigured.FullPath);
+ var compiler = _configuredProject.Capabilities.Contains(ProjectCapabilities.VB) ? "vbc.exe" : "csc.exe";
+ settings.Executable = Path.Combine(compilerRoot, compiler);
+
+ // get its compilation args
+ var args = await targetProjectUnconfigured.GetCompilationArgumentsAsync().ConfigureAwait(true);
+
+ // append the command line args to the debugger launch
+ settings.Arguments = string.Join(" ", args);
+ }
+ }
+ // https://github.com/dotnet/roslyn-sdk/issues/728 : better error handling
+ return new IDebugLaunchSettings[] { settings };
+ }
+
+ private async Task GetCompilerRootAsync(SVsServiceProvider? serviceProvider)
+ {
+ await _threadingService.SwitchToUIThread();
+
+ // https://github.com/dotnet/roslyn-sdk/issues/729 : don't hardcode net fx compiler
+ var shell = (IVsShell?)serviceProvider?.GetService(typeof(SVsShell));
+ if (shell is object
+ && shell.GetProperty((int)__VSSPROPID2.VSSPROPID_InstallRootDir, out var rootDirObj) == VSConstants.S_OK
+ && rootDirObj is string rootDir)
+ {
+ return Path.Combine(rootDir, "MSBuild", "Current", "Bin", "Roslyn");
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml
new file mode 100644
index 0000000000..b431658e46
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptions.xaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptionsViewModel.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptionsViewModel.cs
new file mode 100644
index 0000000000..180012a97e
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/DebuggerOptionsViewModel.cs
@@ -0,0 +1,61 @@
+// 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;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.CompilerServices;
+
+namespace Roslyn.ComponentDebugger
+{
+ internal sealed class DebuggerOptionsViewModel : INotifyPropertyChanged
+ {
+ private readonly Action _indexChanged;
+
+ private IEnumerable _projectNames = ImmutableArray.Empty;
+
+ private int _selectedProjectIndex = -1;
+
+ public event PropertyChangedEventHandler? PropertyChanged;
+
+ public DebuggerOptionsViewModel(Action indexChanged)
+ {
+ _indexChanged = indexChanged;
+ }
+
+ public IEnumerable ProjectNames
+ {
+ get => _projectNames;
+ set
+ {
+ if (!_projectNames.SequenceEqual(value))
+ {
+ _projectNames = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public int SelectedProjectIndex
+ {
+ get => _selectedProjectIndex;
+ set
+ {
+ if (_selectedProjectIndex != value)
+ {
+ _selectedProjectIndex = value;
+ NotifyPropertyChanged();
+ _indexChanged?.Invoke(value);
+ }
+ }
+ }
+
+ private void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
+ {
+ this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsManager.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsManager.cs
new file mode 100644
index 0000000000..6d9c972364
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsManager.cs
@@ -0,0 +1,59 @@
+// 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.ComponentModel.Composition;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.ProjectSystem;
+using Microsoft.VisualStudio.ProjectSystem.Debug;
+
+namespace Roslyn.ComponentDebugger
+{
+ [Export]
+ public class LaunchSettingsManager
+ {
+ private readonly UnconfiguredProject _owningProject;
+ private readonly IDebugTokenReplacer _tokenReplacer;
+
+ [ImportingConstructor]
+ public LaunchSettingsManager(UnconfiguredProject owningProject, IDebugTokenReplacer tokenReplacer)
+ {
+ _owningProject = owningProject;
+ _tokenReplacer = tokenReplacer;
+ }
+
+ public async Task TryGetProjectForLaunchAsync(ILaunchProfile? profile)
+ {
+ UnconfiguredProject? targetProject = null;
+ object? value = null;
+ profile?.OtherSettings?.TryGetValue(Constants.TargetProjectKeyName, out value);
+
+ if (value is string targetProjectPath)
+ {
+ // expand any variables in the path, and root it based on this project
+ var replacedProjectPath = await _tokenReplacer.ReplaceTokensInStringAsync(targetProjectPath, true).ConfigureAwait(true);
+ replacedProjectPath = _owningProject.MakeRooted(replacedProjectPath);
+
+ targetProject = ((IProjectService2)_owningProject.Services.ProjectService).GetLoadedProject(replacedProjectPath);
+ }
+ return targetProject;
+ }
+
+ public void WriteProjectForLaunch(IWritableLaunchProfile profile, UnconfiguredProject targetProject)
+ {
+ if (profile is null)
+ {
+ throw new System.ArgumentNullException(nameof(profile));
+ }
+
+ if (targetProject is null)
+ {
+ throw new System.ArgumentNullException(nameof(targetProject));
+ }
+
+ var rootedPath = _owningProject.MakeRelative(targetProject.FullPath);
+ profile.OtherSettings[Constants.TargetProjectKeyName] = rootedPath;
+ }
+
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsProvider.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsProvider.cs
new file mode 100644
index 0000000000..43b54a2d7f
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/LaunchSettingsProvider.cs
@@ -0,0 +1,101 @@
+// 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;
+using System.Collections.Immutable;
+using System.ComponentModel.Composition;
+using System.IO;
+using System.Linq;
+using System.Windows.Controls;
+using Microsoft.VisualStudio.ProjectSystem;
+using Microsoft.VisualStudio.ProjectSystem.Debug;
+using Microsoft.VisualStudio.Utilities;
+using Task = System.Threading.Tasks.Task;
+
+namespace Roslyn.ComponentDebugger
+{
+ [Export(typeof(ILaunchSettingsUIProvider))]
+ [AppliesTo(Constants.RoslynComponentCapability)]
+ public class LaunchSettingsProvider : ILaunchSettingsUIProvider
+ {
+ private readonly IProjectThreadingService _threadingService;
+ private readonly UnconfiguredProject _unconfiguredProject;
+ private readonly LaunchSettingsManager _launchSettingsManager;
+ private readonly DebuggerOptionsViewModel _viewModel;
+
+ private ImmutableArray _projects;
+ private IWritableLaunchProfile? _launchProfile;
+
+ [ImportingConstructor]
+ [Obsolete("This exported object must be obtained through the MEF export provider.", error: true)]
+ public LaunchSettingsProvider(IProjectThreadingService threadingService, UnconfiguredProject unconfiguredProject, LaunchSettingsManager launchSettingsManager)
+ {
+ _threadingService = threadingService;
+ _unconfiguredProject = unconfiguredProject;
+ _launchSettingsManager = launchSettingsManager;
+ _viewModel = new DebuggerOptionsViewModel(IndexChanged);
+ }
+
+ public string CommandName { get => Constants.CommandName; }
+
+ // https://github.com/dotnet/roslyn-sdk/issues/730 : localization
+ public string FriendlyName { get => "Roslyn Component"; }
+
+ public UserControl? CustomUI { get => new DebuggerOptions() { DataContext = _viewModel }; }
+
+ public void ProfileSelected(IWritableLaunchSettings curSettings)
+ {
+ _launchProfile = curSettings?.ActiveProfile;
+ _threadingService.ExecuteSynchronously(UpdateViewModelAsync);
+ }
+
+ public bool ShouldEnableProperty(string propertyName)
+ {
+ // we disable all the default options for a debugger.
+ // in the future we might want to enable env vars and (potentially) the exe to allow
+ // customization of the compiler used?
+ return false;
+ }
+
+ private async Task UpdateViewModelAsync()
+ {
+ var targetProjects = ArrayBuilder.GetInstance();
+
+ // get the output assembly for this project
+ var projectArgs = await _unconfiguredProject.GetCompilationArgumentsAsync().ConfigureAwait(false);
+ var targetArg = projectArgs.LastOrDefault(a => a.StartsWith("/out:", StringComparison.OrdinalIgnoreCase));
+ var target = Path.GetFileName(targetArg);
+
+ var projectService = _unconfiguredProject.Services.ProjectService;
+ foreach (var targetProjectUnconfigured in projectService.LoadedUnconfiguredProjects)
+ {
+ // check if the args contain the project as an analyzer ref
+ foreach (var arg in await targetProjectUnconfigured.GetCompilationArgumentsAsync().ConfigureAwait(false))
+ {
+ if (arg.StartsWith("/analyzer:", StringComparison.OrdinalIgnoreCase)
+ && arg.EndsWith(target, StringComparison.OrdinalIgnoreCase))
+ {
+ targetProjects.Add(targetProjectUnconfigured);
+ }
+ }
+ }
+ _projects = targetProjects.ToImmutableAndFree();
+
+ var launchTargetProject = await _launchSettingsManager.TryGetProjectForLaunchAsync(_launchProfile?.ToLaunchProfile()).ConfigureAwait(true);
+ var index = _projects.IndexOf(launchTargetProject!);
+
+ _viewModel.ProjectNames = _projects.Select(p => Path.GetFileNameWithoutExtension(p.FullPath));
+ _viewModel.SelectedProjectIndex = index;
+ }
+
+ private void IndexChanged(int newIndex)
+ {
+ if (_launchProfile is object && !_projects.IsDefaultOrEmpty && newIndex >= 0 && newIndex < _projects.Length)
+ {
+ var project = _projects[newIndex];
+ _launchSettingsManager.WriteProjectForLaunch(_launchProfile, project);
+ }
+ }
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/ProjectUtilities.cs b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/ProjectUtilities.cs
new file mode 100644
index 0000000000..b20cc31159
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/ProjectUtilities.cs
@@ -0,0 +1,30 @@
+// 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;
+using System.Collections.Immutable;
+using System.Threading.Tasks;
+using Microsoft.VisualStudio.ProjectSystem;
+
+namespace Roslyn.ComponentDebugger
+{
+ public static class ProjectUtilities
+ {
+ public static Task> GetCompilationArgumentsAsync(this UnconfiguredProject project)
+ {
+ if (project is null)
+ {
+ throw new ArgumentNullException(nameof(project));
+ }
+
+ var dataSource = project.Services.ExportProvider.GetExportedValueOrDefault();
+ if (dataSource is object)
+ {
+ return dataSource.GetArgsAsync();
+ }
+
+ return Task.FromResult(ImmutableArray.Empty);
+ }
+ }
+}
diff --git a/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj
new file mode 100644
index 0000000000..37bb4c8b98
--- /dev/null
+++ b/src/VisualStudio.Roslyn.SDK/ComponentDebugger/Roslyn.ComponentDebugger.csproj
@@ -0,0 +1,40 @@
+
+
+
+
+ Library
+ Roslyn.ComponentDebugger
+ net472
+ enable
+ NU1603;NU1605
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj
index b04a9074b2..370c4ea744 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/Roslyn.SDK.csproj
@@ -120,5 +120,15 @@
true
false
+
+ Roslyn.ComponentDebugger
+ BuiltProjectOutputGroup%3bGetCopyToOutputDirectoryItems%3b
+ DebugSymbolsProjectOutputGroup%3b
+ true
+ false
+
+
+
+
diff --git a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/source.extension.vsixmanifest b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/source.extension.vsixmanifest
index 8d8661a4ee..a091d5313b 100644
--- a/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/source.extension.vsixmanifest
+++ b/src/VisualStudio.Roslyn.SDK/Roslyn.SDK/source.extension.vsixmanifest
@@ -30,6 +30,7 @@
+