/// <summary> /// Compiles the provided syntax tree, and loads and returns the result. /// </summary> /// <param name="generatedSyntax">The syntax tree.</param> /// <returns>The compilation output.</returns> private static byte[] CompileAndLoad(GeneratedSyntax generatedSyntax) { var rawAssembly = CodeGeneratorCommon.CompileAssembly(generatedSyntax, "OrleansCodeGen.dll"); Assembly.Load(rawAssembly); return(rawAssembly); }
/// <summary> /// Generates and compiles an assembly for the provided grains. /// </summary> /// <param name="generatedSyntax"> /// The generated code. /// </param> /// <param name="assemblyName"> /// The name for the generated assembly. /// </param> /// <returns> /// The raw assembly. /// </returns> /// <exception cref="CodeGenerationException"> /// An error occurred generating code. /// </exception> public static byte[] CompileAssembly(GeneratedSyntax generatedSyntax, string assemblyName) { // Add the generated code attribute. var code = AddGeneratedCodeAttribute(generatedSyntax); // Reference everything which can be referenced. var assemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(asm => !asm.IsDynamic && !string.IsNullOrWhiteSpace(asm.Location)) .Select(asm => MetadataReference.CreateFromFile(asm.Location)) .Cast<MetadataReference>() .ToArray(); var logger = TraceLogger.GetLogger("CodeGenerator"); // Generate the code. var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); string source = null; if (logger.IsVerbose3) { source = GenerateSourceCode(code); // Compile the code and load the generated assembly. if (logger.IsVerbose3) { logger.LogWithoutBulkingAndTruncating( Severity.Verbose3, ErrorCode.CodeGenSourceGenerated, "Generating assembly {0} with source:\n{1}", assemblyName, source); } } var compilation = CSharpCompilation.Create(assemblyName) .AddSyntaxTrees(code.SyntaxTree) .AddReferences(assemblies) .WithOptions(options); using (var stream = new MemoryStream()) { var compilationResult = compilation.Emit(stream); if (!compilationResult.Success) { source = source ?? GenerateSourceCode(code); var errors = string.Join("\n", compilationResult.Diagnostics.Select(_ => _.ToString())); logger.Warn( ErrorCode.CodeGenCompilationFailed, "Compilation of assembly {0} failed with errors:\n{1}\nGenerated Source Code:\n{2}", assemblyName, errors, source); throw new CodeGenerationException(errors); } logger.Verbose(ErrorCode.CodeGenCompilationSucceeded, "Compilation of assembly {0} succeeded.", assemblyName); return stream.ToArray(); } }
/// <summary> /// Generates and compiles an assembly for the provided grains. /// </summary> /// <param name="generatedSyntax"> /// The generated code. /// </param> /// <param name="assemblyName"> /// The name for the generated assembly. /// </param> /// <returns> /// The raw assembly. /// </returns> /// <exception cref="CodeGenerationException"> /// An error occurred generating code. /// </exception> public static byte[] CompileAssembly(GeneratedSyntax generatedSyntax, string assemblyName) { // Add the generated code attribute. var code = AddGeneratedCodeAttribute(generatedSyntax); // Reference everything which can be referenced. var assemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(asm => !asm.IsDynamic && !string.IsNullOrWhiteSpace(asm.Location)) .Select(asm => MetadataReference.CreateFromFile(asm.Location)) .Cast <MetadataReference>() .ToArray(); var logger = TraceLogger.GetLogger("CodeGenerator"); // Generate the code. var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); string source = null; if (logger.IsVerbose3) { source = GenerateSourceCode(code); // Compile the code and load the generated assembly. logger.LogWithoutBulkingAndTruncating( Severity.Verbose3, ErrorCode.CodeGenSourceGenerated, "Generating assembly {0} with source:\n{1}", assemblyName, source); } var compilation = CSharpCompilation.Create(assemblyName) .AddSyntaxTrees(code.SyntaxTree) .AddReferences(assemblies) .WithOptions(options); using (var stream = new MemoryStream()) { var compilationResult = compilation.Emit(stream); if (!compilationResult.Success) { source = source ?? GenerateSourceCode(code); var errors = string.Join("\n", compilationResult.Diagnostics.Select(_ => _.ToString())); logger.Warn( ErrorCode.CodeGenCompilationFailed, "Compilation of assembly {0} failed with errors:\n{1}\nGenerated Source Code:\n{2}", assemblyName, errors, source); throw new CodeGenerationException(errors); } logger.Verbose(ErrorCode.CodeGenCompilationSucceeded, "Compilation of assembly {0} succeeded.", assemblyName); return(stream.ToArray()); } }
/// <summary> /// Compiles the provided syntax tree, and loads and returns the result. /// </summary> /// <param name="generatedSyntax">The syntax tree.</param> /// <param name="emitDebugSymbols"> /// Whether or not to emit debug symbols for the generated assembly. /// </param> /// <returns>The compilation output.</returns> private static CachedAssembly CompileAndLoad(GeneratedSyntax generatedSyntax, bool emitDebugSymbols) { var generated = CodeGeneratorCommon.CompileAssembly(generatedSyntax, "OrleansCodeGen", emitDebugSymbols: emitDebugSymbols); Assembly.Load(generated.RawBytes, generated.DebugSymbolRawBytes); return(new CachedAssembly(generated) { Loaded = true }); }
/// <summary> /// Compiles the provided syntax tree, and loads and returns the result. /// </summary> /// <param name="generatedSyntax">The syntax tree.</param> /// <param name="emitDebugSymbols"> /// Whether or not to emit debug symbols for the generated assembly. /// </param> /// <returns>The compilation output.</returns> private static CachedAssembly CompileAndLoad(GeneratedSyntax generatedSyntax, bool emitDebugSymbols) { var generated = CodeGeneratorCommon.CompileAssembly(generatedSyntax, "OrleansCodeGen", emitDebugSymbols: emitDebugSymbols); var loadedAssembly = LoadAssembly(generated); return(new CachedAssembly(generated) { Loaded = true, Assembly = loadedAssembly, }); }
public static CompilationUnitSyntax AddGeneratedCodeAttribute(GeneratedSyntax generatedSyntax) { var codeGenTargetAttributes = SF.AttributeList() .AddAttributes( generatedSyntax.SourceAssemblies.Select( asm => SF.Attribute(typeof(OrleansCodeGenerationTargetAttribute).GetNameSyntax()) .AddArgumentListArguments( SF.AttributeArgument(asm.GetName().FullName.GetLiteralExpression()))).ToArray()) .WithTarget(SF.AttributeTargetSpecifier(SF.Token(SyntaxKind.AssemblyKeyword))); return(generatedSyntax.Syntax.AddAttributeLists(codeGenTargetAttributes)); }
public static CompilationUnitSyntax AddGeneratedCodeAttribute(GeneratedSyntax generatedSyntax) { var codeGenTargetAttributes = SF.AttributeList() .AddAttributes( generatedSyntax.SourceAssemblies.Select( asm => SF.Attribute(typeof(OrleansCodeGenerationTargetAttribute).GetNameSyntax()) .AddArgumentListArguments( SF.AttributeArgument(asm.GetName().FullName.GetLiteralExpression()))).ToArray()) .WithTarget(SF.AttributeTargetSpecifier(SF.Token(SyntaxKind.AssemblyKeyword))); var generatedCodeAttribute = SF.AttributeList() .AddAttributes( SF.Attribute(typeof(GeneratedCodeAttribute).GetNameSyntax()) .AddArgumentListArguments( SF.AttributeArgument("Orleans-CodeGenerator".GetLiteralExpression()), SF.AttributeArgument(RuntimeVersion.FileVersion.GetLiteralExpression()))) .WithTarget(SF.AttributeTargetSpecifier(SF.Token(SyntaxKind.AssemblyKeyword))); return generatedSyntax.Syntax.AddAttributeLists(generatedCodeAttribute, codeGenTargetAttributes); }
/// <summary> /// Compiles the provided syntax tree, and loads and returns the result. /// </summary> /// <param name="generatedSyntax">The syntax tree.</param> /// <returns>The compilation output.</returns> private static byte[] CompileAndLoad(GeneratedSyntax generatedSyntax) { var rawAssembly = CodeGeneratorCommon.CompileAssembly(generatedSyntax, "OrleansCodeGen.dll"); Assembly.Load(rawAssembly); return rawAssembly; }
/// <summary> /// Generates and compiles an assembly for the provided syntax. /// </summary> /// <param name="generatedSyntax"> /// The generated code. /// </param> /// <param name="assemblyName"> /// The name for the generated assembly. /// </param> /// <param name="emitDebugSymbols"> /// Whether or not to emit debug symbols for the generated assembly. /// </param> /// <returns> /// The raw assembly. /// </returns> /// <exception cref="CodeGenerationException"> /// An error occurred generating code. /// </exception> private Assembly CompileAssembly(GeneratedSyntax generatedSyntax, string assemblyName, bool emitDebugSymbols) { // Add the generated code attribute. var code = CodeGeneratorCommon.AddGeneratedCodeAttribute(generatedSyntax); // Reference everything which can be referenced. var assemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(asm => !asm.IsDynamic && !string.IsNullOrWhiteSpace(asm.Location)) .Select(asm => MetadataReference.CreateFromFile(asm.Location)) .Cast <MetadataReference>() .ToArray(); // Generate the code. var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); #if NETSTANDARD2_0 // CoreFX bug https://github.com/dotnet/corefx/issues/5540 // to workaround it, we are calling internal WithTopLevelBinderFlags(BinderFlags.IgnoreCorLibraryDuplicatedTypes) // TODO: this API will be public in the future releases of Roslyn. // This work is tracked in https://github.com/dotnet/roslyn/issues/5855 // Once it's public, we should replace the internal reflection API call by the public one. var method = typeof(CSharpCompilationOptions).GetMethod("WithTopLevelBinderFlags", BindingFlags.NonPublic | BindingFlags.Instance); // we need to pass BinderFlags.IgnoreCorLibraryDuplicatedTypes, but it's an internal class // http://source.roslyn.io/#Microsoft.CodeAnalysis.CSharp/Binder/BinderFlags.cs,00f268571bb66b73 options = (CSharpCompilationOptions)method.Invoke(options, new object[] { 1u << 26 }); #endif string source = null; if (this.logger.IsEnabled(LogLevel.Debug)) { source = CodeGeneratorCommon.GenerateSourceCode(code); // Compile the code and load the generated assembly. this.logger.Debug( ErrorCode.CodeGenSourceGenerated, "Generating assembly {0} with source:\n{1}", assemblyName, source); } var compilation = CSharpCompilation.Create(assemblyName) .AddSyntaxTrees(code.SyntaxTree) .AddReferences(assemblies) .WithOptions(options); using (var outputStream = new MemoryStream()) { var emitOptions = new EmitOptions() .WithEmitMetadataOnly(false) .WithIncludePrivateMembers(true); if (emitDebugSymbols) { emitOptions = emitOptions.WithDebugInformationFormat(DebugInformationFormat.Embedded); } var compilationResult = compilation.Emit(outputStream, options: emitOptions); if (!compilationResult.Success) { source = source ?? CodeGeneratorCommon.GenerateSourceCode(code); var errors = string.Join("\n", compilationResult.Diagnostics.Select(_ => _.ToString())); this.logger.Warn( ErrorCode.CodeGenCompilationFailed, "Compilation of assembly {0} failed with errors:\n{1}\nGenerated Source Code:\n{2}", assemblyName, errors, source); throw new CodeGenerationException(errors); } this.logger.Debug( ErrorCode.CodeGenCompilationSucceeded, "Compilation of assembly {0} succeeded.", assemblyName); return(Assembly.Load(outputStream.ToArray())); } }
/// <summary> /// Compiles the provided syntax tree, and loads and returns the result. /// </summary> /// <param name="generatedSyntax">The syntax tree.</param> /// <param name="emitDebugSymbols"> /// Whether or not to emit debug symbols for the generated assembly. /// </param> /// <returns>The compilation output.</returns> private static CachedAssembly CompileAndLoad(GeneratedSyntax generatedSyntax, bool emitDebugSymbols) { var generated = CodeGeneratorCommon.CompileAssembly(generatedSyntax, "OrleansCodeGen", emitDebugSymbols: emitDebugSymbols); Assembly.Load(generated.RawBytes, generated.DebugSymbolRawBytes); return new CachedAssembly(generated) { Loaded = true }; }
/// <summary> /// Generates and compiles an assembly for the provided grains. /// </summary> /// <param name="generatedSyntax"> /// The generated code. /// </param> /// <param name="assemblyName"> /// The name for the generated assembly. /// </param> /// <param name="emitDebugSymbols"> /// Whether or not to emit debug symbols for the generated assembly. /// </param> /// <returns> /// The raw assembly. /// </returns> /// <exception cref="CodeGenerationException"> /// An error occurred generating code. /// </exception> public static GeneratedAssembly CompileAssembly(GeneratedSyntax generatedSyntax, string assemblyName, bool emitDebugSymbols) { // Add the generated code attribute. var code = AddGeneratedCodeAttribute(generatedSyntax); // Reference everything which can be referenced. var assemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(asm => !asm.IsDynamic && !string.IsNullOrWhiteSpace(asm.Location)) .Select(asm => MetadataReference.CreateFromFile(asm.Location)) .Cast<MetadataReference>() .ToArray(); var logger = LogManager.GetLogger("CodeGenerator"); // Generate the code. var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); #if NETSTANDARD // CoreFX bug https://github.com/dotnet/corefx/issues/5540 // to workaround it, we are calling internal WithTopLevelBinderFlags(BinderFlags.IgnoreCorLibraryDuplicatedTypes) // TODO: this API will be public in the future releases of Roslyn. // This work is tracked in https://github.com/dotnet/roslyn/issues/5855 // Once it's public, we should replace the internal reflection API call by the public one. var method = typeof(CSharpCompilationOptions).GetMethod("WithTopLevelBinderFlags", BindingFlags.NonPublic | BindingFlags.Instance); // we need to pass BinderFlags.IgnoreCorLibraryDuplicatedTypes, but it's an internal class // http://source.roslyn.io/#Microsoft.CodeAnalysis.CSharp/Binder/BinderFlags.cs,00f268571bb66b73 options = (CSharpCompilationOptions)method.Invoke(options, new object[] { 1u << 26 }); #endif string source = null; if (logger.IsVerbose3) { source = GenerateSourceCode(code); // Compile the code and load the generated assembly. logger.LogWithoutBulkingAndTruncating( Severity.Verbose3, ErrorCode.CodeGenSourceGenerated, "Generating assembly {0} with source:\n{1}", assemblyName, source); } var compilation = CSharpCompilation.Create(assemblyName) .AddSyntaxTrees(code.SyntaxTree) .AddReferences(assemblies) .WithOptions(options); var outputStream = new MemoryStream(); var symbolStream = emitDebugSymbols ? new MemoryStream() : null; try { var emitOptions = new EmitOptions() .WithDebugInformationFormat(DebugInformationFormat.PortablePdb); var compilationResult = compilation.Emit(outputStream, symbolStream, options: emitOptions); if (!compilationResult.Success) { source = source ?? GenerateSourceCode(code); var errors = string.Join("\n", compilationResult.Diagnostics.Select(_ => _.ToString())); logger.Warn( ErrorCode.CodeGenCompilationFailed, "Compilation of assembly {0} failed with errors:\n{1}\nGenerated Source Code:\n{2}", assemblyName, errors, source); throw new CodeGenerationException(errors); } logger.Verbose( ErrorCode.CodeGenCompilationSucceeded, "Compilation of assembly {0} succeeded.", assemblyName); return new GeneratedAssembly { RawBytes = outputStream.ToArray(), DebugSymbolRawBytes = symbolStream?.ToArray() }; } finally { outputStream.Dispose(); symbolStream?.Dispose(); } }
/// <summary> /// Compiles the provided syntax tree, and loads and returns the result. /// </summary> /// <param name="generatedSyntax">The syntax tree.</param> /// <param name="emitDebugSymbols"> /// Whether or not to emit debug symbols for the generated assembly. /// </param> /// <returns>The compilation output.</returns> private static CachedAssembly CompileAndLoad(GeneratedSyntax generatedSyntax, bool emitDebugSymbols) { var generated = CodeGeneratorCommon.CompileAssembly(generatedSyntax, "OrleansCodeGen", emitDebugSymbols: emitDebugSymbols); var loadedAssembly = LoadAssembly(generated); return new CachedAssembly(generated) { Loaded = true, Assembly = loadedAssembly, }; }