Files
se-launcher/PluginLoader/Compiler/RoslynCompiler.cs
zznty 9fb29d2011
All checks were successful
Build / Build Launcher (push) Successful in 2m31s
update logging and add pl splash as the main one
2024-05-31 17:12:08 +07:00

103 lines
3.4 KiB
C#

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text;
namespace PluginLoader.Compiler;
public class RoslynCompiler
{
private readonly List<Source> source = new();
private readonly bool debugBuild;
public RoslynCompiler(bool debugBuild = false)
{
this.debugBuild = debugBuild;
}
public void Load(Stream s, string name)
{
var mem = new MemoryStream();
using (mem)
{
s.CopyTo(mem);
source.Add(new(mem, name, debugBuild));
}
}
public byte[] Compile(string assemblyName, out byte[] symbols)
{
symbols = null;
var compilation = CSharpCompilation.Create(
assemblyName,
source.Select(x => x.Tree),
RoslynReferences.EnumerateAllReferences(),
new(
OutputKind.DynamicallyLinkedLibrary,
optimizationLevel: debugBuild ? OptimizationLevel.Debug : OptimizationLevel.Release, allowUnsafe: true));
using (var pdb = new MemoryStream())
using (var ms = new MemoryStream())
{
// write IL code into memory
EmitResult result;
if (debugBuild)
result = compilation.Emit(ms, pdb,
embeddedTexts: source.Select(x => x.Text),
options: new(debugInformationFormat: DebugInformationFormat.PortablePdb,
pdbFilePath: Path.ChangeExtension(assemblyName, "pdb")));
else
result = compilation.Emit(ms);
if (!result.Success)
{
// handle exceptions
var failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (var diagnostic in failures)
{
var location = diagnostic.Location;
var source = this.source.FirstOrDefault(x => x.Tree == location.SourceTree);
LogFile.Log.Debug(
$"{diagnostic.Id}: {diagnostic.GetMessage()} in file:\n{source?.Name ?? "null"} ({location.GetLineSpan().StartLinePosition})");
}
throw new("Compilation failed!");
}
if (debugBuild)
{
pdb.Seek(0, SeekOrigin.Begin);
symbols = pdb.ToArray();
}
ms.Seek(0, SeekOrigin.Begin);
return ms.ToArray();
}
}
private class Source
{
public Source(Stream s, string name, bool includeText)
{
Name = name;
var source = SourceText.From(s, canBeEmbedded: includeText);
if (includeText)
{
Text = EmbeddedText.FromSource(name, source);
Tree = CSharpSyntaxTree.ParseText(source, new(LanguageVersion.Latest), name);
}
else
{
Tree = CSharpSyntaxTree.ParseText(source, new(LanguageVersion.Latest));
}
}
public string Name { get; }
public SyntaxTree Tree { get; }
public EmbeddedText Text { get; }
}
}