/// <summary> /// 将语法树生成到程序集 /// </summary> /// <param name="trees"></param> /// <returns></returns> public virtual Assembly ComplieToAssembly(IEnumerable <SyntaxTree> trees) { #if DEBUG Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); #endif Assembly assembly = null; EmitResult compileResult = null; if (PreCompiler()) { if (trees == default) { return(null); } //Mark : 26ms var options = GetCompilationOptions(); OptionAction?.Invoke(options); Compilation = GetCompilation(options); #if DEBUG Console.WriteLine(); stopwatch.StopAndShowCategoreInfo("[Compilation]", "获取编译单元", 2); stopwatch.Restart(); #endif //Mark : 951ms //Mark : 19M Memory Compilation = (TCompilation)Compilation.AddSyntaxTrees(trees); foreach (var item in _semanticAnalysistor) { Compilation = item(Compilation); } #if DEBUG stopwatch.StopAndShowCategoreInfo("[Semantic]", "语义解析排查", 2); stopwatch.Restart(); #endif //Mark : 264ms //Mark : 3M Memory Stream outputStream = new MemoryStream(); if (AssemblyOutputKind == AssemblyBuildKind.File) { outputStream = File.Create(OutputFilePath); using (var pdbStream = File.Create(OutputPdbPath)) { compileResult = Compilation.Emit( outputStream, pdbStream: pdbStream, options: new EmitOptions(pdbFilePath: OutputPdbPath, debugInformationFormat: DebugInformationFormat.PortablePdb)); } } else { compileResult = Compilation.Emit( outputStream, options: new EmitOptions(false, debugInformationFormat: DebugInformationFormat.PortablePdb)); } if (compileResult.Success) { outputStream.Seek(0, SeekOrigin.Begin); if (CompileSucceedEvent != default) { MemoryStream copyStream = new MemoryStream(); outputStream.CopyTo(copyStream); outputStream.Seek(0, SeekOrigin.Begin); assembly = Domain.CompileStreamCallback(OutputFilePath, OutputPdbPath, outputStream, AssemblyName); CompileSucceedEvent(OutputFilePath, OutputPdbPath, copyStream, Compilation); copyStream.Dispose(); } else { assembly = Domain.CompileStreamCallback(OutputFilePath, OutputPdbPath, outputStream, AssemblyName); } } else { assembly = CompileFailedEvent?.Invoke(outputStream, compileResult.Diagnostics, Compilation); } outputStream.Dispose(); #if DEBUG stopwatch.StopAndShowCategoreInfo("[ Emit ]", "编译时长", 2); #endif } return(assembly); }
/// <summary> /// 将语法树生成到程序集 /// </summary> /// <param name="trees"></param> /// <returns></returns> public virtual Assembly ComplieToAssembly(IEnumerable <SyntaxTree> trees) { Assembly assembly = null; EmitResult compileResult = null; if (PreCompiler()) { if (trees == default) { return(null); } var options = GetCompilationOptions(); OptionAction?.Invoke(options); Compilation = GetCompilation(options); Compilation = (TCompilation)Compilation.AddSyntaxTrees(trees); foreach (var item in _semanticAnalysistor) { Compilation = item(Compilation); } Stream outputStream = new MemoryStream(); if (AssemblyOutputKind == AssemblyBuildKind.File) { outputStream = File.Create(OutputFilePath); using (var pdbStream = File.Create(OutputPdbPath)) { compileResult = Compilation.Emit( outputStream, pdbStream: pdbStream, options: new EmitOptions(pdbFilePath: OutputPdbPath, debugInformationFormat: DebugInformationFormat.PortablePdb)); } } else { compileResult = Compilation.Emit( outputStream, options: new EmitOptions(false, debugInformationFormat: DebugInformationFormat.PortablePdb)); } if (compileResult.Success) { outputStream.Seek(0, SeekOrigin.Begin); if (CompileSucceedEvent != default) { MemoryStream copyStream = new MemoryStream(); outputStream.CopyTo(copyStream); outputStream.Seek(0, SeekOrigin.Begin); assembly = Domain.CompileStreamCallback(OutputFilePath, OutputPdbPath, outputStream, AssemblyName); CompileSucceedEvent(OutputFilePath, OutputPdbPath, copyStream, Compilation); copyStream.Dispose(); } else { assembly = Domain.CompileStreamCallback(OutputFilePath, OutputPdbPath, outputStream, AssemblyName); } } else { assembly = CompileFailedEvent?.Invoke(outputStream, compileResult.Diagnostics, Compilation); } outputStream.Dispose(); } return(assembly); }
/// <summary> /// 将 SyntaxTrees 中的语法树编译到程序集.如果不成功会抛出 NatashaException. /// </summary> /// <remarks> /// <example> /// <code> /// /// //程序集的域加载行为, 该行为决定了编译后的程序集随着依赖加载到域中的处理结果. /// //和加载插件原理相同. /// builder.CompileWithAssemblyLoadBehavior(enum); /// /// //编译单元的引用加载行为, 遇到同名不同版本的引用该如何处理. /// builder.CompileWithReferenceLoadBehavior(enum); /// builder.CompileWithReferencesFilter(func); /// /// </code> /// </example> /// </remarks> public Assembly GetAssembly() { #if DEBUG Stopwatch stopwatch = new(); stopwatch.Start(); #endif //Mark : 26ms if (_compileReferenceBehavior == LoadBehaviorEnum.None) { _compilerOptions.SetSupersedeLowerVersions(true); } var options = _compilerOptions.GetCompilationOptions(); var references = Domain.GetReferences(_compileReferenceBehavior, _referencePickFunc); var compilation = CSharpCompilation.Create(AssemblyName, SyntaxTrees, references, options); #if DEBUG stopwatch.RestartAndShowCategoreInfo("[Compiler]", "获取编译单元", 2); #endif if (EnableSemanticHandler) { foreach (var item in _semanticAnalysistor) { compilation = item(this, compilation); } lock (SyntaxTrees) { SyntaxTrees.Clear(); SyntaxTrees.AddRange(compilation.SyntaxTrees); } } #if DEBUG stopwatch.RestartAndShowCategoreInfo("[Semantic]", "语义处理", 2); #endif Stream dllStream; Stream pdbStream; Stream?xmlStream = null; if (DllFilePath != string.Empty) { dllStream = File.Create(DllFilePath); } else { dllStream = new MemoryStream(); } if (PdbFilePath != string.Empty) { pdbStream = File.Create(PdbFilePath); } else { pdbStream = new MemoryStream(); } if (XmlFilePath != string.Empty) { xmlStream = File.Create(XmlFilePath); } var compileResult = compilation.Emit( dllStream, pdbStream: pdbStream, xmlDocumentationStream: xmlStream, options: new EmitOptions(pdbFilePath: PdbFilePath == string.Empty ? null : PdbFilePath, debugInformationFormat: DebugInformationFormat.PortablePdb)); LogCompilationEvent?.Invoke(compilation.GetNatashaLog()); Assembly?assembly = null; if (compileResult.Success) { dllStream.Seek(0, SeekOrigin.Begin); pdbStream?.Seek(0, SeekOrigin.Begin); Domain.SetAssemblyLoadBehavior(_compileAssemblyBehavior); assembly = Domain.LoadAssemblyFromStream(dllStream, pdbStream); CompileSucceedEvent?.Invoke(compilation, assembly !); } dllStream.Dispose(); pdbStream?.Dispose(); xmlStream?.Dispose(); #if DEBUG stopwatch.StopAndShowCategoreInfo("[ Emit ]", "编译时长", 2); #endif if (!compileResult.Success) { CompileFailedEvent?.Invoke(compilation, compileResult.Diagnostics); throw NatashaExceptionAnalyzer.GetCompileException(compilation, compileResult.Diagnostics); } return(assembly !); }