Exemplo n.º 1
0
        /// <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);
                }
            }
        }
Exemplo n.º 2
0
        /// <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>();
        }
Exemplo n.º 3
0
        /// <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);
        }