From 0830874267876bfabef6dba0b142eb1bd9a79d50 Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Mon, 30 Oct 2023 14:17:02 -0700 Subject: [PATCH] Few small fixes (#68) --- .gitignore | 1 + .vscode/launch.json | 4 +- README.md | 6 +- .../ProgramTests.cs | 2 +- .../Basic.CompilerLog.Util.csproj | 2 +- .../CompilerLogBuilder.cs | 16 ++- src/Basic.CompilerLog.Util/EmitData.cs | 11 +- .../Serialize/MessagePackTypes.cs | 2 +- .../Serialize/MessagePackUtil.cs | 5 +- src/Basic.CompilerLog/Program.cs | 126 ++++++++---------- src/Scratch/Scratch.cs | 40 ++---- 11 files changed, 100 insertions(+), 115 deletions(-) diff --git a/.gitignore b/.gitignore index dfcfd56..4941b7b 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ bld/ [Oo]bj/ [Ll]og/ [Ll]ogs/ +.complog/ # Visual Studio 2015/2017 cache/options directory .vs/ diff --git a/.vscode/launch.json b/.vscode/launch.json index 74f1e79..ed0c4f6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,8 +10,8 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/src/Basic.CompilerLog/bin/Debug/net7.0/Basic.CompilerLog.dll", - "args": ["rsp", "c:\\users\\jaredpar\\temp\\console\\console.csproj"], + "program": "${workspaceFolder}/artifacts/bin/Basic.CompilerLog/debug/Basic.CompilerLog.dll", + "args": ["replay", "C:\\Users\\jaredpar\\code\\roslyn\\artifacts\\log\\Debug\\Build.binlog", "-export", "-o", "c:/users/jaredpar/temp/export"], "cwd": "${workspaceFolder}/src/Basic.CompilerLog", // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console "console": "internalConsole", diff --git a/README.md b/README.md index fb69f9b..ffa992d 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,12 @@ This global tool can be installed via From there the following commands are available: -- `create`: create a compilerlog file from an existing binary log -- `diagnostics`: print diagnostics from the specified compilations +- `create`: create a complog file from an existing binary log +- `replay`: replay the builds from the complog - `export`: export complete compilations to disk - `ref`: export references for a compilation to disk - `rsp`: generate rsp files for compilation events -- `print`: print the summary of a compilerlog on the command line +- `print`: print the summary of a complog on the command line ## Info diff --git a/src/Basic.CompilerLog.UnitTests/ProgramTests.cs b/src/Basic.CompilerLog.UnitTests/ProgramTests.cs index f6a997c..e28302e 100644 --- a/src/Basic.CompilerLog.UnitTests/ProgramTests.cs +++ b/src/Basic.CompilerLog.UnitTests/ProgramTests.cs @@ -141,7 +141,7 @@ public void ExportHelloWorld(string template) public void EmitConsole(string arg) { using var emitDir = new TempDir(); - RunCompLog($"emit {arg} -o {emitDir.DirectoryPath} {Fixture.ConsoleComplogPath.Value}"); + RunCompLog($"replay {arg} -emit -o {emitDir.DirectoryPath} {Fixture.ConsoleComplogPath.Value}"); AssertOutput(@"console\emit\console.dll"); AssertOutput(@"console\emit\console.pdb"); diff --git a/src/Basic.CompilerLog.Util/Basic.CompilerLog.Util.csproj b/src/Basic.CompilerLog.Util/Basic.CompilerLog.Util.csproj index a3d5006..5a0c7d7 100644 --- a/src/Basic.CompilerLog.Util/Basic.CompilerLog.Util.csproj +++ b/src/Basic.CompilerLog.Util/Basic.CompilerLog.Util.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Basic.CompilerLog.Util/CompilerLogBuilder.cs b/src/Basic.CompilerLog.Util/CompilerLogBuilder.cs index d6b64a8..f9075eb 100644 --- a/src/Basic.CompilerLog.Util/CompilerLogBuilder.cs +++ b/src/Basic.CompilerLog.Util/CompilerLogBuilder.cs @@ -80,7 +80,7 @@ internal bool Add(CompilerCall compilerCall) AddCompilationOptions(infoPack, commandLineArguments, compilerCall); - var entry = ZipArchive.CreateEntry(GetCompilerEntryName(_compilationCount), CompressionLevel.Optimal); + var entry = ZipArchive.CreateEntry(GetCompilerEntryName(_compilationCount), CompressionLevel.Fastest); using (var entryStream = entry.Open()) { MessagePackSerializer.Serialize(entryStream, infoPack, SerializerOptions); @@ -198,14 +198,14 @@ public void Close() void WriteMetadata() { - var entry = ZipArchive.CreateEntry(MetadataFileName, CompressionLevel.Optimal); + var entry = ZipArchive.CreateEntry(MetadataFileName, CompressionLevel.Fastest); using var writer = Polyfill.NewStreamWriter(entry.Open(), ContentEncoding, leaveOpen: false); Metadata.Create(_compilationCount).Write(writer); } void WriteAssemblyInfo() { - var entry = ZipArchive.CreateEntry(AssemblyInfoFileName, CompressionLevel.Optimal); + var entry = ZipArchive.CreateEntry(AssemblyInfoFileName, CompressionLevel.Fastest); using var writer = Polyfill.NewStreamWriter(entry.Open(), ContentEncoding, leaveOpen: false); foreach (var kvp in _mvidToRefInfoMap.OrderBy(x => x.Value.FileName).ThenBy(x => x.Key)) { @@ -268,6 +268,12 @@ bool AddGeneratedFilesCore() { // This only works when using portable and embedded pdb formats. A full PDB can't store // generated files + if (!args.EmitPdb) + { + Diagnostics.Add($"Can't read generated files as no PDB is emitted"); + return false; + } + if (args.EmitOptions.DebugInformationFormat is not (DebugInformationFormat.Embedded or DebugInformationFormat.PortablePdb)) { Diagnostics.Add($"Can't read generated files from native PDB"); @@ -440,7 +446,7 @@ private string AddContent(Stream stream) if (_contentHashMap.Add(hashText)) { - var entry = ZipArchive.CreateEntry(GetContentEntryName(hashText), CompressionLevel.Optimal); + var entry = ZipArchive.CreateEntry(GetContentEntryName(hashText), CompressionLevel.Fastest); using var entryStream = entry.Open(); stream.Position = 0; stream.CopyTo(entryStream); @@ -617,7 +623,7 @@ private Guid AddAssembly(string filePath) return mvid; } - var entry = ZipArchive.CreateEntry(GetAssemblyEntryName(mvid), CompressionLevel.Optimal); + var entry = ZipArchive.CreateEntry(GetAssemblyEntryName(mvid), CompressionLevel.Fastest); using var entryStream = entry.Open(); file.Position = 0; file.CopyTo(entryStream); diff --git a/src/Basic.CompilerLog.Util/EmitData.cs b/src/Basic.CompilerLog.Util/EmitData.cs index 5b8ffa7..c2b07dc 100644 --- a/src/Basic.CompilerLog.Util/EmitData.cs +++ b/src/Basic.CompilerLog.Util/EmitData.cs @@ -38,7 +38,14 @@ public EmitData( } } -public readonly struct EmitDiskResult +public interface IEmitResult +{ + public bool Success { get; } + public ImmutableArray Diagnostics { get; } +} + + +public readonly struct EmitDiskResult : IEmitResult { public bool Success { get; } public string Directory { get; } @@ -70,7 +77,7 @@ public EmitDiskResult( } } -public readonly struct EmitMemoryResult +public readonly struct EmitMemoryResult : IEmitResult { public bool Success { get; } public MemoryStream AssemblyStream { get; } diff --git a/src/Basic.CompilerLog.Util/Serialize/MessagePackTypes.cs b/src/Basic.CompilerLog.Util/Serialize/MessagePackTypes.cs index 348ad47..a508941 100644 --- a/src/Basic.CompilerLog.Util/Serialize/MessagePackTypes.cs +++ b/src/Basic.CompilerLog.Util/Serialize/MessagePackTypes.cs @@ -75,7 +75,7 @@ public class CSharpCompilationOptionsPack public class VisualBasicCompilationOptionsPack { [Key(1)] - public ImmutableArray GlobalImports { get; set; } + public string[] GlobalImports { get; set; } [Key(2)] public string? RootNamespace { get; set; } [Key(3)] diff --git a/src/Basic.CompilerLog.Util/Serialize/MessagePackUtil.cs b/src/Basic.CompilerLog.Util/Serialize/MessagePackUtil.cs index 02f23a5..0c59730 100644 --- a/src/Basic.CompilerLog.Util/Serialize/MessagePackUtil.cs +++ b/src/Basic.CompilerLog.Util/Serialize/MessagePackUtil.cs @@ -1,4 +1,5 @@ +using System.Collections.Immutable; using System.Reflection; using System.Security.Cryptography; using System.Text; @@ -217,7 +218,7 @@ internal static VisualBasicCompilationOptions CreateVisualBasicCompilationOption moduleName: optionsPack.ModuleName, mainTypeName: optionsPack.MainTypeName, scriptClassName: WellKnownMemberNames.DefaultScriptClassName, - globalImports: basicPack.GlobalImports, + globalImports: basicPack.GlobalImports.Select(x => GlobalImport.Parse(x)).ToImmutableArray(), rootNamespace: basicPack.RootNamespace, optionStrict: basicPack.OptionStrict, optionInfer: basicPack.OptionInfer, @@ -246,7 +247,7 @@ internal static (CompilationOptionsPack, VisualBasicCompilationOptionsPack, Pars var tuple = CreateVisualBasicParseOptionsPack(options.ParseOptions); var pack = new VisualBasicCompilationOptionsPack() { - GlobalImports = options.GlobalImports, + GlobalImports = options.GlobalImports.Select(x => x.Name).ToArray(), RootNamespace = options.RootNamespace, OptionStrict = options.OptionStrict, OptionInfer = options.OptionInfer, diff --git a/src/Basic.CompilerLog/Program.cs b/src/Basic.CompilerLog/Program.cs index 201b2e0..480f83d 100644 --- a/src/Basic.CompilerLog/Program.cs +++ b/src/Basic.CompilerLog/Program.cs @@ -26,14 +26,17 @@ return command.ToLower() switch { "create" => RunCreate(rest), - "diagnostics" => RunDiagnostics(rest), + "replay" => RunReplay(rest, cts.Token), "export" => RunExport(rest), "ref" => RunReferences(rest), "rsp" => RunResponseFile(rest), - "emit" => RunEmit(rest, cts.Token), "analyzers" => RunAnalyzers(rest), "print" => RunPrint(rest), "help" => RunHelp(rest), + + // Older option names + "diagnostics" => RunReplay(rest, cts.Token), + "emit" => RunReplay(rest, cts.Token), _ => RunHelp(null) }; } @@ -368,12 +371,20 @@ void PrintUsage() } } -int RunEmit(IEnumerable args, CancellationToken cancellationToken) +int RunReplay(IEnumerable args, CancellationToken cancellationToken) { var baseOutputPath = ""; + var severity = DiagnosticSeverity.Warning; + var export = false; + var emit = false; + var analyzers = false; var options = new FilterOptionSet(includeNoneHost: true) { - { "o|out=", "path to output binaries to", o => baseOutputPath = o }, + { "severity", "minimum severity to display (default Warning)", (DiagnosticSeverity s) => severity = s }, + { "export", "export failed compilation", e => export = e is not null }, + { "emit", "emit compilation", e => emit = e is not null }, + { "analyzers", "use actual analyzers / generators (default uses generated files)", a => analyzers = a is not null }, + { "o|out=", "path to export to ", b => baseOutputPath = b }, }; try @@ -385,88 +396,65 @@ int RunEmit(IEnumerable args, CancellationToken cancellationToken) return ExitFailure; } - using var compilerLogStream = GetOrCreateCompilerLogStream(extra); - using var reader = GetCompilerLogReader(compilerLogStream, leaveOpen: true); - var compilerCalls = reader.ReadAllCompilerCalls(options.FilterCompilerCalls); - var allSucceeded = true; + if (!string.IsNullOrEmpty(baseOutputPath) && !(export || emit)) + { + WriteLine("Error: Specified a path to export to but did not specify -export"); + return ExitFailure; + } baseOutputPath = GetBaseOutputPath(baseOutputPath); - WriteLine($"Generating binary files to {baseOutputPath}"); - Directory.CreateDirectory(baseOutputPath); + if (!string.IsNullOrEmpty(baseOutputPath)) + { + WriteLine($"Outputting to {baseOutputPath}"); + } + + var analyzerHostOptions = analyzers ? BasicAnalyzerHostOptions.Default : BasicAnalyzerHostOptions.None; + using var compilerLogStream = GetOrCreateCompilerLogStream(extra); + using var reader = GetCompilerLogReader(compilerLogStream, leaveOpen: true, analyzerHostOptions); + var compilerCalls = reader.ReadAllCompilerCalls(options.FilterCompilerCalls); + var exportUtil = new ExportUtil(reader, includeAnalyzers: analyzerHostOptions.Kind != BasicAnalyzerKind.None); + var sdkDirs = DotnetUtil.GetSdkDirectories(); for (int i = 0; i < compilerCalls.Count; i++) { + cancellationToken.ThrowIfCancellationRequested(); + var compilerCall = compilerCalls[i]; - var emitDirPath = GetOutputPath(baseOutputPath, compilerCalls, i, "emit"); - Directory.CreateDirectory(emitDirPath); - Write($"{compilerCall.GetDiagnosticName()} ... "); + Write($"{compilerCall.GetDiagnosticName()} ..."); + var compilationData = reader.ReadCompilationData(compilerCall); - var result = compilationData.EmitToDisk(emitDirPath, cancellationToken); - if (result.Success) + var compilation = compilationData.GetCompilationAfterGenerators(); + + IEmitResult emitResult; + if (emit) { - WriteLine("done"); + var path = GetOutputPath(baseOutputPath, compilerCalls, i, "emit"); + Directory.CreateDirectory(path); + emitResult = compilationData.EmitToDisk(path, cancellationToken); } else { - allSucceeded = false; - WriteLine("FAILED"); - foreach (var diagnostic in result.Diagnostics) - { - WriteLine(diagnostic.GetMessage()); - } + emitResult = compilationData.EmitToMemory(cancellationToken); } - } - - return allSucceeded ? ExitSuccess : ExitFailure; - } - catch (OptionException e) - { - WriteLine(e.Message); - PrintUsage(); - return ExitFailure; - } - void PrintUsage() - { - WriteLine("complog rsp [OPTIONS] msbuild.complog"); - options.WriteOptionDescriptions(Out); - } -} - -int RunDiagnostics(IEnumerable args) -{ - var severity = DiagnosticSeverity.Warning; - var options = new FilterOptionSet(includeNoneHost: true) - { - { "severity", "minimum severity to display (default Warning)", (DiagnosticSeverity s) => severity = s }, - }; - - try - { - var extra = options.Parse(args); - if (options.Help) - { - PrintUsage(); - return ExitFailure; - } - - using var compilerLogStream = GetOrCreateCompilerLogStream(extra); - using var reader = GetCompilerLogReader(compilerLogStream, leaveOpen: true); - var compilationDatas = reader.ReadAllCompilationData(options.FilterCompilerCalls); - - foreach (var compilationData in compilationDatas) - { - var compilerCall = compilationData.CompilerCall; - WriteLine(compilerCall.GetDiagnosticName()); - var compilation = compilationData.GetCompilationAfterGenerators(); - foreach (var diagnostic in compilation.GetDiagnostics()) + WriteLine(emitResult.Success ? "Success" : "Error"); + foreach (var diagnostic in emitResult.Diagnostics) { if (diagnostic.Severity >= severity) { + Write(" "); WriteLine(diagnostic.GetMessage()); } } + + if (!emitResult.Success && export) + { + var exportPath = GetOutputPath(baseOutputPath, compilerCalls, i, "export"); + Directory.CreateDirectory(exportPath); + WriteLine($"Exporting to {exportPath}"); + exportUtil.Export(compilationData.CompilerCall, exportPath, sdkDirs); + } } return ExitSuccess; @@ -480,7 +468,7 @@ int RunDiagnostics(IEnumerable args) void PrintUsage() { - WriteLine("complog diagnostics [OPTIONS] msbuild.complog"); + WriteLine("complog replay [OPTIONS] msbuild.complog"); options.WriteOptionDescriptions(Out); } } @@ -542,9 +530,9 @@ List GetCompilerCalls(List extra, Func } } -CompilerLogReader GetCompilerLogReader(Stream compilerLogStream, bool leaveOpen) +CompilerLogReader GetCompilerLogReader(Stream compilerLogStream, bool leaveOpen, BasicAnalyzerHostOptions? options = null) { - var reader = CompilerLogReader.Create(compilerLogStream, leaveOpen); + var reader = CompilerLogReader.Create(compilerLogStream, leaveOpen, options); if (reader.MetadataVersion > CompilerLogReader.LatestMetadataVersion) { WriteLine($"Compiler log version newer than toolset: {reader.MetadataVersion}"); diff --git a/src/Scratch/Scratch.cs b/src/Scratch/Scratch.cs index cc0ebf8..7716bbe 100644 --- a/src/Scratch/Scratch.cs +++ b/src/Scratch/Scratch.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using System.Reflection; using Basic.CompilerLog; using Basic.CompilerLog.Util; using BenchmarkDotNet.Environments; @@ -128,37 +129,18 @@ void Profile() } } -void VerifyAll(string logPath, BasicAnalyzerHostOptions? options = null) +int RunComplog(string args) { - var exportDest = @"c:\users\jaredpar\temp\export"; - EmptyDirectory(exportDest); - - options ??= BasicAnalyzerHostOptions.None; - using var reader = CompilerLogReader.Create(logPath, options); - var exportUtil = new ExportUtil(reader, includeAnalyzers: options.Value.Kind != BasicAnalyzerKind.None); - var sdkDirs = DotnetUtil.GetSdkDirectories(); - int failedCount = 0; - foreach (var compilationData in reader.ReadAllCompilationData()) - { - Console.Write($"{compilationData.CompilerCall.GetDiagnosticName()} ..."); - var result = compilationData.EmitToMemory(); - if (result.Success) - { - Console.WriteLine("Success"); - continue; - } - - Console.WriteLine("Error"); - foreach (var item in result.Diagnostics) - { - Console.WriteLine(item.GetMessage()); - } + var assembly = typeof(FilterOptionSet).Assembly; + var program = assembly.GetType("Program", throwOnError: true); + var main = program!.GetMethod("
$", BindingFlags.Static | BindingFlags.NonPublic); + return (int)main!.Invoke(null, new[] { args.Split(' ', StringSplitOptions.RemoveEmptyEntries) })!; +} - var dest = Path.Combine(exportDest, failedCount.ToString()); - Console.WriteLine($"Exporting to {dest}"); - exportUtil.Export(compilationData.CompilerCall, dest, sdkDirs); - failedCount++; - } +void VerifyAll(string logPath) +{ + var exportDest = @"c:\users\jaredpar\temp\export"; + RunComplog($"replay {logPath} -o {exportDest} -export"); } void ExportTest(CompilerLogReader reader)