/// <summary> /// Generates the assembly from the specified CodeGen configuration. /// </summary> /// <param name="xmlConfig">The CodeGen configuration.</param> /// <param name="assemblyPath">The output assembly path.</param> public void GenerateAssembly(XmlConfig xmlConfig, string assemblyPath) { using (StringWriter errorOutput = new StringWriter()) { TextWriter consoleOut = Console.Out; try { Console.SetOut(TextWriter.Null); xmlConfig.MultiFileExport = false; Initialize(xmlConfig, TextWriter.Null, errorOutput); // Generate user types GenerateUserTypes(); // Throw exception if there was an error StringBuilder sb = errorOutput.GetStringBuilder(); if (sb.Length > 0) { throw new Exception(sb.ToString()); } if (!xmlConfig.GenerateAssemblyWithILWriter) { string code = GenerateSingleFile(); var syntaxTrees = new List <SyntaxTree>(); syntaxTrees.Add(CSharpSyntaxTree.ParseText(code, path: "AutoGeneratedFile.cs", encoding: UTF8Encoding.Default)); using (FileStream dllStream = new FileStream(assemblyPath, FileMode.CreateNew)) { errorLogger = errorOutput; if (!GenerateRoslynAssembly(syntaxTrees, dllStream, null)) { throw new Exception(errorOutput.GetStringBuilder().ToString()); } } } else { codeWriter.GenerateBinary(userTypes, xmlConfig.GeneratedAssemblyName, !xmlConfig.DisablePdbGeneration, dependentAssemblies.Select(da => ResolveAssemblyPath(da))); } } finally { Console.SetOut(consoleOut); } } }
/// <summary> /// Initializes members from the specified CodeGen configuration. /// </summary> /// <param name="xmlConfig">The CodeGen configuration.</param> /// <param name="logger">The logger.</param> /// <param name="errorLogger">The error logger.</param> private void Initialize(XmlConfig xmlConfig, TextWriter logger, TextWriter errorLogger) { stopwatch = System.Diagnostics.Stopwatch.StartNew(); this.logger = logger; this.errorLogger = errorLogger; this.xmlConfig = xmlConfig; xmlModules = xmlConfig.Modules; typeNames = xmlConfig.Types; includedFiles = xmlConfig.IncludedFiles; referencedAssemblies = xmlConfig.ReferencedAssemblies; generationOptions = xmlConfig.GetGenerationFlags(); int nameLimit = xmlConfig.GenerateAssemblyWithILWriter ? 10000 : 1000; if (xmlConfig.GenerateAssemblyWithILWriter && !string.IsNullOrEmpty(xmlConfig.GeneratedAssemblyName)) { codeWriter = new ManagedILCodeWriter(Path.GetFileNameWithoutExtension(xmlConfig.GeneratedAssemblyName), generationOptions, nameLimit); } else { codeWriter = new CSharpCodeWriter(generationOptions, nameLimit); } userTypeFactory = new UserTypeFactory(xmlConfig.Transformations, codeWriter.Naming); userTypes = new List <UserType>(); }
/// <summary> /// Generates user types using the specified XML configuration. /// </summary> /// <param name="xmlConfig">The XML configuration.</param> /// <param name="logger">The logger text writer. If set to null, Console.Out will be used.</param> /// <param name="errorLogger">The error logger text writer. If set to null, Console.Error will be used.</param> public void Generate(XmlConfig xmlConfig, TextWriter logger = null, TextWriter errorLogger = null) { ConcurrentDictionary <string, string> generatedFiles = new ConcurrentDictionary <string, string>(); var syntaxTrees = new ConcurrentBag <SyntaxTree>(); string currentDirectory = Directory.GetCurrentDirectory(); string outputDirectory = currentDirectory + "\\output\\"; // Check logger and error logger if (errorLogger == null) { errorLogger = Console.Error; } if (logger == null) { logger = Console.Out; } Initialize(xmlConfig, logger, errorLogger); // Create output directory Directory.CreateDirectory(outputDirectory); // Generate user types GenerateUserTypes(); // Use IL code writer for assembly generation. if (xmlConfig.GenerateAssemblyWithILWriter && !string.IsNullOrEmpty(xmlConfig.GeneratedAssemblyName)) { logger.Write("IL emitting time..."); codeWriter.GenerateBinary(userTypes, xmlConfig.GeneratedAssemblyName, !xmlConfig.DisablePdbGeneration, dependentAssemblies.Select(da => ResolveAssemblyPath(da))); logger.WriteLine(" {0}", stopwatch.Elapsed); } else { // Code generation and saving it to disk logger.Write("Saving code to disk..."); if (!generationOptions.HasFlag(UserTypeGenerationFlags.SingleFileExport)) { // Generate Code Parallel.ForEach(userTypes, (symbolEntry) => { Tuple <string, string> result = GenerateCode(codeWriter, symbolEntry, userTypeFactory, outputDirectory, errorLogger, generationOptions, generatedFiles); string text = result.Item1; string filename = result.Item2; if (!string.IsNullOrEmpty(xmlConfig.GeneratedAssemblyName) && !string.IsNullOrEmpty(text)) { lock (syntaxTrees) { syntaxTrees.Add(CSharpSyntaxTree.ParseText(text, path: filename, encoding: System.Text.UTF8Encoding.Default)); } } }); } else { string filename = string.Format(@"{0}\everything.exported.cs", outputDirectory); string code = GenerateSingleFile(); generatedFiles.TryAdd(filename.ToLowerInvariant(), filename); if (!generationOptions.HasFlag(UserTypeGenerationFlags.DontSaveGeneratedCodeFiles)) { File.WriteAllText(filename, code); } if (!string.IsNullOrEmpty(xmlConfig.GeneratedAssemblyName)) { logger.WriteLine(" {0}", stopwatch.Elapsed); logger.Write("Parsing generated code with Roslyn..."); syntaxTrees.Add(CSharpSyntaxTree.ParseText(code, path: filename, encoding: UTF8Encoding.Default)); } } logger.WriteLine(" {0}", stopwatch.Elapsed); // Compiling the code if (!string.IsNullOrEmpty(xmlConfig.GeneratedAssemblyName)) { string dllFilename = Path.Combine(outputDirectory, xmlConfig.GeneratedAssemblyName); string pdbFilename = Path.Combine(outputDirectory, Path.GetFileNameWithoutExtension(dllFilename) + ".pdb"); using (var dllStream = new FileStream(dllFilename, FileMode.Create)) using (var pdbStream = new FileStream(pdbFilename, FileMode.Create)) { if (GenerateRoslynAssembly(syntaxTrees, dllStream, pdbStream)) { logger.WriteLine("DLL size: {0}", dllStream.Position); logger.WriteLine("PDB size: {0}", pdbStream.Position); } } logger.WriteLine("Compiling: {0}", stopwatch.Elapsed); } // Generating props file if (!string.IsNullOrEmpty(xmlConfig.GeneratedPropsFileName)) { using (TextWriter output = new StreamWriter(outputDirectory + xmlConfig.GeneratedPropsFileName, false /* append */, System.Text.Encoding.UTF8, 16 * 1024 * 1024)) { output.WriteLine(@"<?xml version=""1.0"" encoding=""utf-8""?>"); output.WriteLine(@"<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">"); output.WriteLine(@" <ItemGroup>"); foreach (var file in generatedFiles.Values) { output.WriteLine(@" <Compile Include=""{0}"" />", file); } output.WriteLine(@" </ItemGroup>"); output.WriteLine(@"</Project>"); } } } logger.WriteLine("Total time: {0}", stopwatch.Elapsed); }