Skip to content

Commit

Permalink
Merge pull request #988 from DustinCampbell/locate-msbuild
Browse files Browse the repository at this point in the history
Re-architect how MSBuild is loaded by OmniSharp
  • Loading branch information
DustinCampbell authored Oct 27, 2017
2 parents d1a1451 + 9bdf658 commit f0fc64e
Show file tree
Hide file tree
Showing 29 changed files with 903 additions and 545 deletions.
87 changes: 64 additions & 23 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -245,60 +245,102 @@ Task("CreateMSBuildFolder")
{
DirectoryHelper.ForceCreate(env.Folders.MSBuild);
var msbuild15TargetFolder = CombinePaths(env.Folders.MSBuild, "15.0");
var msbuild15BinTargetFolder = CombinePaths(msbuild15TargetFolder, "Bin");
var msbuildLibraries = new []
{
"Microsoft.Build",
"Microsoft.Build.Framework",
"Microsoft.Build.Tasks.Core",
"Microsoft.Build.Utilities.Core"
};
string sdkResolverTFM;
if (Platform.Current.IsWindows)
{
Information("Copying MSBuild runtime...");
var msbuildRuntimeFolder = CombinePaths(env.Folders.Tools, "Microsoft.Build.Runtime", "contentFiles", "any", "net46");
DirectoryHelper.Copy(msbuildRuntimeFolder, env.Folders.MSBuild);
var msbuildSourceFolder = CombinePaths(env.Folders.Tools, "Microsoft.Build.Runtime", "contentFiles", "any", "net46");
DirectoryHelper.Copy(msbuildSourceFolder, msbuild15BinTargetFolder, copySubDirectories: false);
var msbuild15SourceFolder = CombinePaths(msbuildSourceFolder, "15.0");
DirectoryHelper.Copy(msbuild15SourceFolder, msbuild15TargetFolder);
Information("Copying MSBuild libraries...");
foreach (var library in msbuildLibraries)
{
var libraryFileName = library + ".dll";
var librarySourcePath = CombinePaths(env.Folders.Tools, library, "lib", "net46", libraryFileName);
var libraryTargetPath = CombinePaths(msbuild15BinTargetFolder, libraryFileName);
FileHelper.Copy(librarySourcePath, libraryTargetPath);
}
sdkResolverTFM = "net46";
}
else
{
Information("Copying Mono MSBuild runtime...");
DirectoryHelper.Copy(env.Folders.MonoMSBuildRuntime, env.Folders.MSBuild);
var msbuildSourceFolder = env.Folders.MonoMSBuildRuntime;
DirectoryHelper.Copy(msbuildSourceFolder, msbuild15BinTargetFolder, copySubDirectories: false);
var msbuild15SourceFolder = CombinePaths(msbuildSourceFolder, "15.0");
DirectoryHelper.Copy(msbuild15SourceFolder, msbuild15TargetFolder);
Information("Copying MSBuild libraries...");
foreach (var library in msbuildLibraries)
{
var libraryFileName = library + ".dll";
var librarySourcePath = CombinePaths(env.Folders.MonoMSBuildLib, libraryFileName);
var libraryTargetPath = CombinePaths(msbuild15BinTargetFolder, libraryFileName);
FileHelper.Copy(librarySourcePath, libraryTargetPath);
}
sdkResolverTFM = "netstandard1.5";
}
// Copy MSBuild SDK Resolver and DotNetHostResolver
Information("Coping MSBuild SDK resolver...");
var sdkResolverFolder = CombinePaths(env.Folders.Tools, "Microsoft.DotNet.MSBuildSdkResolver", "lib", sdkResolverTFM);
var msbuildSdkResolverFolder = CombinePaths(env.Folders.MSBuild, "SdkResolvers", "Microsoft.DotNet.MSBuildSdkResolver");
DirectoryHelper.ForceCreate(msbuildSdkResolverFolder);
var sdkResolverSourceFolder = CombinePaths(env.Folders.Tools, "Microsoft.DotNet.MSBuildSdkResolver", "lib", sdkResolverTFM);
var sdkResolverTargetFolder = CombinePaths(msbuild15BinTargetFolder, "SdkResolvers", "Microsoft.DotNet.MSBuildSdkResolver");
DirectoryHelper.ForceCreate(sdkResolverTargetFolder);
FileHelper.Copy(
source: CombinePaths(sdkResolverFolder, "Microsoft.DotNet.MSBuildSdkResolver.dll"),
destination: CombinePaths(msbuildSdkResolverFolder, "Microsoft.DotNet.MSBuildSdkResolver.dll"));
source: CombinePaths(sdkResolverSourceFolder, "Microsoft.DotNet.MSBuildSdkResolver.dll"),
destination: CombinePaths(sdkResolverTargetFolder, "Microsoft.DotNet.MSBuildSdkResolver.dll"));
if (Platform.Current.IsWindows)
{
CopyDotNetHostResolver(env, "win", "x86", "hostfxr.dll", msbuildSdkResolverFolder, copyToArchSpecificFolder: true);
CopyDotNetHostResolver(env, "win", "x64", "hostfxr.dll", msbuildSdkResolverFolder, copyToArchSpecificFolder: true);
CopyDotNetHostResolver(env, "win", "x86", "hostfxr.dll", sdkResolverTargetFolder, copyToArchSpecificFolder: true);
CopyDotNetHostResolver(env, "win", "x64", "hostfxr.dll", sdkResolverTargetFolder, copyToArchSpecificFolder: true);
}
else if (Platform.Current.IsMacOS)
{
CopyDotNetHostResolver(env, "osx", "x64", "libhostfxr.dylib", msbuildSdkResolverFolder, copyToArchSpecificFolder: false);
CopyDotNetHostResolver(env, "osx", "x64", "libhostfxr.dylib", sdkResolverTargetFolder, copyToArchSpecificFolder: false);
}
else if (Platform.Current.IsLinux)
{
CopyDotNetHostResolver(env, "linux", "x64", "libhostfxr.so", msbuildSdkResolverFolder, copyToArchSpecificFolder: false);
CopyDotNetHostResolver(env, "linux", "x64", "libhostfxr.so", sdkResolverTargetFolder, copyToArchSpecificFolder: false);
}
// Copy content of Microsoft.Net.Compilers
Information("Copying Microsoft.Net.Compilers...");
var compilersFolder = CombinePaths(env.Folders.Tools, "Microsoft.Net.Compilers", "tools");
var msbuildRoslynFolder = CombinePaths(env.Folders.MSBuild, "Roslyn");
var compilersSourceFolder = CombinePaths(env.Folders.Tools, "Microsoft.Net.Compilers", "tools");
var compilersTargetFolder = CombinePaths(msbuild15BinTargetFolder, "Roslyn");
DirectoryHelper.Copy(compilersFolder, msbuildRoslynFolder);
DirectoryHelper.Copy(compilersSourceFolder, compilersTargetFolder);
// Delete unnecessary files
FileHelper.Delete(CombinePaths(msbuildRoslynFolder, "Microsoft.CodeAnalysis.VisualBasic.dll"));
FileHelper.Delete(CombinePaths(msbuildRoslynFolder, "Microsoft.VisualBasic.Core.targets"));
FileHelper.Delete(CombinePaths(msbuildRoslynFolder, "VBCSCompiler.exe"));
FileHelper.Delete(CombinePaths(msbuildRoslynFolder, "VBCSCompiler.exe.config"));
FileHelper.Delete(CombinePaths(msbuildRoslynFolder, "vbc.exe"));
FileHelper.Delete(CombinePaths(msbuildRoslynFolder, "vbc.exe.config"));
FileHelper.Delete(CombinePaths(msbuildRoslynFolder, "vbc.rsp"));
FileHelper.Delete(CombinePaths(compilersTargetFolder, "Microsoft.CodeAnalysis.VisualBasic.dll"));
FileHelper.Delete(CombinePaths(compilersTargetFolder, "Microsoft.VisualBasic.Core.targets"));
FileHelper.Delete(CombinePaths(compilersTargetFolder, "VBCSCompiler.exe"));
FileHelper.Delete(CombinePaths(compilersTargetFolder, "VBCSCompiler.exe.config"));
FileHelper.Delete(CombinePaths(compilersTargetFolder, "vbc.exe"));
FileHelper.Delete(CombinePaths(compilersTargetFolder, "vbc.exe.config"));
FileHelper.Delete(CombinePaths(compilersTargetFolder, "vbc.rsp"));
});

