Example #1
0
        /// <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);
        }
Example #2
0
        /// <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();
            }
        }
Example #3
0
        /// <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());
            }
        }
Example #4
0
        /// <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
            });
        }
Example #5
0
        /// <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));
        }
Example #7
0
 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);
 }
Example #8
0
 /// <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
     };
 }
Example #11
0
        /// <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();
            }
        }
Example #12
0
 /// <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,
     };
 }