/// <summary> /// Generate code based on inputs and print to output files. /// </summary> /// <param name="inputDefs">Paths for source files.</param> /// <param name="outputPath">Location to store output files.</param> /// <param name="outputFileBasename">The basename used for all the output files.</param> public static void GenerateCode(string[] inputDefs, string outputPath, string outputFileBasename) { CodeGenCSharpCompiler compiler = new CodeGenCSharpCompiler(); CompilerOutput compilerOutput = compiler.CompileFromFiles(inputDefs, outputPath); CodeCommentsReader codeComments = compilerOutput.CodeComments; Compilation compilation = compilerOutput.Compilation; Assembly sourceTypesAssembly = compilerOutput.Assembly; // Store C# compiler, used later to compute codegen type hash. // TypeMetadataMapper.Compilation = compilerOutput.Compilation; MultiCodeWriter codeWriter = GetMainCodeWriter(sourceTypesAssembly); var codeGenErrors = new List <CodegenError>(); bool result = GenerateTypes(codeWriter, compilation, codeComments, codeGenErrors, sourceTypesAssembly); if (!result || codeGenErrors.Any()) { PrintCodeGenErrorsAndExit(codeGenErrors); } if (!Directory.Exists(outputPath)) { Directory.CreateDirectory(outputPath); } WriteOutputToFile(codeWriter, outputFileBasename, outputPath); }
/// <summary> /// Initializes a new instance of the <see cref="CompilerOutput"/> struct. /// </summary> /// <param name="assembly"></param> /// <param name="emitResult"></param> /// <param name="codeComments"></param> /// <param name="compilation"></param> public CompilerOutput(Assembly assembly, EmitResult emitResult, CodeCommentsReader codeComments, CSharpCompilation compilation) { Assembly = assembly; EmitResult = emitResult; CodeComments = codeComments; Compilation = compilation; }
private static bool GenerateTypes(CodeWriter codeWriter, Compilation compilation, CodeCommentsReader codeComments, List <CodegenError> codeGenErrors, Assembly sourceTypesAssembly) { bool result = true; codeWriter.WriteBeginFile(); var typeCodeGenerator = new TypeCodeGenerator { CodeWriter = codeWriter, SourceCompilation = compilation, SourceCodeComments = codeComments, CodeGenErrors = codeGenErrors, }; // CodeGen all the Mlos types. // foreach (Type sourceType in sourceTypesAssembly.GetTypes().Where(type => type.IsCodegenType())) { result &= typeCodeGenerator.GenerateType(sourceType); } codeWriter.WriteEndFile(); return(result); }
/// <summary> /// Compiles multiple CSharp files into assembly. /// </summary> /// <param name="inputFiles"></param> /// <param name="outputPath"></param> /// <remarks> /// The method also returns a documentation created from the source code. /// </remarks> /// <returns></returns> internal CompilerOutput CompileFromFiles(string[] inputFiles, string outputPath) { string resultAssemblyDocFullPath = Path.Combine(outputPath, "SettingsRegistry.xml"); Directory.CreateDirectory(Path.GetDirectoryName(resultAssemblyDocFullPath)); string assemblyName = Path.GetFileNameWithoutExtension(outputPath); var syntaxTrees = inputFiles.Select(inputFile => { string sourceContent = File.ReadAllText(inputFile); return(CSharpSyntaxTree.ParseText(text: sourceContent, path: inputFile, encoding: System.Text.Encoding.ASCII)); }); var refPaths = new[] { typeof(object).GetTypeInfo().Assembly.Location, Assembly.GetAssembly(typeof(Attributes.BaseCodegenAttribute)).Location, Assembly.GetExecutingAssembly().Location, Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll"), }; MetadataReference[] references = refPaths.Select(r => MetadataReference.CreateFromFile(r)).ToArray(); // Compile as dynamic library and disable all warnings. // var compilationOptions = new CSharpCompilationOptions( OutputKind.DynamicallyLinkedLibrary, warningLevel: 0, optimizationLevel: OptimizationLevel.Debug, allowUnsafe: true); CSharpCompilation compilation = CSharpCompilation.Create( assemblyName: assemblyName, syntaxTrees: syntaxTrees, references: references, options: compilationOptions); Assembly outputAssembly; using (var peStream = new MemoryStream()) using (var pdbStream = new MemoryStream()) using (var xmlDocStream = new MemoryStream()) { var emitOptions = new EmitOptions( debugInformationFormat: DebugInformationFormat.PortablePdb, includePrivateMembers: true); EmitResult emitResults = compilation.Emit( peStream: peStream, pdbStream: pdbStream, xmlDocumentationStream: xmlDocStream, options: emitOptions); // Rewind streams. // peStream.Seek(0, SeekOrigin.Begin); pdbStream.Seek(0, SeekOrigin.Begin); xmlDocStream.Seek(0, SeekOrigin.Begin); if (!emitResults.Success) { emitResults.Diagnostics.ToList().ForEach( error => { Console.Error.WriteLine($"Location:{error.Location}"); Console.Error.WriteLine($" Error: {error}"); }); Environment.Exit(1); } outputAssembly = AssemblyLoadContext.Default.LoadFromStream(peStream, pdbStream); var codeComments = new CodeCommentsReader(); codeComments.LoadFromAssembly(xmlDocStream); return(new CompilerOutput(outputAssembly, emitResults, codeComments, compilation)); } }