/// <summary>
Expand Down Expand Up @@ -514,7 +556,6 @@ void CopyMonoBuild(BuildEnvironment env, string sourceFolder, string outputFolde

// Copy MSBuild runtime and libraries
DirectoryHelper.Copy($"{env.Folders.MSBuild}", CombinePaths(outputFolder, "msbuild"));
DirectoryHelper.Copy($"{env.Folders.MonoMSBuildLib}", outputFolder);

// Included in Mono
FileHelper.Delete(CombinePaths(outputFolder, "System.AppContext.dll"));
Expand Down
3 changes: 3 additions & 0 deletions build/Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@
<MicrosoftExtensionsPlatformAbstractionsVersion>1.1.0</MicrosoftExtensionsPlatformAbstractionsVersion>
<MicrosoftNetTestSdkVersion>15.0.0</MicrosoftNetTestSdkVersion>
<MicrosoftTestPlatformTranslationLayerVersion>15.3.0</MicrosoftTestPlatformTranslationLayerVersion>
<MicrosoftVisualStudioSetupConfigurationInteropVersion>1.14.114</MicrosoftVisualStudioSetupConfigurationInteropVersion>
<MicrosoftVisualStudioSDKEmbedInteropTypesVersion>15.0.12</MicrosoftVisualStudioSDKEmbedInteropTypesVersion>
<NewtonsoftJsonVersion>9.0.1</NewtonsoftJsonVersion>
<NuGetPackagingVersion>4.3.0</NuGetPackagingVersion>
<NuGetPackagingCoreVersion>4.3.0</NuGetPackagingCoreVersion>
<NuGetProjectModelVersion>4.3.0</NuGetProjectModelVersion>
<NuGetVersioningVersion>4.3.0</NuGetVersioningVersion>
<SystemCollectionsImmutableVersion>1.4.0</SystemCollectionsImmutableVersion>
<SystemCompositionVersion>1.0.31</SystemCompositionVersion>
<SystemReflectionMetadataVersion>1.4.2</SystemReflectionMetadataVersion>
<SystemThreadingTasksDataflowVersion>4.6.0</SystemThreadingTasksDataflowVersion>
Expand Down
28 changes: 27 additions & 1 deletion scripts/runhelpers.cake
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,32 @@ private void KillProcessTree(Process process)
}
else
{
process.Kill();
foreach (var pid in GetUnixChildProcessIds(process.Id))
{
Run("kill", pid.ToString());
}

Run("kill", process.Id.ToString());
}
}

