Exemple #1
0
        private static CompiledAssembly EmitCompiledTemplate(string newAssemblyName, CSharpCompilation compilation)
        {
            using (MemoryStream dllMemoryStream = new MemoryStream())
                using (MemoryStream pdbMemoryStream = new MemoryStream())
                {
                    EmitResult result = compilation.Emit(dllMemoryStream, pdbMemoryStream);

                    if (result.Success)
                    {
                        dllMemoryStream.Seek(0, SeekOrigin.Begin);
                        pdbMemoryStream.Seek(0, SeekOrigin.Begin);

                        CompiledAssembly compiledTemplate = new CompiledAssembly(newAssemblyName,
                                                                                 dllMemoryStream.ToArray(), pdbMemoryStream.ToArray(), false, null);

                        return(compiledTemplate);
                    }
                    else
                    {
                        List <string> errorMessages = result.Diagnostics
                                                      .Where(d => d.IsWarningAsError || d.Severity == DiagnosticSeverity.Error)
                                                      .Select(d => d.ToString())
                                                      .ToList();

                        CompiledAssembly compiledTemplate = new CompiledAssembly(newAssemblyName,
                                                                                 new byte[0], new byte[0], true, errorMessages);

                        return(compiledTemplate);
                    }
                }
        }
Exemple #2
0
        public static CompiledAssembly Compile(string sourceText, string sourceFilename,
                                               string assemblyName, IEnumerable <string> additionalReferences = null)
        {
            try
            {
                bool          hasErrors;
                List <string> errorMessages;

                SyntaxTree syntaxTree = ParseSourceCode(sourceText, sourceFilename);
                errorMessages = syntaxTree.GetDiagnostics()
                                .Where(d => d.IsWarningAsError || d.Severity == DiagnosticSeverity.Error)
                                .Select(d => d.ToString())
                                .ToList();
                if (errorMessages.Any())
                {
                    return(new CompiledAssembly(assemblyName, new byte[0], new byte[0], true, errorMessages));
                }

                MetadataReference[] references = CollectAssemblyReferences(additionalReferences, out hasErrors, out errorMessages);
                if (hasErrors)
                {
                    return(new CompiledAssembly(assemblyName, new byte[0], new byte[0], true, errorMessages));
                }

                CSharpCompilation compilation = SetupCompiler(assemblyName, syntaxTree, references);

                CompiledAssembly compiledTemplate = EmitCompiledTemplate(assemblyName, compilation);
                return(compiledTemplate);
            }
            catch (Exception e)
            {
                return(new CompiledAssembly(assemblyName, new byte[0], new byte[0], true,
                                            new[] { "Internal compiler error: " + e.Message }));
            }
        }
        public CompiledAssembly LoadOrCompile(Options options,
                                              string sourceText, string sourceFilename,
                                              IEnumerable <string> additionalReferences = null)
        {
            CompiledAssembly assembly;

            options.Log("Generating final source code form.");

            // Generate the final compiled text itself.
            string finalSourceText = GenerateFinalSourceText(sourceText, sourceFilename, additionalReferences);

            // We use a content-addressible cache:  The hash of the compiled
            // text is the name of the cache file.  We truncate the hash to its first
            // 10 bytes (80 bits), since we don't need cryptographic security:  We
            // just need a low probability of an accidental collision, and 80 bits
            // is plenty for that.
            string hashName = finalSourceText.SHA256().ToHexChars(false).Substring(0, 20);

            options.Log("Assembly name: {0}.dll", hashName);

            // If we already have it in memory, just use it.
            if (_templates.TryGetValue(hashName, out assembly))
            {
                options.Log("Using in-memory cached assembly.");
                return(assembly);
            }

            options.Log("Searching for assembly in cache folder \"{0}\".", _folder);

            // Choose suitable output pathnames.
            string dllPath = Path.Combine(_folder, hashName + ".dll");
            string pdbPath = Path.Combine(_folder, hashName + ".pdb");

            // Try to load the cached DLL and PDB files.  If they exist,
            // we'll use them:  They have the right hash, so they must be
            // the right data.
            byte[] cachedDll, cachedPdb;

            // First, try to get the DLL.  It's okay if we can't.
            try
            {
                cachedDll = File.ReadAllBytes(dllPath);
                if (cachedDll.Length == 0)
                {
                    cachedDll = null;
                }
            }
            catch (IOException)
            {
                cachedDll = null;
            }

            if (cachedDll != null)
            {
                // Maybe load the PDB, if it exists.  If it doesn't, no big deal:
                // the user just doesn't get debugging information, but at least
                // we don't have to compile the source code again.
                try
                {
                    cachedPdb = File.ReadAllBytes(pdbPath);
                    if (cachedPdb.Length == 0)
                    {
                        cachedPdb = null;
                    }
                }
                catch (IOException)
                {
                    cachedPdb = null;
                }

                options.Log("Using on-disk cached assembly.");

                // Got at least the DLL, if not the PDB, so we're good to go.
                assembly = new CompiledAssembly(hashName, cachedDll, cachedPdb);

                // Keep a copy in memory so we don't have to do it again.
                _templates.Add(hashName, assembly);

                // And we're done.
                return(assembly);
            }

            options.Log("Compiling new assembly.");

            // Don't have it, so compile it for real.  This can be slow (seconds,
            // not milliseconds or microseconds).
            assembly = CSharpCompiler.Compile(finalSourceText,
                                              sourceFilename, hashName, additionalReferences);

            // Don't bother caching it if we can't compile it.
            if (assembly.HasErrors)
            {
                options.Log("Compile failed with errors.");
                return(assembly);
            }

            options.Log("Writing new assembly to cache folder \"{0}\".", _folder);

            // Try to write the compiled assembly to disk.  If we can't,
            // the cache is just slower across runs, but it's not really
            // an error.
            try
            {
                Directory.CreateDirectory(_folder);
            }
            catch (Exception e)
            {
                options.Log("Cannot ensure \"{0}\" exists: {1}", _folder, e.Message);
            }

            try
            {
                File.WriteAllBytes(dllPath, assembly.Dll);
            }
            catch (Exception e)
            {
                options.Log("Cannot write to \"{0}\": {1}", dllPath, e.Message);
            }

            try
            {
                File.WriteAllBytes(pdbPath, assembly.Pdb);
            }
            catch (Exception e)
            {
                options.Log("Cannot write to \"{0}\": {1}", pdbPath, e.Message);
            }

            return(assembly);
        }