/// <summary> /// Emits compiled assembly to temporary file /// </summary> /// <param name="compilation"></param> /// <param name="result"></param> /// <param name="filename"></param> /// <returns></returns> public AssemblyWrapper EmitCompiledAssembly(Microsoft.CodeAnalysis.Compilation compilation, out EmitResult result, string filename) { var fi = new FileInfo(filename); fi.Directory?.Create(); using (var fs = new FileStream(fi.FullName, FileMode.Create)) { result = compilation.Emit(fs); if (!result.Success) { return(null); } } var assembly = LoadByFullFilename(fi.FullName); return(assembly); }
private CompilationResult EmitCompilation( string path, string assemblyName, string filePath, Microsoft.CodeAnalysis.Compilation compilation) { var result = compilation.Emit(path, manifestResources: _embeddedResourceCreator.GetManifestResources(assemblyName, filePath)); return(new CompilationResult { IsSuccess = result.Success, Errors = result.Diagnostics .Where(d => d.Severity == DiagnosticSeverity.Error) .Select(d => new CompilationError { Message = d.GetMessage(), Location = d.Location.ToString() }) .ToList() }); }
public Assembly Compile(Microsoft.CodeAnalysis.Compilation compilation, string outputPath) { var pdbPath = Path.ChangeExtension(outputPath, "pdb"); var xmlDocPath = Path.ChangeExtension(outputPath, "xml"); using (MemoryStream dllStream = new MemoryStream(), pdbStream = new MemoryStream(), xmlStream = new MemoryStream()) { using (var win32ResStream = compilation.CreateDefaultWin32Resources( versionResource: true, // Important! noManifest: false, manifestContents: null, iconInIcoFormat: null)) { var result = compilation.Emit( peStream: dllStream, pdbStream: pdbStream, xmlDocumentationStream: xmlStream, win32Resources: win32ResStream); if (!result.Success) { var failures = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error); foreach (var diagnostic in failures) { Logger.Error(diagnostic); } return(null); } _fileSystem.WriteAllBytes(outputPath, dllStream.ToArray()); _fileSystem.WriteAllBytes(pdbPath, pdbStream.ToArray()); _fileSystem.WriteAllBytes(xmlDocPath, xmlStream.ToArray()); return(_assemblyLoader.LoadFrom(outputPath)); } } }
public static CompilationResult GetAssemblyFromCompilation( ICodeGenAssemblyLoadContext loader, Microsoft.CodeAnalysis.Compilation compilation) { using (var ms = new MemoryStream()) { var result = compilation.Emit(ms, pdbStream: null); if (!result.Success) { var formatter = new DiagnosticFormatter(); var errorMessages = result.Diagnostics .Where(IsError) .Select(d => formatter.Format(d)); return(CompilationResult.FromErrorMessages(errorMessages)); } ms.Seek(0, SeekOrigin.Begin); try { return(CompilationResult.FromAssembly(loader.LoadStream(ms, symbols: null))); } catch (Exception ex) { var v = ex; while (v.InnerException != null) { v = v.InnerException; } return(CompilationResult.FromErrorMessages(ex.GetAllErrorMessages())); } } }
private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, CancellationToken cancellationToken) { Debug.Assert(!Arguments.IsInteractive); cancellationToken.ThrowIfCancellationRequested(); if (Arguments.DisplayLogo) { PrintLogo(consoleOutput); } if (Arguments.DisplayHelp) { PrintHelp(consoleOutput); return(Succeeded); } if (ReportErrors(Arguments.Errors, consoleOutput, errorLogger)) { return(Failed); } var touchedFilesLogger = (Arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null; Compilation compilation = CreateCompilation(consoleOutput, touchedFilesLogger, errorLogger); if (compilation == null) { return(Failed); } var diagnostics = new List <DiagnosticInfo>(); var analyzers = ResolveAnalyzersFromArguments(diagnostics, MessageProvider, touchedFilesLogger); var additionalTextFiles = ResolveAdditionalFilesFromArguments(diagnostics, MessageProvider, touchedFilesLogger); if (ReportErrors(diagnostics, consoleOutput, errorLogger)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); CancellationTokenSource analyzerCts = null; AnalyzerManager analyzerManager = null; AnalyzerDriver analyzerDriver = null; try { Func <ImmutableArray <Diagnostic> > getAnalyzerDiagnostics = null; ConcurrentSet <Diagnostic> analyzerExceptionDiagnostics = null; if (!analyzers.IsDefaultOrEmpty) { analyzerCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); analyzerManager = new AnalyzerManager(); analyzerExceptionDiagnostics = new ConcurrentSet <Diagnostic>(); Action <Diagnostic> addExceptionDiagnostic = diagnostic => analyzerExceptionDiagnostics.Add(diagnostic); var analyzerOptions = new AnalyzerOptions(ImmutableArray <AdditionalText> .CastUp(additionalTextFiles)); analyzerDriver = AnalyzerDriver.Create(compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, Arguments.ReportAnalyzer, out compilation, analyzerCts.Token); getAnalyzerDiagnostics = () => analyzerDriver.GetDiagnosticsAsync().Result; } // Print the diagnostics produced during the parsing stage and exit if there were any errors. if (ReportErrors(compilation.GetParseDiagnostics(), consoleOutput, errorLogger)) { return(Failed); } if (ReportErrors(compilation.GetDeclarationDiagnostics(), consoleOutput, errorLogger)) { return(Failed); } EmitResult emitResult; // NOTE: as native compiler does, we generate the documentation file // NOTE: 'in place', replacing the contents of the file if it exists string finalPeFilePath; string finalPdbFilePath; string finalXmlFilePath; Stream xmlStreamOpt = null; cancellationToken.ThrowIfCancellationRequested(); finalXmlFilePath = Arguments.DocumentationPath; if (finalXmlFilePath != null) { xmlStreamOpt = OpenFile(finalXmlFilePath, consoleOutput, PortableShim.FileMode.OpenOrCreate, PortableShim.FileAccess.Write, PortableShim.FileShare.ReadWriteBitwiseOrDelete); if (xmlStreamOpt == null) { return(Failed); } xmlStreamOpt.SetLength(0); } cancellationToken.ThrowIfCancellationRequested(); IEnumerable <DiagnosticInfo> errors; using (var win32ResourceStreamOpt = GetWin32Resources(Arguments, compilation, out errors)) using (xmlStreamOpt) { if (ReportErrors(errors, consoleOutput, errorLogger)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); string outputName = GetOutputFileName(compilation, cancellationToken); finalPeFilePath = Path.Combine(Arguments.OutputDirectory, outputName); finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalPeFilePath, ".pdb"); // NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit. var emitOptions = Arguments.EmitOptions. WithOutputNameOverride(outputName). WithPdbFilePath(finalPdbFilePath); using (var peStreamProvider = new CompilerEmitStreamProvider(this, finalPeFilePath)) using (var pdbStreamProviderOpt = Arguments.EmitPdb ? new CompilerEmitStreamProvider(this, finalPdbFilePath) : null) { emitResult = compilation.Emit( peStreamProvider, pdbStreamProviderOpt, (xmlStreamOpt != null) ? new Compilation.SimpleEmitStreamProvider(xmlStreamOpt) : null, (win32ResourceStreamOpt != null) ? new Compilation.SimpleEmitStreamProvider(win32ResourceStreamOpt) : null, Arguments.ManifestResources, emitOptions, getAnalyzerDiagnostics, cancellationToken); if (emitResult.Success && touchedFilesLogger != null) { if (pdbStreamProviderOpt != null) { touchedFilesLogger.AddWritten(finalPdbFilePath); } touchedFilesLogger.AddWritten(finalPeFilePath); } } } GenerateSqmData(Arguments.CompilationOptions, emitResult.Diagnostics); if (ReportErrors(emitResult.Diagnostics, consoleOutput, errorLogger)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (analyzerExceptionDiagnostics != null && ReportErrors(analyzerExceptionDiagnostics, consoleOutput, errorLogger)) { return(Failed); } bool errorsReadingAdditionalFiles = false; foreach (var additionalFile in additionalTextFiles) { if (ReportErrors(additionalFile.Diagnostics, consoleOutput, errorLogger)) { errorsReadingAdditionalFiles = true; } } if (errorsReadingAdditionalFiles) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (Arguments.TouchedFilesPath != null) { Debug.Assert(touchedFilesLogger != null); if (finalXmlFilePath != null) { touchedFilesLogger.AddWritten(finalXmlFilePath); } var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, mode: PortableShim.FileMode.OpenOrCreate); if (readStream == null) { return(Failed); } using (var writer = new StreamWriter(readStream)) { touchedFilesLogger.WriteReadPaths(writer); } var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, mode: PortableShim.FileMode.OpenOrCreate); if (writtenStream == null) { return(Failed); } using (var writer = new StreamWriter(writtenStream)) { touchedFilesLogger.WriteWrittenPaths(writer); } } } finally { // At this point analyzers are already complete in which case this is a no-op. Or they are // still running because the compilation failed before all of the compilation events were // raised. In the latter case the driver, and all its associated state, will be waiting around // for events that are never coming. Cancel now and let the clean up process begin. if (analyzerCts != null) { analyzerCts.Cancel(); if (analyzerManager != null) { // Clear cached analyzer descriptors and unregister exception handlers hooked up to the LocalizableString fields of the associated descriptors. analyzerManager.ClearAnalyzerState(analyzers); } if (Arguments.ReportAnalyzer && analyzerDriver != null && compilation != null) { ReportAnalyzerExecutionTime(consoleOutput, analyzerDriver, Culture, compilation.Options.ConcurrentBuild); } } } return(Succeeded); }
private int RunCore(TextWriter consoleOutput, ErrorLogger2 errorLogger, CancellationToken cancellationToken) { Debug.Assert(!Arguments.GetFieldOrProperty <bool>("IsScriptRunner")); cancellationToken.ThrowIfCancellationRequested(); if (Arguments.DisplayLogo) { PrintLogo(consoleOutput); } if (Arguments.DisplayHelp) { PrintHelp(consoleOutput); return(Succeeded); } if (ReportErrors(Arguments.Errors, consoleOutput, errorLogger)) { return(Failed); } var touchedFilesLogger = (Arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null; Compilation compilation = CreateCompilation(consoleOutput, touchedFilesLogger, errorLogger); if (compilation == null) { return(Failed); } var diagnostics = typeof(List <>).MakeGenericTypeFast(Refl.Type_DiagnosticInfo).InvokeFunction(".ctor"); var analyzers = ResolveAnalyzersAndGeneratorsFromArguments(diagnostics, MessageProvider, touchedFilesLogger); var additionalTextFiles = ResolveAdditionalFilesFromArguments(diagnostics, MessageProvider, touchedFilesLogger); if (ReportErrors((IEnumerable <DiagnosticInfo>)diagnostics, consoleOutput, errorLogger)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); CancellationTokenSource analyzerCts = null; AnalyzerManager analyzerManager = null; AnalyzerDriver analyzerDriver = null; try { Func <ImmutableArray <Diagnostic> > getAnalyzerDiagnostics = null; ConcurrentSet <Diagnostic> analyzerExceptionDiagnostics = null; if (!analyzers.IsDefaultOrEmpty) { analyzerCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); analyzerManager = new AnalyzerManager(); analyzerExceptionDiagnostics = new ConcurrentSet <Diagnostic>(); Action <Diagnostic> addExceptionDiagnostic = diagnostic => analyzerExceptionDiagnostics.Add(diagnostic); var analyzerOptions = new AnalyzerOptions(ImmutableArray.CreateRange(additionalTextFiles.Select(x => (AdditionalText)x))); analyzerDriver = ReflAnalyzerDriver.CreateAndAttachToCompilation( compilation, analyzers, analyzerOptions, analyzerManager, addExceptionDiagnostic, Arguments.ReportAnalyzer, out compilation, analyzerCts.Token); getAnalyzerDiagnostics = () => ((Task <ImmutableArray <Diagnostic> >)analyzerDriver.InvokeFunction("GetDiagnosticsAsync", compilation)).Result; } // Print the diagnostics produced during the parsing stage and exit if there were any errors. if (ReportErrors(compilation.GetParseDiagnostics(), consoleOutput, errorLogger)) { return(Failed); } if (ReportErrors(compilation.GetDeclarationDiagnostics(), consoleOutput, errorLogger)) { return(Failed); } consoleOutput.WriteLine("Rewriting LINQ to procedural code..."); var originalCompilation = compilation; var rewrittenLinqInvocations = 0; var rewrittenMethods = 0; foreach (var syntaxTree in compilation.SyntaxTrees) { var rewriter = new LinqRewriter(originalCompilation.GetSemanticModel(syntaxTree)); var root = syntaxTree.GetRoot(); SyntaxNode rewritten; try { rewritten = rewriter.Visit(root); } catch (Exception ex) { ReportErrors(new[] { rewriter.CreateDiagnosticForException(ex, syntaxTree.FilePath) }, consoleOutput, errorLogger); var m = ex; while (m != null) { Console.WriteLine(m); Console.WriteLine(m.StackTrace); m = m.InnerException; } return(Failed); } if (rewritten != root) { var originalOptions = (CSharp.CSharpParseOptions)root.SyntaxTree.Options; var parseOptions = ((CSharp.CSharpParseOptions)syntaxTree.Options).WithLanguageVersion(originalOptions.LanguageVersion); var syntaxTree2 = syntaxTree.WithRootAndOptions(rewritten, parseOptions); OriginalPaths[syntaxTree] = syntaxTree.FilePath; //rewritten = rewritten.SyntaxTree.WithRootAndOptions compilation = compilation.ReplaceSyntaxTree(syntaxTree, syntaxTree2); rewrittenLinqInvocations += rewriter.RewrittenLinqQueries; rewrittenMethods += rewriter.RewrittenMethods; } } var infoDescriptor = new DiagnosticDescriptor("REWRITE1001", "RoslynLinqRewrite statistics", "Rewritten {0} LINQ queries in {1} methods as procedural code.", "Compiler", DiagnosticSeverity.Info, true); var info = Diagnostic.Create(infoDescriptor, Location.None, rewrittenLinqInvocations, rewrittenMethods); consoleOutput.WriteLine(DiagnosticFormatter.Format(info)); var rewriteto = Environment.GetEnvironmentVariable("ROSLYN_LINQ_REWRITE_OUT_STATISTICS_TO"); if (rewriteto != null) { File.WriteAllText(rewriteto, string.Format("Rewritten {0} LINQ queries in {1} methods as procedural code.", rewrittenLinqInvocations, rewrittenMethods)); } //consoleOutput.WriteLine(string.Format, rewrittenLinqInvocations, rewrittenMethods)); var k = compilation.GetDiagnostics().Where(x => x.Severity == DiagnosticSeverity.Error).ToList(); if (k.Count != 0) { foreach (var err in k) { var errordescr = new DiagnosticDescriptor("REWRITE1002", "Could not compile rewritten method", "Could not compile rewritten method. Consider applying a [Shaman.Runtime.NoLinqRewrite] attribute. File: {0}. Code: {1}", "Compiler", DiagnosticSeverity.Error, true); var m = err.Location.SourceTree.GetRoot().FindNode(err.Location.SourceSpan); var err2 = Diagnostic.Create(infoDescriptor, err.Location, err.Location.SourceTree.FilePath, m.ToString()); consoleOutput.WriteLine(DiagnosticFormatter.Format(info)); //System.Console.WriteLine("Could not compile rewritten method. Consider applying a [Shaman.Runtime.NoLinqRewrite] attribute."); //System.Console.WriteLine(err.Location.SourceTree.FilePath); //var z = m.FirstAncestorOrSelf<CSharp.Syntax.BaseMethodDeclarationSyntax>(x => x.Kind() == CSharp.SyntaxKind.MethodDeclaration); //compilation.GetSemanticModel().GetEnclosingSymbol(err.Location.SourceSpan.Start) } } if (ReportErrors(compilation.GetParseDiagnostics().Where(x => x.Severity == DiagnosticSeverity.Error), consoleOutput, errorLogger)) { return(Failed); } if (ReportErrors(compilation.GetDeclarationDiagnostics().Where(x => x.Severity == DiagnosticSeverity.Error), consoleOutput, errorLogger)) { return(Failed); } EmitResult emitResult; // NOTE: as native compiler does, we generate the documentation file // NOTE: 'in place', replacing the contents of the file if it exists string finalPeFilePath; string finalPdbFilePath; string finalXmlFilePath; Stream xmlStreamOpt = null; cancellationToken.ThrowIfCancellationRequested(); finalXmlFilePath = Arguments.DocumentationPath; if (finalXmlFilePath != null) { xmlStreamOpt = OpenFile(finalXmlFilePath, consoleOutput, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete); if (xmlStreamOpt == null) { return(Failed); } xmlStreamOpt.SetLength(0); } cancellationToken.ThrowIfCancellationRequested(); ImmutableArray <Diagnostic> emitDiagnostics; IEnumerable <DiagnosticInfo> errors; using (var win32ResourceStreamOpt = GetWin32Resources(Arguments, compilation, out errors)) using (xmlStreamOpt) { if (ReportErrors(errors, consoleOutput, errorLogger)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); string outputName = GetOutputFileName(compilation, cancellationToken); finalPeFilePath = Path.Combine(Arguments.OutputDirectory, outputName); finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalPeFilePath, ".pdb"); // NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit. var emitOptions = Arguments.EmitOptions. WithOutputNameOverride(outputName). WithPdbFilePath(finalPdbFilePath); // The PDB path is emitted in it's entirety into the PE. This makes it impossible to have deterministic // builds that occur in different source directories. To enable this we shave all path information from // the PDB when specified by the user. // // This is a temporary work around to allow us to make progress with determinism. The following issue // tracks getting an official solution here. // // https://github.com/dotnet/roslyn/issues/9813 if (Arguments.ParseOptions.Features.ContainsKey("pdb-path-determinism") && !string.IsNullOrEmpty(emitOptions.PdbFilePath)) { emitOptions = emitOptions.WithPdbFilePath(Path.GetFileName(emitOptions.PdbFilePath)); } //var dummyCompiler = Refl.Type_Csc.InvokeFunction(".ctor", backup_responseFile, (object)null, backup_args, backup_analyzerLoader); var constr = Refl.Type_Csc.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).First(); var backup_buildPaths2 = Refl.Type_BuildPaths.InvokeFunction(".ctor", backup_buildPaths.ClientDirectory, backup_buildPaths.WorkingDirectory, backup_buildPaths.SdkDirectory, backup_buildPaths.TempDirectory); var dummyCompiler = constr.Invoke(new object[] { backup_responseFile, backup_buildPaths2, backup_args, backup_analyzerLoader }); //var dummyCompiler = Activator.CreateInstance(Refl.Type_Csc, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.CreateInstance|BindingFlags.Instance, null, new object[]{ backup_responseFile, (object)null, backup_args, backup_analyzerLoader}, null); var peStreamProvider = Refl.Type_CompilerEmitStreamProvider.InvokeFunction(".ctor", dummyCompiler, finalPeFilePath); var pdbStreamProviderOpt = Arguments.EmitPdb ? Refl.Type_CompilerEmitStreamProvider.InvokeFunction(".ctor", dummyCompiler, finalPdbFilePath) : null; /* * internal EmitResult Emit( * Compilation.EmitStreamProvider peStreamProvider, * Compilation.EmitStreamProvider pdbStreamProvider, * Compilation.EmitStreamProvider xmlDocumentationStreamProvider, * Compilation.EmitStreamProvider win32ResourcesStreamProvider, * IEnumerable<ResourceDescription> manifestResources, * EmitOptions options, * IMethodSymbol debugEntryPoint, * CompilationTestData testData, * Func<ImmutableArray<Diagnostic>> getHostDiagnostics, * CancellationToken cancellationToken) */ var diagnosticBag = Refl.Type_DiagnosticBag.InvokeFunction(".ctor"); emitResult = null; try { var peStream = ReflEmitStreamProvider.CreateStream(peStreamProvider, diagnosticBag); var pdbStream = pdbStreamProviderOpt != null?ReflEmitStreamProvider.CreateStream(pdbStreamProviderOpt, diagnosticBag) : null; emitResult = compilation.Emit( peStream, pdbStream, xmlStreamOpt, win32ResourceStreamOpt, Arguments.ManifestResources, emitOptions, null, cancellationToken); } catch { emitDiagnostics = GetEmitDiagnostic(diagnosticBag); if (emitDiagnostics.Length == 0) { throw; } } emitDiagnostics = GetEmitDiagnostic(diagnosticBag); if (emitResult != null && emitResult.Success && touchedFilesLogger != null) { if (pdbStreamProviderOpt != null) { touchedFilesLogger.InvokeAction("AddWritten", finalPdbFilePath); } touchedFilesLogger.InvokeAction("AddWritten", finalPeFilePath); } peStreamProvider.InvokeAction("Close", diagnosticBag); pdbStreamProviderOpt?.InvokeAction("Close", diagnosticBag); } if (ReportErrors((emitResult != null ? emitResult.Diagnostics : Enumerable.Empty <Diagnostic>()).Union(emitDiagnostics), consoleOutput, errorLogger)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (analyzerExceptionDiagnostics != null && ReportErrors(analyzerExceptionDiagnostics, consoleOutput, errorLogger)) { return(Failed); } bool errorsReadingAdditionalFiles = false; foreach (var additionalFile in additionalTextFiles) { if (ReportErrors(additionalFile.GetFieldOrProperty <IEnumerable <Diagnostic> >("Diagnostics"), consoleOutput, errorLogger)) { errorsReadingAdditionalFiles = true; } } if (errorsReadingAdditionalFiles) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (Arguments.TouchedFilesPath != null) { Debug.Assert(touchedFilesLogger != null); if (finalXmlFilePath != null) { touchedFilesLogger.InvokeAction("AddWritten", finalXmlFilePath); } var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, mode: FileMode.OpenOrCreate); if (readStream == null) { return(Failed); } using (var writer = new StreamWriter(readStream)) { touchedFilesLogger.InvokeAction("WriteReadPaths", writer); } var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, mode: FileMode.OpenOrCreate); if (writtenStream == null) { return(Failed); } using (var writer = new StreamWriter(writtenStream)) { touchedFilesLogger.InvokeAction("WriteWrittenPaths", writer); } } } finally { // At this point analyzers are already complete in which case this is a no-op. Or they are // still running because the compilation failed before all of the compilation events were // raised. In the latter case the driver, and all its associated state, will be waiting around // for events that are never coming. Cancel now and let the clean up process begin. if (analyzerCts != null) { analyzerCts.Cancel(); if (analyzerManager != null) { // Clear cached analyzer descriptors and unregister exception handlers hooked up to the LocalizableString fields of the associated descriptors. analyzerManager.InvokeAction("ClearAnalyzerState", analyzers); } if (Arguments.ReportAnalyzer && analyzerDriver != null && compilation != null) { ReportAnalyzerExecutionTime(consoleOutput, analyzerDriver, Culture, compilation.Options.ConcurrentBuild); } } } return(Succeeded); }
/// <summary> /// csc.exe and vbc.exe entry point. /// </summary> public virtual int Run(TextWriter consoleOutput, CancellationToken cancellationToken) { Debug.Assert(!Arguments.IsInteractive); cancellationToken.ThrowIfCancellationRequested(); if (Arguments.DisplayLogo) { PrintLogo(consoleOutput); } if (Arguments.DisplayHelp) { PrintHelp(consoleOutput); return(Succeeded); } if (PrintErrors(Arguments.Errors, consoleOutput)) { return(Failed); } var touchedFilesLogger = (Arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null; Compilation compilation = CreateCompilation(consoleOutput, touchedFilesLogger); if (compilation == null) { return(Failed); } var diagnostics = new List <DiagnosticInfo>(); var analyzers = Arguments.ResolveAnalyzersFromArguments(diagnostics, MessageProvider, touchedFilesLogger); if (PrintErrors(diagnostics, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); EmitResult emitResult; // EDMAURER: Don't yet know if there are method body errors. don't overwrite // any existing output files until the compilation is known to be successful. string tempExeFilename = null; string tempPdbFilename = null; // NOTE: as native compiler does, we generate the documentation file // NOTE: 'in place', replacing the contents of the file if it exists try { tempExeFilename = CreateTempFile(consoleOutput); // Can happen when temp directory is "full" if (tempExeFilename == null) { return(Failed); } FileStream output = OpenFile(tempExeFilename, consoleOutput); if (output == null) { return(Failed); } string finalOutputPath; string finalPdbFilePath; string finalXmlFilePath; using (output) { FileStream pdb = null; FileStream xml = null; cancellationToken.ThrowIfCancellationRequested(); if (Arguments.CompilationOptions.DebugInformationKind != DebugInformationKind.None) { tempPdbFilename = CreateTempFile(consoleOutput); if (tempPdbFilename == null) { return(Failed); } pdb = OpenFile(tempPdbFilename, consoleOutput); if (pdb == null) { return(Failed); } } cancellationToken.ThrowIfCancellationRequested(); finalXmlFilePath = Arguments.DocumentationPath; if (finalXmlFilePath != null) { xml = OpenFile(finalXmlFilePath, consoleOutput, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete); if (xml == null) { return(Failed); } xml.SetLength(0); } cancellationToken.ThrowIfCancellationRequested(); IEnumerable <DiagnosticInfo> errors; using (var win32Res = GetWin32Resources(Arguments, compilation, out errors)) using (pdb) using (xml) { if (PrintErrors(errors, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); string outputName = GetOutputFileName(compilation, cancellationToken); finalOutputPath = Path.Combine(Arguments.OutputDirectory, outputName); finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalOutputPath, ".pdb"); // NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit. emitResult = compilation.Emit(output, outputName, finalPdbFilePath, pdb, xml, cancellationToken, win32Res, Arguments.ManifestResources); } } GenerateSqmData(Arguments.CompilationOptions, emitResult.Diagnostics); if (PrintErrors(emitResult.Diagnostics, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); var analyzerDiagnostics = AnalyzerDriver.GetDiagnostics(compilation, analyzers, default(CancellationToken)); if (PrintErrors(analyzerDiagnostics, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (!TryDeleteFile(finalOutputPath, consoleOutput) || !TryMoveFile(tempExeFilename, finalOutputPath, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (tempPdbFilename != null) { if (!TryDeleteFile(finalPdbFilePath, consoleOutput) || !TryMoveFile(tempPdbFilename, finalPdbFilePath, consoleOutput)) { return(Failed); } } cancellationToken.ThrowIfCancellationRequested(); if (Arguments.TouchedFilesPath != null) { Debug.Assert(touchedFilesLogger != null); touchedFilesLogger.AddWritten(tempExeFilename); touchedFilesLogger.AddWritten(finalOutputPath); if (tempPdbFilename != null) { touchedFilesLogger.AddWritten(tempPdbFilename); touchedFilesLogger.AddWritten(finalPdbFilePath); } if (finalXmlFilePath != null) { touchedFilesLogger.AddWritten(finalXmlFilePath); } var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, FileMode.OpenOrCreate); if (readStream == null) { return(Failed); } using (var writer = new StreamWriter(readStream)) { touchedFilesLogger.WriteReadPaths(writer); } var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, FileMode.OpenOrCreate); if (writtenStream == null) { return(Failed); } using (var writer = new StreamWriter(writtenStream)) { touchedFilesLogger.WriteWrittenPaths(writer); } } return(Succeeded); } finally { if (tempExeFilename != null) { TryDeleteFile(tempExeFilename, consoleOutput: null); } if (tempPdbFilename != null) { TryDeleteFile(tempPdbFilename, consoleOutput: null); } } }
private int RunCore(TextWriter consoleOutput, CancellationToken cancellationToken) { Debug.Assert(!Arguments.IsInteractive); cancellationToken.ThrowIfCancellationRequested(); if (Arguments.DisplayLogo) { PrintLogo(consoleOutput); } if (Arguments.DisplayHelp) { PrintHelp(consoleOutput); return(Succeeded); } if (PrintErrors(Arguments.Errors, consoleOutput)) { return(Failed); } var touchedFilesLogger = (Arguments.TouchedFilesPath != null) ? new TouchedFileLogger() : null; Compilation compilation = CreateCompilation(consoleOutput, touchedFilesLogger); if (compilation == null) { return(Failed); } var diagnostics = new List <DiagnosticInfo>(); var analyzers = ResolveAnalyzersFromArguments(diagnostics, MessageProvider, touchedFilesLogger); var additionalTextFiles = ResolveAdditionalFilesFromArguments(diagnostics, MessageProvider, touchedFilesLogger); if (PrintErrors(diagnostics, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); var analyzerOptions = new AnalyzerOptions(ImmutableArray.Create <AdditionalText, AdditionalTextFile>(additionalTextFiles)); AnalyzerDriver analyzerDriver = null; if (!analyzers.IsDefaultOrEmpty) { analyzerDriver = AnalyzerDriver.Create(compilation, analyzers, analyzerOptions, out compilation, cancellationToken); } // Print the diagnostics produced during the parsing stage and exit if there were any errors. if (PrintErrors(compilation.GetParseDiagnostics(), consoleOutput)) { return(Failed); } if (PrintErrors(compilation.GetDeclarationDiagnostics(), consoleOutput)) { return(Failed); } EmitResult emitResult; // EDMAURER: Don't yet know if there are method body errors. don't overwrite // any existing output files until the compilation is known to be successful. string tempExeFilename = null; string tempPdbFilename = null; // NOTE: as native compiler does, we generate the documentation file // NOTE: 'in place', replacing the contents of the file if it exists try { FileStream output = CreateTempFile(consoleOutput, out tempExeFilename); // Can happen when temp directory is "full" if (output == null) { return(Failed); } string finalOutputPath; string finalPdbFilePath; string finalXmlFilePath; using (output) { FileStream pdb = null; FileStream xml = null; cancellationToken.ThrowIfCancellationRequested(); if (Arguments.EmitPdb) { pdb = CreateTempFile(consoleOutput, out tempPdbFilename); if (pdb == null) { return(Failed); } } cancellationToken.ThrowIfCancellationRequested(); finalXmlFilePath = Arguments.DocumentationPath; if (finalXmlFilePath != null) { xml = OpenFile(finalXmlFilePath, consoleOutput, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete); if (xml == null) { return(Failed); } xml.SetLength(0); } cancellationToken.ThrowIfCancellationRequested(); IEnumerable <DiagnosticInfo> errors; using (var win32Res = GetWin32Resources(Arguments, compilation, out errors)) using (pdb) using (xml) { if (PrintErrors(errors, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); string outputName = GetOutputFileName(compilation, cancellationToken); finalOutputPath = Path.Combine(Arguments.OutputDirectory, outputName); finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalOutputPath, ".pdb"); // NOTE: Unlike the PDB path, the XML doc path is not embedded in the assembly, so we don't need to pass it to emit. var emitOptions = Arguments.EmitOptions. WithOutputNameOverride(outputName). WithPdbFilePath(finalPdbFilePath); emitResult = compilation.Emit(output, pdb, xml, win32Res, Arguments.ManifestResources, emitOptions, cancellationToken); } } GenerateSqmData(Arguments.CompilationOptions, emitResult.Diagnostics); if (PrintErrors(emitResult.Diagnostics, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (analyzerDriver != null) { var analyzerDiagnostics = analyzerDriver.GetDiagnosticsAsync().Result; if (PrintErrors(analyzerDiagnostics, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); } bool errorsReadingAdditionalFiles = false; foreach (var additionalFile in additionalTextFiles) { if (PrintErrors(additionalFile.Diagnostics, consoleOutput)) { errorsReadingAdditionalFiles = true; } } if (errorsReadingAdditionalFiles) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (!TryDeleteFile(finalOutputPath, consoleOutput) || !TryMoveFile(tempExeFilename, finalOutputPath, consoleOutput)) { return(Failed); } cancellationToken.ThrowIfCancellationRequested(); if (tempPdbFilename != null) { if (!TryDeleteFile(finalPdbFilePath, consoleOutput) || !TryMoveFile(tempPdbFilename, finalPdbFilePath, consoleOutput)) { return(Failed); } } cancellationToken.ThrowIfCancellationRequested(); if (Arguments.TouchedFilesPath != null) { Debug.Assert(touchedFilesLogger != null); touchedFilesLogger.AddWritten(tempExeFilename); touchedFilesLogger.AddWritten(finalOutputPath); if (tempPdbFilename != null) { touchedFilesLogger.AddWritten(tempPdbFilename); touchedFilesLogger.AddWritten(finalPdbFilePath); } if (finalXmlFilePath != null) { touchedFilesLogger.AddWritten(finalXmlFilePath); } var readStream = OpenFile(Arguments.TouchedFilesPath + ".read", consoleOutput, FileMode.OpenOrCreate); if (readStream == null) { return(Failed); } using (var writer = new StreamWriter(readStream)) { touchedFilesLogger.WriteReadPaths(writer); } var writtenStream = OpenFile(Arguments.TouchedFilesPath + ".write", consoleOutput, FileMode.OpenOrCreate); if (writtenStream == null) { return(Failed); } using (var writer = new StreamWriter(writtenStream)) { touchedFilesLogger.WriteWrittenPaths(writer); } } return(Succeeded); } finally { if (tempExeFilename != null) { TryDeleteFile(tempExeFilename, consoleOutput: null); } if (tempPdbFilename != null) { TryDeleteFile(tempPdbFilename, consoleOutput: null); } } }
/// <summary> /// Emit the IL for the compilation into the specified stream. /// </summary> /// <param name="compilation">Compilation.</param> /// <param name="outputPath">Path of the file to which the compilation will be written.</param> /// <param name="pdbPath">Path of the file to which the compilation's debug info will be written. /// Also embedded in the output file. Null to forego PDB generation. /// </param> /// <param name="xmlDocPath">Path of the file to which the compilation's XML documentation will be written. Null to forego XML generation.</param> /// <param name="win32ResourcesPath">Path of the file from which the compilation's Win32 resources will be read (in RES format). /// Null to indicate that there are none.</param> /// <param name="manifestResources">List of the compilation's managed resources. Null to indicate that there are none.</param> /// <param name="cancellationToken">To cancel the emit process.</param> /// <exception cref="ArgumentNullException">Compilation or path is null.</exception> /// <exception cref="ArgumentException">Path is empty or invalid.</exception> /// <exception cref="IOException">An error occurred while reading or writing a file.</exception> public static EmitResult Emit( this Compilation compilation, string outputPath, string?pdbPath = null, string?xmlDocPath = null, string?win32ResourcesPath = null, IEnumerable <ResourceDescription>?manifestResources = null, CancellationToken cancellationToken = default ) { if (compilation == null) { throw new ArgumentNullException(nameof(compilation)); } using ( var outputStream = FileUtilities.CreateFileStreamChecked( File.Create, outputPath, nameof(outputPath) ) ) using ( var pdbStream = ( pdbPath == null ? null : FileUtilities.CreateFileStreamChecked( File.Create, pdbPath, nameof(pdbPath) ) ) ) using ( var xmlDocStream = ( xmlDocPath == null ? null : FileUtilities.CreateFileStreamChecked( File.Create, xmlDocPath, nameof(xmlDocPath) ) ) ) using ( var win32ResourcesStream = ( win32ResourcesPath == null ? null : FileUtilities.CreateFileStreamChecked( File.OpenRead, win32ResourcesPath, nameof(win32ResourcesPath) ) ) ) { return(compilation.Emit( outputStream, pdbStream: pdbStream, xmlDocumentationStream: xmlDocStream, win32Resources: win32ResourcesStream, manifestResources: manifestResources, options: new EmitOptions(pdbFilePath: pdbPath), cancellationToken: cancellationToken )); } }