int[] GetUnixChildProcessIds(int processId)
{
var output = RunAndCaptureOutput("ps", "-A -o ppid,pid");
var lines = output.Split(new[] { System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries);
var childPIDs = new List<int>();

foreach (var line in lines)
{
var pairs = line.Trim().Split(new[] { ' ' }, System.StringSplitOptions.RemoveEmptyEntries);

int ppid;
if (int.TryParse(pairs[0].Trim(), out ppid) && ppid == processId)
{
childPIDs.Add(int.Parse(pairs[1].Trim()));
}

}

return childPIDs.ToArray();
}
5 changes: 5 additions & 0 deletions src/OmniSharp.Abstractions/Logging/LoggerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ namespace Microsoft.Extensions.Logging
{
public static class LoggerExceptions
{
public static void LogDebug(this ILogger logger, Exception ex, string message, params object[] args)
{
logger.LogDebug(0, ex, message, args);
}

public static void LogError(this ILogger logger, Exception ex, string message, params object[] args)
{
logger.LogError(0, ex, message, args);
Expand Down
10 changes: 10 additions & 0 deletions src/OmniSharp.Abstractions/MSBuild/Discovery/DiscoveryType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace OmniSharp.MSBuild.Discovery
{
public enum DiscoveryType
{
StandAlone = 0,
DeveloperConsole = 1,
VisualStudioSetup = 2,
Mono = 3
}
}
12 changes: 12 additions & 0 deletions src/OmniSharp.Abstractions/MSBuild/Discovery/IMSBuildLocator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Collections.Immutable;

namespace OmniSharp.MSBuild.Discovery
{
public interface IMSBuildLocator
{
MSBuildInstance RegisteredInstance { get; }

void RegisterInstance(MSBuildInstance instance);
ImmutableArray<MSBuildInstance> GetInstances();
}
}
31 changes: 31 additions & 0 deletions src/OmniSharp.Abstractions/MSBuild/Discovery/MSBuildInstance.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Immutable;

namespace OmniSharp.MSBuild.Discovery
{
public class MSBuildInstance
{
public string Name { get; }
public string MSBuildPath { get; }
public Version Version { get; }
public DiscoveryType DiscoveryType { get; }
public ImmutableDictionary<string, string> PropertyOverrides { get; }
public bool SetMSBuildExePathVariable { get; }

public MSBuildInstance(
string name, string msbuildPath, Version version, DiscoveryType discoveryType,
ImmutableDictionary<string, string> propertyOverrides = null,
bool setMSBuildExePathVariable = false)
{
Name = name;
MSBuildPath = msbuildPath;
Version = version ?? new Version(0, 0);
DiscoveryType = discoveryType;
PropertyOverrides = propertyOverrides ?? ImmutableDictionary<string, string>.Empty;
SetMSBuildExePathVariable = setMSBuildExePathVariable;
}

public override string ToString()
=> $"{Name} {Version} - \"{MSBuildPath}\"";
}
}
1 change: 1 addition & 0 deletions src/OmniSharp.Abstractions/OmniSharp.Abstractions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="$(MicrosoftExtensionsPlatformAbstractionsVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonVersion)" />
<PackageReference Include="NuGet.Versioning" Version="$(NuGetVersioningVersion)" />
<PackageReference Include="System.Collections.Immutable" Version="$(SystemCollectionsImmutableVersion)" />
<PackageReference Include="System.Composition" Version="$(SystemCompositionVersion)" />
<PackageReference Include="System.ValueTuple" Version="$(SystemValueTupleVersion)" />
</ItemGroup>
Expand Down
26 changes: 26 additions & 0 deletions src/OmniSharp.Abstractions/Utilities/PlatformHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,32 @@ private static string RealPath(string path)
return result;
}

public static Version GetMonoVersion()
{
var output = ProcessHelper.RunAndCaptureOutput("mono", "--version");
if (output == null)
{
return null;
}

// The mono --version text contains several lines. We'll just walk through the first line,
// word by word, until we find a word that parses as a version number. Normally, this should
// be the *fifth* word. E.g. "Mono JIT compiler version 4.8.0"

var lines = output.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
var words = lines[0].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

foreach (var word in words)
{
if (Version.TryParse(word, out var version))
{
return version;
}
}

return null;
}

public static string GetMonoRuntimePath()
{
if (IsWindows)
Expand Down
3 changes: 2 additions & 1 deletion src/OmniSharp.Host/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("TestUtility")]
[assembly: InternalsVisibleTo("OmniSharp.Http.Tests")]
[assembly: InternalsVisibleTo("TestUtility")]
49 changes: 43 additions & 6 deletions src/OmniSharp.Host/CompositionHostBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using OmniSharp.Eventing;
using OmniSharp.FileWatching;
using OmniSharp.Mef;
using OmniSharp.MSBuild.Discovery;
using OmniSharp.Options;
using OmniSharp.Roslyn;
using OmniSharp.Services;
Expand Down Expand Up @@ -49,15 +50,24 @@ public CompositionHost Build()
var assemblyLoader = _serviceProvider.GetRequiredService<IAssemblyLoader>();
var config = new ContainerConfiguration();

var assemblies = _assemblies
.Concat(new[] { typeof(OmniSharpWorkspace).GetTypeInfo().Assembly, typeof(IRequest).GetTypeInfo().Assembly })
.Distinct();

config = config.WithAssemblies(assemblies);

var fileSystemWatcher = new ManualFileSystemWatcher();
var metadataHelper = new MetadataHelper(assemblyLoader);

// We must register an MSBuild instance before composing MEF to ensure that
// our AssemblyResolve event is hooked up first.
var msbuildLocator = _serviceProvider.GetRequiredService<IMSBuildLocator>();
var instances = msbuildLocator.GetInstances();
var instance = instances.FirstOrDefault();
if (instance != null)
{
msbuildLocator.RegisterInstance(instance);
}
else
{
var logger = loggerFactory.CreateLogger<CompositionHostBuilder>();
logger.LogError("Could not locate MSBuild instance to register with OmniSharp");
}

config = config
.WithProvider(MefValueProvider.From(_serviceProvider))
.WithProvider(MefValueProvider.From<IFileSystemWatcher>(fileSystemWatcher))
Expand All @@ -69,11 +79,32 @@ public CompositionHost Build()
.WithProvider(MefValueProvider.From(options.CurrentValue.FormattingOptions))
.WithProvider(MefValueProvider.From(assemblyLoader))
.WithProvider(MefValueProvider.From(metadataHelper))
.WithProvider(MefValueProvider.From(msbuildLocator))
.WithProvider(MefValueProvider.From(_eventEmitter ?? NullEventEmitter.Instance));

var parts = _assemblies
.Concat(new[] { typeof(OmniSharpWorkspace).GetTypeInfo().Assembly, typeof(IRequest).GetTypeInfo().Assembly })
.Distinct()
.SelectMany(a => SafeGetTypes(a))
.ToArray();

config = config.WithParts(parts);

return config.CreateContainer();
}

private static IEnumerable<Type> SafeGetTypes(Assembly a)
{
try
{
return a.DefinedTypes.Select(t => t.AsType()).ToArray();
}
catch (ReflectionTypeLoadException e)
{
return e.Types.Where(t => t != null).ToArray();
}
}

public static IServiceProvider CreateDefaultServiceProvider(IConfiguration configuration, IServiceCollection services = null)
{
services = services ?? new ServiceCollection();
Expand All @@ -83,6 +114,12 @@ public static IServiceProvider CreateDefaultServiceProvider(IConfiguration confi
services.AddSingleton<IAssemblyLoader, AssemblyLoader>();
services.AddOptions();

// MSBuild
services.AddSingleton<IMSBuildLocator>(sp =>
MSBuildLocator.CreateDefault(
loggerFactory: sp.GetService<ILoggerFactory>(),
assemblyLoader: sp.GetService<IAssemblyLoader>()));

// Setup the options from configuration
services.Configure<OmniSharpOptions>(configuration);
services.AddLogging();
Expand Down
Loading

0 comments on commit f0fc64e

Please sign in to comment.