Skip to content

Commit

Permalink
Use AOT version of Roslyn found in local .NET SDK
Browse files Browse the repository at this point in the history
This gives a massive speedup to the startup time as the NuGet version of
Roslyn takes a while to load because of JIT.
  • Loading branch information
jgiannuzzi committed Mar 23, 2021
1 parent 4ef6b17 commit 666ee2b
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 1 deletion.
58 changes: 58 additions & 0 deletions T4.Build/SdkAssemblyLoadContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using Mono.TextTemplating.CodeCompilation;

namespace T4.Build
{
class SdkAssemblyLoadContext : AssemblyLoadContext
{
readonly string runtimeDir;
readonly string roslynDir;

public SdkAssemblyLoadContext()
{
runtimeDir = Path.GetDirectoryName(typeof(object).Assembly.Location);

var dotnetRoot = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(runtimeDir)));
string MakeRoslynPath(string d) => Path.Combine(d, "Roslyn", "bincore");
var sdkDir = FindHighestVersionedDirectory(Path.Combine(dotnetRoot, "sdk"), d => Directory.Exists(MakeRoslynPath(d)));
roslynDir = MakeRoslynPath(sdkDir);
}

static string FindHighestVersionedDirectory(string parentFolder, Func<string, bool> validate)
{
string bestMatch = null;
SemVersion bestVersion = SemVersion.Zero;
foreach (var dir in Directory.EnumerateDirectories(parentFolder))
{
var name = Path.GetFileName(dir);
if (SemVersion.TryParse(name, out var version) && version.Major >= 0)
{
if (version > bestVersion && (validate == null || validate(dir)))
{
bestVersion = version;
bestMatch = dir;
}
}
}
return bestMatch;
}

protected override Assembly Load(AssemblyName assemblyName)
{
switch (assemblyName.Name)
{
case "Microsoft.CodeAnalysis":
case "Microsoft.CodeAnalysis.CSharp":
return LoadFromAssemblyPath(Path.Combine(roslynDir, $"{assemblyName.Name}.dll"));
case "System.Collections.Immutable":
case "System.Reflection.Metadata":
return LoadFromAssemblyPath(Path.Combine(runtimeDir, $"{assemblyName.Name}.dll"));
}

return null;
}
}
}
2 changes: 1 addition & 1 deletion T4.Build/T4.Build.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<licenseUrl>https://licenses.nuget.org/Apache-2.0</licenseUrl>
</metadata>
<files>
<file src="bin/$configuration$/$framework$/*.dll" target="tools/" />
<file src="bin/$configuration$/$framework$/*.dll" exclude="**/Microsoft.CodeAnalysis*.dll;**/System.Reflection.Metadata.dll;**/System.Collections.Immutable.dll" target="tools/" />
<file src="bin/$configuration$/$framework$/*.runtimeconfig.json" target="tools/" />
<file src="build/common.targets" target="build/common.targets" />
<file src="build/single.targets" target="build/T4.Build.targets" />
Expand Down
37 changes: 37 additions & 0 deletions T4.Build/TemplatingEngineExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.IO;
using System.Reflection;
using Mono.TextTemplating;

namespace T4.Build
{
public static class RoslynTemplatingEngineExtensions
{
private static readonly object sync = new object();
private static MethodInfo useInProcessCompilerMethod;

private static MethodInfo UseInProcessCompilerMethod
{
get
{
lock (sync)
{
if (useInProcessCompilerMethod == null)
{
var context = new SdkAssemblyLoadContext();
var assembly = context.LoadFromAssemblyPath(Path.Combine(Path.GetDirectoryName(typeof(RoslynTemplatingEngineExtensions).Assembly.Location), "Mono.TextTemplating.Roslyn.dll"));
var extensions = assembly.GetType("Mono.TextTemplating.RoslynTemplatingEngineExtensions");
useInProcessCompilerMethod = extensions.GetMethod("UseInProcessCompiler", new Type[] { typeof(TemplatingEngine) });
}
}

return useInProcessCompilerMethod;
}
}

public static void UseInProcessCompiler(this TemplatingEngine engine)
{
UseInProcessCompilerMethod.Invoke(null, new object[] { engine });
}
}
}

0 comments on commit 666ee2b

Please sign in to comment.