Skip to content

Commit c4876a5

Browse files
authored
Support source-generated files (#193)
* Support source-generated files * Fix message * Include source-generated files in stage 1 * Use complog util * Include `<Compile>` by default * Remove outdated comment
1 parent 09b6851 commit c4876a5

File tree

3 files changed

+81
-32
lines changed

3 files changed

+81
-32
lines changed

src/SourceBrowser/src/BinLogToSln/BinLogToSln.csproj

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
<VersionPrefix>1.0.1</VersionPrefix>
1010
</PropertyGroup>
1111

12-
<ItemGroup>
13-
<PackageReference Include="LibGit2Sharp" />
14-
<PackageReference Include="Mono.Options" />
15-
<PackageReference Include="NuGet.Frameworks" />
16-
<PackageReference Include="System.Reflection.Metadata" />
12+
<ItemGroup>
13+
<PackageReference Include="Basic.CompilerLog.Util" />
14+
<PackageReference Include="LibGit2Sharp" />
15+
<PackageReference Include="Mono.Options" />
16+
<PackageReference Include="NuGet.Frameworks" />
17+
<PackageReference Include="System.Reflection.Metadata" />
1718
</ItemGroup>
1819

1920
<ItemGroup>

src/SourceBrowser/src/BinLogToSln/Program.cs

Lines changed: 74 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1+
using LibGit2Sharp;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.CSharp;
4+
using Microsoft.SourceBrowser.BinLogParser;
5+
using Mono.Options;
6+
using NuGet.Frameworks;
17
using System;
28
using System.Collections.Generic;
39
using System.Diagnostics.CodeAnalysis;
410
using System.IO;
511
using System.Linq;
6-
using System.Numerics;
712
using System.Reflection.Metadata;
813
using System.Reflection.PortableExecutable;
914
using System.Runtime.CompilerServices;
10-
using LibGit2Sharp;
11-
using Microsoft.CodeAnalysis;
12-
using Microsoft.CodeAnalysis.CSharp;
13-
using Microsoft.SourceBrowser.BinLogParser;
14-
using Mono.Options;
15-
using NuGet.Frameworks;
1615

1716
[assembly: InternalsVisibleTo("BinLogToSln.Tests")]
1817

@@ -146,6 +145,7 @@ private static bool ShouldExcludeInvocation(CompilerInvocation invocation)
146145

147146
return false;
148147
}
148+
149149
static void Main(string[] args)
150150
{
151151
string binlog = null;
@@ -205,7 +205,7 @@ static void Main(string[] args)
205205
WriteSolutionHeader(sln);
206206

207207
IEnumerable<CompilerInvocation> invocations = BinLogCompilerInvocationsReader.ExtractInvocations(binlog);
208-
208+
209209
// Group invocations by assembly name and select the best one for each
210210
var invocationGroups = invocations
211211
.Where(invocation => !ShouldExcludeInvocation(invocation))
@@ -240,11 +240,10 @@ static void Main(string[] args)
240240
using var projFile = new FileStream(projectFilePath, FileMode.Create);
241241
using var project = new StreamWriter(projFile);
242242

243-
string typeGuid = invocation.Language switch
243+
(string typeGuid, bool isCSharp) = invocation.Language switch
244244
{
245-
LanguageNames.CSharp => CSharpProjectTypeGuid,
246-
LanguageNames.VisualBasic => VBProjectTypeGuid,
247-
_ => CSharpProjectTypeGuid,
245+
LanguageNames.VisualBasic => (VBProjectTypeGuid, false),
246+
_ => (CSharpProjectTypeGuid, true),
248247
};
249248
sln.WriteLine($"Project(\"{typeGuid}\") = \"{projectName}\", \"{Path.Join("src", repoRelativeProjectPath)}\", \"{GetProjectGuid()}\"");
250249
sln.WriteLine("EndProject");
@@ -255,6 +254,7 @@ static void Main(string[] args)
255254
project.WriteLine(" <GenerateAssemblyInfo>false</GenerateAssemblyInfo>");
256255
project.WriteLine(" <GenerateTargetFrameworkAttribute>false</GenerateTargetFrameworkAttribute>");
257256
project.WriteLine(" <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>");
257+
project.WriteLine(" <_SkipAnalyzers>true</_SkipAnalyzers>");
258258
project.WriteLine($" <AssemblyName>{invocation.AssemblyName}</AssemblyName>");
259259
int idx = 1;
260260
if (invocation.Parsed.CompilationOptions is CSharpCompilationOptions cSharpOptions)
@@ -269,7 +269,7 @@ static void Main(string[] args)
269269
}
270270
if (cSharpOptions.CryptoKeyFile != null)
271271
{
272-
includeFile(cSharpOptions.CryptoKeyFile, out string projectRelativePath, out _);
272+
string projectRelativePath = includeFile(cSharpOptions.CryptoKeyFile, includeCompile: false);
273273
project.WriteLine($" <KeyOriginatorFile>{projectRelativePath}</KeyOriginatorFile>");
274274
}
275275
}
@@ -283,25 +283,33 @@ static void Main(string[] args)
283283
project.WriteLine(" <ItemGroup>");
284284
foreach (CommandLineSourceFile sourceFile in invocation.Parsed.SourceFiles)
285285
{
286-
includeFile(sourceFile.Path, out string projectRelativePath, out string link);
287-
project.WriteLine($" <Compile Include=\"{projectRelativePath}\"{(link != null ? $" Link=\"{link}\"" : "")}/>");
286+
includeFile(sourceFile.Path);
288287
}
289288
project.WriteLine(" </ItemGroup>");
290289
project.WriteLine(" <ItemGroup>");
291290
foreach (CommandLineReference reference in invocation.Parsed.MetadataReferences)
292291
{
293-
string path = reference.Reference;
294-
if (!File.Exists(path))
292+
includeReference("ReferencePath", reference.Reference);
293+
}
294+
project.WriteLine(" </ItemGroup>");
295+
296+
// Add generated files.
297+
project.WriteLine(" <ItemGroup>");
298+
foreach (var generatedFile in getGeneratedFiles())
299+
{
300+
string filePath = generatedFile.FilePath;
301+
if (!File.Exists(filePath))
295302
{
296-
Console.WriteLine($"Could not find reference '{path}'");
297-
continue;
303+
Directory.CreateDirectory(Path.GetDirectoryName(filePath));
304+
var stream = generatedFile.Stream;
305+
stream.Position = 0;
306+
using var fileStream = File.OpenWrite(filePath);
307+
stream.CopyTo(fileStream);
298308
}
299-
string projToRepoPath = Path.GetRelativePath(invocation.ProjectDirectory, repoRoot);
300-
string projToOutputPath = Path.Join(projToRepoPath, "..");
301-
string refPath = DedupeReference(output, path);
302-
project.WriteLine($" <ReferencePath Include=\"{Path.Join(projToOutputPath, refPath)}\"/>");
309+
includeFile(filePath);
303310
}
304311
project.WriteLine(" </ItemGroup>");
312+
305313
project.WriteLine("</Project>");
306314
if (!string.IsNullOrEmpty(invocation.OutputAssemblyPath))
307315
{
@@ -311,12 +319,13 @@ static void Main(string[] args)
311319
File.Copy(invocation.OutputAssemblyPath, outputFilePath, true);
312320
}
313321

