diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/BuildHostProcessManager.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/BuildHostProcessManager.cs index 25ce59ab9279a..a035a75aac6f3 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/BuildHostProcessManager.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/BuildHostProcessManager.cs @@ -29,27 +29,39 @@ public BuildHostProcessManager(ILoggerFactory? loggerFactory = null, string? bin _binaryLogPath = binaryLogPath; } - public async Task GetBuildHostAsync(string projectFilePath, CancellationToken cancellationToken) + /// + /// Returns the best to use for this project; if it picked a fallback option because the preferred kind was unavailable, that's returned too, otherwise null. + /// + public async Task<(IBuildHost, BuildHostProcessKind? PreferredKind)> GetBuildHostAsync(string projectFilePath, CancellationToken cancellationToken) { var neededBuildHostKind = GetKindForProject(projectFilePath); + BuildHostProcessKind? preferredKind = null; _logger?.LogTrace($"Choosing a build host of type {neededBuildHostKind} for {projectFilePath}."); + if (neededBuildHostKind == BuildHostProcessKind.Mono && MonoMSBuildDiscovery.GetMonoMSBuildDirectory() == null) + { + _logger?.LogWarning($"An installation of Mono could not be found; {projectFilePath} will be loaded with the .NET Core SDK and may encounter errors."); + neededBuildHostKind = BuildHostProcessKind.NetCore; + preferredKind = BuildHostProcessKind.Mono; + } + var buildHost = await GetBuildHostAsync(neededBuildHostKind, cancellationToken).ConfigureAwait(false); // If this is a .NET Framework build host, we may not have have build tools installed and thus can't actually use it to build. - // Check if this is the case. + // Check if this is the case. Unlike the mono case, we have to actually ask the other process since MSBuildLocator only allows + // us to discover VS instances in .NET Framework hosts right now. if (neededBuildHostKind == BuildHostProcessKind.NetFramework) { if (!await buildHost.HasUsableMSBuildAsync(projectFilePath, cancellationToken)) { // It's not usable, so we'll fall back to the .NET Core one. _logger?.LogWarning($"An installation of Visual Studio or the Build Tools for Visual Studio could not be found; {projectFilePath} will be loaded with the .NET Core SDK and may encounter errors."); - return await GetBuildHostAsync(BuildHostProcessKind.NetCore, cancellationToken); + return (await GetBuildHostAsync(BuildHostProcessKind.NetCore, cancellationToken), PreferredKind: BuildHostProcessKind.NetFramework); } } - return buildHost; + return (buildHost, preferredKind); } public async Task GetBuildHostAsync(BuildHostProcessKind buildHostKind, CancellationToken cancellationToken) @@ -58,13 +70,17 @@ public async Task GetBuildHostAsync(BuildHostProcessKind buildHostKi { if (!_processes.TryGetValue(buildHostKind, out var buildHostProcess)) { - var process = buildHostKind switch + var processStartInfo = buildHostKind switch { - BuildHostProcessKind.NetCore => LaunchDotNetCoreBuildHost(), - BuildHostProcessKind.NetFramework => LaunchDotNetFrameworkBuildHost(), + BuildHostProcessKind.NetCore => CreateDotNetCoreBuildHostStartInfo(), + BuildHostProcessKind.NetFramework => CreateDotNetFrameworkBuildHostStartInfo(), + BuildHostProcessKind.Mono => CreateMonoBuildHostStartInfo(), _ => throw ExceptionUtilities.UnexpectedValue(buildHostKind) }; + var process = Process.Start(processStartInfo); + Contract.ThrowIfNull(process, "Process.Start failed to launch a process."); + buildHostProcess = new BuildHostProcess(process, _loggerFactory); buildHostProcess.Disconnected += BuildHostProcess_Disconnected; _processes.Add(buildHostKind, buildHostProcess); @@ -108,7 +124,7 @@ public async ValueTask DisposeAsync() await process.DisposeAsync(); } - private Process LaunchDotNetCoreBuildHost() + private ProcessStartInfo CreateDotNetCoreBuildHostStartInfo() { var processStartInfo = new ProcessStartInfo() { @@ -125,16 +141,12 @@ private Process LaunchDotNetCoreBuildHost() AppendBuildHostCommandLineArgumentsConfigureProcess(processStartInfo); - var process = Process.Start(processStartInfo); - Contract.ThrowIfNull(process, "Process.Start failed to launch a process."); - return process; + return processStartInfo; } - private Process LaunchDotNetFrameworkBuildHost() + private ProcessStartInfo CreateDotNetFrameworkBuildHostStartInfo() { - var netFrameworkBuildHost = Path.Combine(Path.GetDirectoryName(typeof(BuildHostProcessManager).Assembly.Location)!, "BuildHost-net472", "Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.exe"); - Contract.ThrowIfFalse(File.Exists(netFrameworkBuildHost), $"Unable to locate the .NET Framework build host at {netFrameworkBuildHost}"); - + var netFrameworkBuildHost = GetPathToDotNetFrameworkBuildHost(); var processStartInfo = new ProcessStartInfo() { FileName = netFrameworkBuildHost, @@ -142,9 +154,28 @@ private Process LaunchDotNetFrameworkBuildHost() AppendBuildHostCommandLineArgumentsConfigureProcess(processStartInfo); - var process = Process.Start(processStartInfo); - Contract.ThrowIfNull(process, "Process.Start failed to launch a process."); - return process; + return processStartInfo; + } + + private ProcessStartInfo CreateMonoBuildHostStartInfo() + { + var processStartInfo = new ProcessStartInfo + { + FileName = "mono" + }; + + processStartInfo.ArgumentList.Add(GetPathToDotNetFrameworkBuildHost()); + + AppendBuildHostCommandLineArgumentsConfigureProcess(processStartInfo); + + return processStartInfo; + } + + private static string GetPathToDotNetFrameworkBuildHost() + { + var netFrameworkBuildHost = Path.Combine(Path.GetDirectoryName(typeof(BuildHostProcessManager).Assembly.Location)!, "BuildHost-net472", "Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost.exe"); + Contract.ThrowIfFalse(File.Exists(netFrameworkBuildHost), $"Unable to locate the .NET Framework build host at {netFrameworkBuildHost}"); + return netFrameworkBuildHost; } private void AppendBuildHostCommandLineArgumentsConfigureProcess(ProcessStartInfo processStartInfo) @@ -173,10 +204,6 @@ private void AppendBuildHostCommandLineArgumentsConfigureProcess(ProcessStartInf private static BuildHostProcessKind GetKindForProject(string projectFilePath) { - // At the moment we don't have mono support here, so if we're not on Windows, we'll always force to .NET Core. - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return BuildHostProcessKind.NetCore; - // This implements the algorithm as stated in https://github.com/dotnet/project-system/blob/9a761848e0f330a45e349685a266fea00ac3d9c5/docs/opening-with-new-project-system.md; // we'll load the XML of the project directly, and inspect for certain elements. XDocument document; @@ -208,13 +235,14 @@ private static BuildHostProcessKind GetKindForProject(string projectFilePath) return BuildHostProcessKind.NetCore; // Nothing that indicates it's an SDK-style project, so use our .NET framework host - return BuildHostProcessKind.NetFramework; + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? BuildHostProcessKind.NetFramework : BuildHostProcessKind.Mono; } public enum BuildHostProcessKind { NetCore, - NetFramework + NetFramework, + Mono } private sealed class BuildHostProcess : IAsyncDisposable diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs index 82a1090a5474f..0e187df5c44c4 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/HostWorkspace/LanguageServerProjectSystem.cs @@ -6,6 +6,7 @@ using System.Collections.Immutable; using System.Composition; using System.Diagnostics; +using System.Runtime.InteropServices; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; @@ -18,6 +19,7 @@ using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.Composition; using Roslyn.Utilities; +using static Microsoft.CodeAnalysis.LanguageServer.HostWorkspace.BuildHostProcessManager; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.HostWorkspace; @@ -96,7 +98,10 @@ public async Task OpenSolutionAsync(string solutionFilePath) // If we don't have a .NET Core SDK on this machine at all, try .NET Framework if (!await buildHost.HasUsableMSBuildAsync(solutionFilePath, CancellationToken.None)) - buildHost = await buildHostProcessManager.GetBuildHostAsync(BuildHostProcessManager.BuildHostProcessKind.NetFramework, CancellationToken.None); + { + var kind = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? BuildHostProcessKind.NetFramework : BuildHostProcessKind.Mono; + buildHost = await buildHostProcessManager.GetBuildHostAsync(kind, CancellationToken.None); + } foreach (var project in await buildHost.GetProjectsInSolutionAsync(solutionFilePath, CancellationToken.None)) { @@ -144,14 +149,22 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList { - var errorKind = await LoadOrReloadProjectAsync(projectToLoad, buildHostProcessManager, cancellationToken); + var (errorKind, preferredBuildHostKind) = await LoadOrReloadProjectAsync(projectToLoad, buildHostProcessManager, cancellationToken); if (errorKind is LSP.MessageType.Error) { // We should display a toast when the value of displayedToast is 0. This will also update the value to 1 meaning we won't send any more toasts. var shouldShowToast = Interlocked.CompareExchange(ref displayedToast, value: 1, comparand: 0) == 0; if (shouldShowToast) { - var message = string.Format(LanguageServerResources.There_were_problems_loading_project_0_See_log_for_details, Path.GetFileName(projectToLoad.Path)); + string message; + + if (preferredBuildHostKind == BuildHostProcessKind.NetFramework) + message = LanguageServerResources.Projects_failed_to_load_because_MSBuild_could_not_be_found; + else if (preferredBuildHostKind == BuildHostProcessKind.Mono) + message = LanguageServerResources.Projects_failed_to_load_because_Mono_could_not_be_found; + else + message = string.Format(LanguageServerResources.There_were_problems_loading_project_0_See_log_for_details, Path.GetFileName(projectToLoad.Path)); + await ShowToastNotification.ShowToastNotificationAsync(errorKind.Value, message, cancellationToken, ShowToastNotification.ShowCSharpLogsCommand); } } @@ -179,13 +192,15 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList LoadOrReloadProjectAsync(ProjectToLoad projectToLoad, BuildHostProcessManager buildHostProcessManager, CancellationToken cancellationToken) + private async Task<(LSP.MessageType? failureType, BuildHostProcessKind? preferredKind)> LoadOrReloadProjectAsync(ProjectToLoad projectToLoad, BuildHostProcessManager buildHostProcessManager, CancellationToken cancellationToken) { + BuildHostProcessKind? preferredBuildHostKind = null; + try { var projectPath = projectToLoad.Path; - var buildHost = await buildHostProcessManager!.GetBuildHostAsync(projectPath, cancellationToken); + (var buildHost, preferredBuildHostKind) = await buildHostProcessManager!.GetBuildHostAsync(projectPath, cancellationToken); if (await buildHost.IsProjectFileSupportedAsync(projectPath, cancellationToken)) { @@ -197,7 +212,7 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList(projectLanguage) == null) { - return null; + return (null, null); } var existingProjects = _loadedProjects.GetOrAdd(projectPath, static _ => new List()); @@ -242,21 +257,21 @@ private async ValueTask LoadOrReloadProjectsAsync(ImmutableSegmentedList logItem.Kind is WorkspaceDiagnosticKind.Failure) ? LSP.MessageType.Error : LSP.MessageType.Warning; + return (diagnosticLogItems.Any(logItem => logItem.Kind is WorkspaceDiagnosticKind.Failure) ? LSP.MessageType.Error : LSP.MessageType.Warning, preferredBuildHostKind); } else { _logger.LogInformation($"Successfully completed load of {projectPath}"); - return null; + return (null, null); } } - return null; + return (null, null); } catch (Exception e) { _logger.LogError(e, $"Exception thrown while loading {projectToLoad.Path}"); - return LSP.MessageType.Error; + return (LSP.MessageType.Error, preferredBuildHostKind); } } } diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx index d0b08a3fe8e1c..cca0bf9b5fb4a 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/LanguageServerResources.resx @@ -162,6 +162,12 @@ Passed! + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Running tests... @@ -192,12 +198,6 @@ There were problems loading project {0}. See log for details. - - There were errors loading solution {0}. See log for details. - - - There were problems loading your projects. See log for details. - Using .runsettings file at {0} diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf index 3bbbc9bd995a7..2f89ee777207a 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.cs.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ Při načítání {0} projektu došlo k potížím. Podrobnosti najdete v protokolu. - - There were errors loading solution {0}. See log for details. - Při načítání {0} řešení došlo k chybám. Podrobnosti najdete v protokolu. - - - - There were problems loading your projects. See log for details. - Při načítání vašich projektů došlo k potížím. Podrobnosti najdete v protokolu. - - Using .runsettings file at {0} Použití souboru .runsettings v {0} diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.de.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.de.xlf index 10409ad55fa79..a00f1f9b7f641 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.de.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.de.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ Problem beim Laden der projekt {0}. Weitere Informationen finden Sie im Protokoll. - - There were errors loading solution {0}. See log for details. - Fehler beim Laden der Projektmappe {0}. Weitere Informationen finden Sie im Protokoll. - - - - There were problems loading your projects. See log for details. - Beim Laden Ihrer Projekte sind Probleme aufgetreten. Weitere Informationen finden Sie im Protokoll. - - Using .runsettings file at {0} Verwenden der RUNSETTINGS-Datei unter {0} diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.es.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.es.xlf index 9a901b57c98f2..30e937255012e 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.es.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.es.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ Hubo problemas al cargar el {0} del proyecto. Consulte el registro para obtener más detalles. - - There were errors loading solution {0}. See log for details. - Se produjeron errores al cargar la solución {0}. Consulte el registro para obtener más detalles. - - - - There were problems loading your projects. See log for details. - Hubo problemas al cargar los proyectos. Consulte el registro para obtener más detalles. - - Using .runsettings file at {0} Uso del archivo .runsettings en {0} diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.fr.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.fr.xlf index 01ac238eb3ac6..1ab5beb047a80 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.fr.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.fr.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ Des problèmes se sont produits lors du chargement des {0} du projet. Pour plus d’informations, consultez le journal. - - There were errors loading solution {0}. See log for details. - Des erreurs se sont produites lors du chargement de la solution {0}. Pour plus d’informations, consultez le journal. - - - - There were problems loading your projects. See log for details. - Des problèmes se sont produits lors du chargement de vos projets. Pour plus d’informations, consultez le journal. - - Using .runsettings file at {0} Utilisation du fichier .runsettings sur {0} diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.it.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.it.xlf index 9b1dc1040bdd1..a49db33554665 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.it.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.it.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ Si sono verificati problemi durante il caricamento del progetto {0}. Per i dettagli, vedere il log. - - There were errors loading solution {0}. See log for details. - Si sono verificati errori durante il caricamento della soluzione {0}. Per i dettagli, vedere il log. - - - - There were problems loading your projects. See log for details. - Si sono verificati problemi durante il caricamento dei progetti. Per i dettagli, vedere il log. - - Using .runsettings file at {0} Uso del file con estensione runsettings in {0} diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ja.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ja.xlf index 0f227dee90ad8..1c5e5f6706613 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ja.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ja.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ プロジェクト {0} の読み込み中に問題が発生しました。詳細については、ログを参照してください。 - - There were errors loading solution {0}. See log for details. - ソリューション {0} の読み込み中にエラーが発生しました。詳細については、ログを参照してください。 - - - - There were problems loading your projects. See log for details. - プロジェクトの読み込み中に問題が発生しました。詳細については、ログを参照してください。 - - Using .runsettings file at {0} {0} の runsettings ファイルを使用しています diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ko.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ko.xlf index 62b67bc7725b3..410a0bac339d2 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ko.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ko.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ 프로젝트 {0} 로드하는 동안 문제가 발생했습니다. 자세한 내용은 로그를 참조하세요. - - There were errors loading solution {0}. See log for details. - 솔루션 {0} 로드하는 동안 오류가 발생했습니다. 자세한 내용은 로그를 참조하세요. - - - - There were problems loading your projects. See log for details. - 프로젝트를 로드하는 동안 문제가 발생했습니다. 자세한 내용은 로그를 참조하세요. - - Using .runsettings file at {0} {0}에서 runsettings 파일을 사용하는 중 diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pl.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pl.xlf index bde55e4abca31..71cc23474c90a 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pl.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pl.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ Wystąpiły problemy podczas ładowania {0} projektu. Zobacz dziennik, aby uzyskać szczegółowe informacje. - - There were errors loading solution {0}. See log for details. - Wystąpiły błędy podczas ładowania {0} rozwiązania. Zobacz dziennik, aby uzyskać szczegółowe informacje. - - - - There were problems loading your projects. See log for details. - Wystąpiły problemy podczas ładowania projektów. Zobacz dziennik, aby uzyskać szczegółowe informacje. - - Using .runsettings file at {0} Używanie pliku .runsettings w {0} diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pt-BR.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pt-BR.xlf index dfd8c5469ea55..103c509e40569 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pt-BR.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.pt-BR.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ Houve problemas ao carregar o projeto {0}. Consulte o log para obter detalhes. - - There were errors loading solution {0}. See log for details. - Ocorreram erros ao carregar a solução {0}. Consulte o log para obter detalhes. - - - - There were problems loading your projects. See log for details. - Houve problemas ao carregar seus projetos. Consulte o log para obter detalhes. - - Using .runsettings file at {0} Usando o arquivo .runsettings em {0} diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ru.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ru.xlf index 6be521916394d..20a605e91185e 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ru.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.ru.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ Возникли проблемы при загрузке {0}. Дополнительные сведения см. в журнале. - - There were errors loading solution {0}. See log for details. - Произошли ошибки при загрузке {0}. Дополнительные сведения см. в журнале. - - - - There were problems loading your projects. See log for details. - Возникли проблемы при загрузке проектов. Дополнительные сведения см. в журнале. - - Using .runsettings file at {0} Использование файла RUNSETTINGS в {0} diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.tr.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.tr.xlf index 3021151d1bac0..5c0767f8ddf94 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.tr.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.tr.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ Proje ayarları yüklenirken sorun {0}. Ayrıntılar için günlüğe bakın. - - There were errors loading solution {0}. See log for details. - Çözüm dosyası yüklenirken hatalar {0}. Ayrıntılar için günlüğe bakın. - - - - There were problems loading your projects. See log for details. - Projeleriniz yüklenirken sorun oluştu. Ayrıntılar için günlüğe bakın. - - Using .runsettings file at {0} Şu konumdaki .runsettings dosyası kullanılıyor: {0} diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hans.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hans.xlf index 8ec22e089237d..4082cfcbf374f 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hans.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hans.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ 加载项目 {0} 时出现问题。有关详细信息,请参阅日志。 - - There were errors loading solution {0}. See log for details. - 加载解决方案 {0} 时出错。有关详细信息,请参阅日志。 - - - - There were problems loading your projects. See log for details. - 加载项目时出现问题。有关详细信息,请参阅日志。 - - Using .runsettings file at {0} 在 {0} 使用 .runsettings 文件 diff --git a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hant.xlf b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hant.xlf index cf375bc274739..ede8aec66e52c 100644 --- a/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hant.xlf +++ b/src/Features/LanguageServer/Microsoft.CodeAnalysis.LanguageServer/xlf/LanguageServerResources.zh-Hant.xlf @@ -77,6 +77,16 @@ Passed! + + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + Projects failed to load because the .NET Framework build tools could not be found. Try installing Visual Studio or the Visual Studio Build Tools package, or check the logs for details. + + + + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + Projects failed to load because the Mono could not be found. Ensure that Mono and MSBuild are installed, and check the logs for details. + + Running tests... Running tests... @@ -127,16 +137,6 @@ 載入專案 {0} 時發生問題。如需詳細資料,請參閱記錄檔。 - - There were errors loading solution {0}. See log for details. - 載入解決方案 {0} 時發生錯誤。如需詳細資料,請參閱記錄檔。 - - - - There were problems loading your projects. See log for details. - 載入您的專案時發生問題。如需詳細資料,請參閱記錄檔。 - - Using .runsettings file at {0} 使用位於 {0} 的 .runsettings 檔案 diff --git a/src/Workspaces/Core/MSBuild.BuildHost/BuildHost.cs b/src/Workspaces/Core/MSBuild.BuildHost/BuildHost.cs index 652c07e88c768..6b86acc4cde61 100644 --- a/src/Workspaces/Core/MSBuild.BuildHost/BuildHost.cs +++ b/src/Workspaces/Core/MSBuild.BuildHost/BuildHost.cs @@ -43,36 +43,61 @@ private bool TryEnsureMSBuildLoaded(string projectOrSolutionFilePath) return true; } - VisualStudioInstance? instance; + if (!PlatformInformation.IsRunningOnMono) + { + + VisualStudioInstance? instance; #if NETFRAMEWORK - // In this case, we're just going to pick the highest VS install on the machine, in case the projects are using some newer - // MSBuild features. Since we don't have something like a global.json we can't really know what the minimum version is. + // In this case, we're just going to pick the highest VS install on the machine, in case the projects are using some newer + // MSBuild features. Since we don't have something like a global.json we can't really know what the minimum version is. - // TODO: we should also check that the managed tools are actually installed - instance = MSBuildLocator.QueryVisualStudioInstances().OrderByDescending(vs => vs.Version).FirstOrDefault(); + // TODO: we should also check that the managed tools are actually installed + instance = MSBuildLocator.QueryVisualStudioInstances().OrderByDescending(vs => vs.Version).FirstOrDefault(); #else - // Locate the right SDK for this particular project; MSBuildLocator ensures in this case the first one is the preferred one. - // TODO: we should pick the appropriate instance back in the main process and just use the one chosen here. - var options = new VisualStudioInstanceQueryOptions { DiscoveryTypes = DiscoveryType.DotNetSdk, WorkingDirectory = Path.GetDirectoryName(projectOrSolutionFilePath) }; - instance = MSBuildLocator.QueryVisualStudioInstances(options).FirstOrDefault(); + // Locate the right SDK for this particular project; MSBuildLocator ensures in this case the first one is the preferred one. + // TODO: we should pick the appropriate instance back in the main process and just use the one chosen here. + var options = new VisualStudioInstanceQueryOptions { DiscoveryTypes = DiscoveryType.DotNetSdk, WorkingDirectory = Path.GetDirectoryName(projectOrSolutionFilePath) }; + instance = MSBuildLocator.QueryVisualStudioInstances(options).FirstOrDefault(); #endif - if (instance != null) - { - MSBuildLocator.RegisterInstance(instance); - _logger.LogInformation($"Registered MSBuild instance at {instance.MSBuildPath}"); - return true; + if (instance != null) + { + MSBuildLocator.RegisterInstance(instance); + _logger.LogInformation($"Registered MSBuild instance at {instance.MSBuildPath}"); + } + else + { + _logger.LogCritical("No compatible MSBuild instance could be found."); + } } else { - _logger.LogCritical("No compatible MSBuild instance could be found."); - return false; +#if NETFRAMEWORK + + // We're running on Mono, but not all Mono installations have a usable MSBuild installation, so let's see if we have one that we can use. + var monoMSBuildDirectory = MonoMSBuildDiscovery.GetMonoMSBuildDirectory(); + + if (monoMSBuildDirectory != null) + { + MSBuildLocator.RegisterMSBuildPath(monoMSBuildDirectory); + _logger.LogInformation($"Registered MSBuild instance at {monoMSBuildDirectory}"); + } + else + { + _logger.LogCritical("No Mono MSBuild installation could be found; see https://www.mono-project.com/ for installation instructions."); + } + +#else + _logger.LogCritical("Trying to run the .NET Core BuildHost on Mono is unsupported."); +#endif } + + return MSBuildLocator.IsRegistered; } } @@ -117,9 +142,20 @@ private void EnsureMSBuildLoaded(string projectFilePath) [MethodImpl(MethodImplOptions.NoInlining)] // Do not inline this, since this uses MSBuild types which are being loaded by the caller private static ImmutableArray<(string ProjectPath, string ProjectGuid)> GetProjectsInSolution(string solutionFilePath) { - return SolutionFile.Parse(solutionFilePath).ProjectsInOrder - .Where(static p => p.ProjectType != SolutionProjectType.SolutionFolder) - .SelectAsArray(static p => (p.AbsolutePath, p.ProjectGuid)); + // WARNING: do not use a lambda in this function, as it internally will be put in a class that contains other lambdas used in + // TryEnsureMSBuildLoaded; on Mono this causes type load errors. + + var builder = ImmutableArray.CreateBuilder<(string ProjectPath, string ProjectGuid)>(); + + foreach (var project in SolutionFile.Parse(solutionFilePath).ProjectsInOrder) + { + if (project.ProjectType != SolutionProjectType.SolutionFolder) + { + builder.Add((project.AbsolutePath, project.ProjectGuid)); + } + } + + return builder.ToImmutable(); } public Task IsProjectFileSupportedAsync(string projectFilePath, CancellationToken cancellationToken) diff --git a/src/Workspaces/Core/MSBuild.BuildHost/MonoMSBuildDiscovery.cs b/src/Workspaces/Core/MSBuild.BuildHost/MonoMSBuildDiscovery.cs new file mode 100644 index 0000000000000..4aae5204d4042 --- /dev/null +++ b/src/Workspaces/Core/MSBuild.BuildHost/MonoMSBuildDiscovery.cs @@ -0,0 +1,162 @@ +// 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.IO; +using System.Linq; +using System.Runtime.InteropServices; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Workspaces.MSBuild.BuildHost; + +internal static class MonoMSBuildDiscovery +{ + private static IEnumerable? s_searchPaths; + private static string? s_monoRuntimeExecutablePath; + private static string? s_monoLibDirPath; + private static string? s_monoMSBuildDirectory; + + private static IEnumerable GetSearchPaths() + { + if (s_searchPaths == null) + { + var path = Environment.GetEnvironmentVariable("PATH"); + if (path == null) + { + return Array.Empty(); + } + + s_searchPaths = path + .Split(Path.PathSeparator) + .Select(p => p.Trim('"')); + } + + return s_searchPaths; + } + + // http://man7.org/linux/man-pages/man3/realpath.3.html + // CharSet.Ansi is UTF8 on Unix + [DllImport("libc", EntryPoint = "realpath", CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr Unix_realpath(string path, IntPtr buffer); + + // http://man7.org/linux/man-pages/man3/free.3.html + [DllImport("libc", EntryPoint = "free", ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)] + private static extern void Unix_free(IntPtr ptr); + + /// + /// Returns the canonicalized absolute path from a given path, expanding symbolic links and resolving + /// references to /./, /../ and extra '/' path characters. + /// + private static string? RealPath(string path) + { + if (PlatformInformation.IsWindows) + { + throw new PlatformNotSupportedException($"{nameof(RealPath)} can only be called on Unix."); + } + + var ptr = Unix_realpath(path, IntPtr.Zero); + var result = Marshal.PtrToStringAnsi(ptr); // uses UTF8 on Unix + Unix_free(ptr); + + return result; + } + + /// + /// Returns the fully qualified path to the mono executable. + /// + private static string? GetMonoRuntimeExecutablePath() + { + Contract.ThrowIfTrue(PlatformInformation.IsWindows); + + if (s_monoRuntimeExecutablePath == null) + { + var monoPath = GetSearchPaths() + .Select(p => Path.Combine(p, "mono")) + .FirstOrDefault(File.Exists); + + if (monoPath == null) + { + return null; + } + + s_monoRuntimeExecutablePath = RealPath(monoPath); + } + + return s_monoRuntimeExecutablePath; + } + + /// + /// Returns the path to the mono lib directory, usually /usr/bin/mono. + /// + private static string? GetMonoLibDirPath() + { + Contract.ThrowIfTrue(PlatformInformation.IsWindows); + + const string DefaultMonoLibPath = "/usr/lib/mono"; + if (Directory.Exists(DefaultMonoLibPath)) + { + return DefaultMonoLibPath; + } + + // The normal Unix path doesn't exist, so we'll fallback to finding Mono using the + // runtime location. This is the likely situation on macOS. + + if (s_monoLibDirPath == null) + { + var monoRuntimePath = GetMonoRuntimeExecutablePath(); + if (monoRuntimePath == null) + { + return null; + } + + var monoDirPath = Path.GetDirectoryName(monoRuntimePath)!; + + var monoLibDirPath = Path.Combine(monoDirPath, "..", "lib", "mono"); + monoLibDirPath = Path.GetFullPath(monoLibDirPath); + + s_monoLibDirPath = Directory.Exists(monoLibDirPath) + ? monoLibDirPath + : null; + } + + return s_monoLibDirPath; + } + + /// + /// Returns the path to MSBuild, the actual directory containing MSBuild.dll and friends. Usually should end in Current/bin. + /// + public static string? GetMonoMSBuildDirectory() + { + Contract.ThrowIfTrue(PlatformInformation.IsWindows); + + if (s_monoMSBuildDirectory == null) + { + var monoLibDirPath = GetMonoLibDirPath(); + if (monoLibDirPath == null) + return null; + + var monoMSBuildDirPath = Path.Combine(monoLibDirPath, "msbuild"); + var monoMSBuildDir = new DirectoryInfo(Path.GetFullPath(monoMSBuildDirPath)); + + if (!monoMSBuildDir.Exists) + return null; + + // Inside this is either a Current directory or a 15.0 directory, so find it; the previous code at + // https://github.com/OmniSharp/omnisharp-roslyn/blob/dde8119c40f4e3920eb5ea894cbca047033bd9aa/src/OmniSharp.Host/MSBuild/Discovery/MSBuildInstanceProvider.cs#L48-L58 + // ensured we had a correctly normalized path in case the underlying file system might have been case insensitive. + var versionDirectory = + monoMSBuildDir.EnumerateDirectories().SingleOrDefault(d => d.Name == "Current") ?? + monoMSBuildDir.EnumerateDirectories().SingleOrDefault(d => d.Name == "15.0"); + + if (versionDirectory == null) + return null; + + // Fetch the bin directory underneath, continuing to be case insensitive + s_monoMSBuildDirectory = versionDirectory.EnumerateDirectories().SingleOrDefault(d => string.Equals(d.Name, "bin", StringComparison.OrdinalIgnoreCase))?.FullName; + } + + return s_monoMSBuildDirectory; + } +}