Skip to content

Commit

Permalink
udpate compiler 分离文件,健壮程序
Browse files Browse the repository at this point in the history
  • Loading branch information
NMSAzulX committed Jul 2, 2024
1 parent 5cb6532 commit d6ef2b5
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 349 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using Microsoft.CodeAnalysis.Emit;
using System;
using System.Collections.Concurrent;
/// <summary>
/// 程序集编译构建器 - EMIT选项
/// </summary>
public sealed partial class AssemblyCSharpBuilder
{
private ConcurrentQueue<Func<EmitOptions, EmitOptions>>? _emitOptionHandle;
/// <summary>
/// 追加对 emitOption 的处理逻辑.
/// <list type="bullet">
/// <item>一次性配置,不可重用.</item>
/// <item>多次调用会进入配置队列.</item>
/// <item>调用 <see cref="GetAssembly"/> 后清空队列.</item>
/// <item>调用 <see cref="Clear"/> 后清空队列.</item>
/// <item>调用 <see cref="ClearEmitOptionCache"/> 后清空队列.</item>
/// </list>
/// </summary>
/// <remarks>
/// 注:该配置属于一次性配置,若重复使用该配置逻辑,请在这次编译后重新调用该方法.
/// </remarks>
/// <param name="handleAndReturnNewEmitOption"></param>
/// <returns>链式对象(调用方法的实例本身).</returns>
public AssemblyCSharpBuilder ConfigEmitOptions(Func<EmitOptions, EmitOptions> handleAndReturnNewEmitOption)
{
_emitOptionHandle ??= new ConcurrentQueue<Func<EmitOptions, EmitOptions>>();
_emitOptionHandle.Enqueue(handleAndReturnNewEmitOption);
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Immutable;
using System.Reflection;

/// <summary>
/// 程序集编译构建器 - 事件
/// </summary>
public sealed partial class AssemblyCSharpBuilder
{
/// <summary>
/// 监听编译日志事件,默认不监听.
/// </summary>
/// <remarks>
/// 注:该事件会被缓存,复用时无需重复添加方法.
/// </remarks>
public event Action<NatashaCompilationLog>? LogCompilationEvent;
/// <summary>
/// 流编译成功之后触发的事件.
/// </summary>
/// <remarks>
/// 此时已编译结束,程序集已经生成并加载.
/// </remarks>
public event Action<CSharpCompilation, Assembly>? CompileSucceedEvent;


/// <summary>
/// 流编译失败之后触发的事件.
/// </summary>
/// <remarks>
/// 此时已经编译结束, 但是编译失败.
/// </remarks>
public event Action<CSharpCompilation, ImmutableArray<Diagnostic>>? CompileFailedEvent;
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@

public sealed partial class AssemblyCSharpBuilder
{
/// <summary>
/// 监听编译日志事件,默认不监听.
/// </summary>
/// <remarks>
/// 注:该事件会被缓存,复用时无需重复添加方法.
/// </remarks>
public event Action<NatashaCompilationLog>? LogCompilationEvent;
/// <summary>
/// 和使用 <see cref="LogCompilationEvent"/> += log =>{} 一样.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Natasha.CSharp.Compiler.Utils;
using System;
using System.IO;

/// <summary>
Expand Down Expand Up @@ -27,7 +28,25 @@ static AssemblyCSharpBuilder()
}

}

private bool _cleanOutput;
/// <summary>
/// 重复编译时,强制清除已存在的文件.
/// </summary>
/// <returns></returns>
public AssemblyCSharpBuilder WithForceCleanOutput()
{
_cleanOutput = true;
return this;
}
/// <summary>
/// 重复编译时,不清除已存在的文件. 使用 old -> repeate.guid.oldname 进行替换.(不指定默认使用该方案)
/// </summary>
/// <returns></returns>
public AssemblyCSharpBuilder WithoutForceCleanOutput()
{
_cleanOutput = false;
return this;
}
/// <summary>
/// 设置程序集名称.
/// </summary>
Expand Down Expand Up @@ -132,6 +151,23 @@ public AssemblyCSharpBuilder WithFileOutput(string? folder = null)
CommentFilePath = Path.Combine(OutputFolder, $"{AssemblyName}.xml");
return this;
}


private string FileHandle(string file)
{
if (File.Exists(DllFilePath))
{
if (_cleanOutput)
{
File.Delete(DllFilePath);
}
else
{
return NatashaFileRepeateHelper.GetAvaliableFilePath(DllFilePath);
}
}
return file;
}
#endregion

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using Microsoft.CodeAnalysis;
using System;
using System.Collections.Generic;
/// <summary>
/// 程序集编译构建器 - 引用选项
/// </summary>
public sealed partial class AssemblyCSharpBuilder
{
private Func<IEnumerable<MetadataReference>, IEnumerable<MetadataReference>>? _referencesFilter;
private CombineReferenceBehavior _combineReferenceBehavior = CombineReferenceBehavior.UseCurrent;
private readonly ReferenceConfiguration _referenceConfiguration = new();
private readonly List<MetadataReference> _specifiedReferences;

/// <summary>
/// 该方法允许共享域参与编译.
/// <list type="bullet">
/// <item>
/// <description>[共享域] 元数据 [参与] 编译.</description>
/// </item>
/// <item>
/// <description>[当前域] 元数据 [参与] 编译.</description>
/// </item>
/// </list>
/// </summary>
/// <remarks>
/// 注:若两个域不同,且存在相同名称元数据,默认优先使用主域的元数据.
/// </remarks>
/// <param name="action">配置同名元数据的解决策略</param>
/// <returns>链式对象(调用方法的实例本身).</returns>
public AssemblyCSharpBuilder WithCombineReferences(Action<ReferenceConfiguration>? action = null)
{
action?.Invoke(_referenceConfiguration);
_combineReferenceBehavior = CombineReferenceBehavior.CombineDefault;
return this;
}


/// <summary>
/// 配置编译元数据的合并行为.
/// <list type="bullet">
/// <item>
/// <description>[共享域] 元数据 [不参与] 编译.</description>
/// </item>
/// <item>
/// <description>[当前域] 元数据 [参与] 编译.</description>
/// </item>
/// </list>
/// </summary>
/// <returns>链式对象(调用方法的实例本身).</returns>
public AssemblyCSharpBuilder WithCurrentReferences()
{
_combineReferenceBehavior = CombineReferenceBehavior.UseCurrent;
return this;
}

/// <summary>
/// 使用外部指定的元数据引用进行编译.
/// <list type="bullet">
/// <item>
/// <description>[共享域] 元数据 [不参与] 编译.</description>
/// </item>
/// <item>
/// <description>[当前域] 元数据 [不参与] 编译.</description>
/// </item>
/// </list>
/// </summary>
/// <remarks>
/// 使用 ClearOutsideReferences 可以清除本次传递的元数据引用.
/// </remarks>
/// <param name="metadataReferences"></param>
/// <returns>链式对象(调用方法的实例本身).</returns>
public AssemblyCSharpBuilder WithSpecifiedReferences(IEnumerable<MetadataReference> metadataReferences)
{
lock (_specifiedReferences)
{
_specifiedReferences.AddRange(metadataReferences);
}
_combineReferenceBehavior = CombineReferenceBehavior.UseSpecified;
return this;
}

/// <summary>
/// 清除由 WithSpecifiedReferences 方法传入的元数据引用.
/// </summary>
/// <returns>链式对象(调用方法的实例本身).</returns>
public AssemblyCSharpBuilder ClearOutsideReferences()
{
lock (_specifiedReferences)
{
_specifiedReferences.Clear();
}
return this;
}


/// <summary>
/// 配置元数据引用过滤策略.
/// </summary>
/// <param name="referencesFilter"></param>
/// <returns>链式对象(调用方法的实例本身).</returns>
public AssemblyCSharpBuilder SetReferencesFilter(Func<IEnumerable<MetadataReference>, IEnumerable<MetadataReference>>? referencesFilter)
{
_referencesFilter = referencesFilter;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ static UsingAnalysistor()
var node = error.GetTypeSyntaxNode<UsingDirectiveSyntax>(root);
if (node != null)
{
NatashaDiagnosticsExtension.RemoveUsingAndNode(node, errorNodes);
node.RemoveUsingAndNode(errorNodes);
}
}
//命名空间“namespace”中不存在类型或命名空间名“name”(是否缺少程序集引用?)
else if (error.Id == "CS0234")
{
error.RemoveUsingAndNodesFromStartName(root, errorNodes);
error.RemoveDefaultUsingAndNodesByStartName(root, errorNodes);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ internal unsafe static class RuntimeInnerHelper
internal readonly static ApplyUpdateDelegate ApplyUpdate;
static RuntimeInnerHelper()
{
AssemblyCSharpBuilder builder = new AssemblyCSharpBuilder();
AssemblyCSharpBuilder builder = new();
var assembly = builder
.UseDefaultLoadContext()
.UseSimpleMode()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static void RemoveUsingAndNode(this UsingDirectiveSyntax usingDirectiveSy

}

public static void RemoveUsingAndNodesFromStartName(this Diagnostic diagnostic, CompilationUnitSyntax root, HashSet<SyntaxNode> removeCollection)
public static void RemoveDefaultUsingAndNodesByStartName(this Diagnostic diagnostic, CompilationUnitSyntax root, HashSet<SyntaxNode> removeCollection)
{
var usingNode = GetTypeSyntaxNode<UsingDirectiveSyntax>(diagnostic, root);
if (usingNode!=null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace Natasha.CSharp.Compiler.Utils
{
internal static class NatashaFileRepeateHelper
{
public static string GetAvaliableFilePath(string file)
{
var tempOutputFolder = Path.GetDirectoryName(file);
if (!Directory.Exists(tempOutputFolder))
{
Directory.CreateDirectory(tempOutputFolder);
}
var tempFileName = Path.GetFileName(file);
return Path.Combine(tempOutputFolder, $"repeate.{Guid.NewGuid():N}.{tempFileName}");
}
}
}

0 comments on commit d6ef2b5

Please sign in to comment.