314-
void includeFile(string originalPath, out string projectRelativePath, out string link)
322+
string includeFile(string originalPath, bool includeCompile = true)
315323
{
316324
string filePath = Path.GetFullPath(originalPath);
317325
string repoRelativePath = Path.GetRelativePath(repoRoot, filePath);
318326
string outputFile;
319-
link = null;
327+
string link = null;
328+
string projectRelativePath;
320329
if (repoRelativePath.StartsWith("..\\", StringComparison.Ordinal) || repoRelativePath.StartsWith("../", StringComparison.Ordinal) || Path.IsPathRooted(repoRelativePath))
321330
{
322331
string externalPath = Path.Join("_external", idx++.ToString(), Path.GetFileName(filePath));
@@ -338,6 +347,44 @@ void includeFile(string originalPath, out string projectRelativePath, out string
338347
{
339348
File.Copy(filePath, outputFile);
340349
}
350+
351+
if (includeCompile)
352+
{
353+
project.WriteLine($" <Compile Include=\"{projectRelativePath}\"{(link != null ? $" Link=\"{link}\"" : "")}/>");
354+
}
355+
356+
return projectRelativePath;
357+
}
358+
359+
void includeReference(string kind, string path)
360+
{
361+
if (!File.Exists(path))
362+
{
363+
Console.WriteLine($"Could not find {kind} '{path}'");
364+
return;
365+
}
366+
367+
string projToRepoPath = Path.GetRelativePath(invocation.ProjectDirectory, repoRoot);
368+
string projToOutputPath = Path.Join(projToRepoPath, "..");
369+
string refPath = DedupeReference(output, path);
370+
project.WriteLine($" <{kind} Include=\"{Path.Join(projToOutputPath, refPath)}\"/>");
371+
}
372+
373+
IEnumerable<(string FilePath, MemoryStream Stream)> getGeneratedFiles()
374+
{
375+
try
376+
{
377+
return Basic.CompilerLog.Util.RoslynUtil.ReadGeneratedFilesFromPdb(
378+
isCSharp: isCSharp,
379+
diagnosticName: invocation.ProjectFilePath,
380+
invocation.Parsed);
381+
}
382+
catch (Exception ex)
383+
{
384+
// We don't want to fail official builds during stage 1, so just log a warning.
385+
Console.WriteLine($"##vso[task.logissue type=warning;]Error processing generated files for '{invocation.ProjectFilePath}': {ex}");
386+
return [];
387+
}
341388
}
342389
}
343390

@@ -386,7 +433,7 @@ private static string GetProjectGuid()
386433
return Guid.NewGuid().ToString("B");
387434
}
388435

389-
private static string CSharpProjectTypeGuid = "{9A19103F-16F7-4668-BE54-9A1E7A4F7556}";
390-
private static string VBProjectTypeGuid = "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}";
436+
private static readonly string CSharpProjectTypeGuid = "{9A19103F-16F7-4668-BE54-9A1E7A4F7556}";
437+
private static readonly string VBProjectTypeGuid = "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}";
391438
}
392439
}

src/SourceBrowser/src/Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
<PackageVersion Include="Shouldly" Version="4.3.0" />
4242

4343
<!-- other dependencies -->
44+
<PackageVersion Include="Basic.CompilerLog.Util" Version="0.9.17" />
4445
<PackageVersion Include="LibGit2Sharp" Version="0.30.0" />
4546
<PackageVersion Include="MSBuild.StructuredLogger" Version="2.3.45" />
4647
<PackageVersion Include="ManagedEsent" Version="2.0.0" />

0 commit comments

Comments
 (0)