Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion NuGet.config
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<configuration>
<packageSources>
<clear />
<add key="dotnet-public" value="https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet-public/nuget/v3/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
</packageSources>
<disabledPackageSources>
<clear />
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.203",
"version": "8.0.117",
"rollForward": "major"
}
}
2 changes: 1 addition & 1 deletion src/SourceBrowser/src/BinLogParser/BinLogParser.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net472;net9.0</TargetFrameworks>
<TargetFrameworks>net472;net8.0</TargetFrameworks>
<AssemblyName>BinLogParser</AssemblyName>
<RootNamespace>Microsoft.SourceBrowser.BinLogParser</RootNamespace>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/SourceBrowser/src/BinLogToSln/BinLogToSln.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<PackAsTool>true</PackAsTool>
<RollForward>Major</RollForward>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
Expand Down
180 changes: 148 additions & 32 deletions src/SourceBrowser/src/BinLogToSln/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,115 @@

namespace BinLogToSln
{
class Program
{
class Program
{
private static CompilerInvocation SelectBestInvocation(IGrouping<string, CompilerInvocation> invocationGroup)
{
var invocations = invocationGroup.ToList();
if (invocations.Count == 1)
{
return invocations[0];
}

Console.WriteLine($"Selecting best invocation for assembly '{invocationGroup.Key}' from {invocations.Count} candidates:");
foreach (var inv in invocations)
{
Console.WriteLine($" - {inv.ProjectFilePath}");
}

// Score each invocation based on our criteria
var scoredInvocations = invocations.Select(inv => new
{
Invocation = inv,
Score = CalculateInvocationScore(inv)
}).ToList();

// Select the highest scored invocation
var best = scoredInvocations.OrderByDescending(x => x.Score).First();

Console.WriteLine($"Selected: {best.Invocation.ProjectFilePath} (score: {best.Score})");
return best.Invocation;
}

private static int CalculateInvocationScore(CompilerInvocation invocation)
{
int score = 0;

try
{
// Prefer invocations with non-*.notsupported.cs source files
var sourceFiles = invocation.Parsed?.SourceFiles;
if (sourceFiles.HasValue)
{
int totalSourceFiles = sourceFiles.Value.Length;
int notSupportedFiles = sourceFiles.Value.Count(sf => sf.Path.Contains(".notsupported.cs"));

if (totalSourceFiles > 0)
{
// Higher score for projects with fewer notsupported files relative to total
score += (totalSourceFiles - notSupportedFiles) * 100;

// Bonus for having no notsupported files at all
if (notSupportedFiles == 0)
{
score += 1000;
}
}
}

// Prefer more specific target frameworks
// This is a heuristic - longer framework names are typically more specific
string targetFramework = GetTargetFrameworkFromCommandLine(invocation.CommandLineArguments);
if (!string.IsNullOrEmpty(targetFramework))
{
score += targetFramework.Length * 10;

// Prefer platform-specific frameworks over generic ones
if (targetFramework.Contains("linux") || targetFramework.Contains("windows") || targetFramework.Contains("osx"))
{
score += 500;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error calculating score for {invocation.ProjectFilePath}: {ex.Message}");
// Return a base score so we don't exclude this invocation entirely
score = 1;
}

return score;
}

private static string GetTargetFrameworkFromCommandLine(string commandLineArguments)
{
if (string.IsNullOrEmpty(commandLineArguments))
return null;

// Look for /p:TargetFramework=xxx pattern
var match = System.Text.RegularExpressions.Regex.Match(
commandLineArguments,
@"/p:TargetFramework=([^\s;]+)",
System.Text.RegularExpressions.RegexOptions.IgnoreCase);

if (match.Success)
{
return match.Groups[1].Value;
}

// Look for --target-framework xxx pattern
match = System.Text.RegularExpressions.Regex.Match(
commandLineArguments,
@"--target-framework\s+([^\s]+)",
System.Text.RegularExpressions.RegexOptions.IgnoreCase);

if (match.Success)
{
return match.Groups[1].Value;
}

return null;
}
static void Main(string[] args)
{
string binlog = null;
Expand Down Expand Up @@ -74,36 +181,45 @@ static void Main(string[] args)
using var sln = new StreamWriter(slnFile);
WriteSolutionHeader(sln);

IEnumerable<CompilerInvocation> invocations = BinLogCompilerInvocationsReader.ExtractInvocations(binlog);
var processed = new HashSet<string>();
foreach (CompilerInvocation invocation in invocations)
{
if (string.IsNullOrEmpty(invocation.ProjectDirectory))
{
continue;
}

string projectFolder = Path.GetFileName(invocation.ProjectDirectory);
if (projectFolder == "ref" || projectFolder == "stubs")
{
Console.WriteLine($"Skipping Ref Assembly project {invocation.ProjectFilePath}");
continue;
}

if (Path.GetFileName(Path.GetDirectoryName(invocation.ProjectDirectory)) == "cycle-breakers")
{
Console.WriteLine($"Skipping Wpf Cycle-Breaker project {invocation.ProjectFilePath}");
continue;
}

if (!processed.Add(invocation.ProjectFilePath))
{
continue;
}

if (!processed.Add(Path.GetFileNameWithoutExtension(invocation.ProjectFilePath)))
{
continue;
IEnumerable<CompilerInvocation> invocations = BinLogCompilerInvocationsReader.ExtractInvocations(binlog);

// Group invocations by assembly name and select the best one for each
var invocationGroups = invocations
.Where(invocation => !string.IsNullOrEmpty(invocation.ProjectDirectory))
.Where(invocation =>
{
string projectFolder = Path.GetFileName(invocation.ProjectDirectory);
if (projectFolder == "ref" || projectFolder == "stubs")
{
Console.WriteLine($"Skipping Ref Assembly project {invocation.ProjectFilePath}");
return false;
}
if (Path.GetFileName(Path.GetDirectoryName(invocation.ProjectDirectory)) == "cycle-breakers")
{
Console.WriteLine($"Skipping Wpf Cycle-Breaker project {invocation.ProjectFilePath}");
return false;
}
return true;
})
.GroupBy(invocation => invocation.AssemblyName)
.Select(group => SelectBestInvocation(group));

var processed = new HashSet<string>();
foreach (CompilerInvocation invocation in invocationGroups)
{
if (invocation == null)
{
continue;
}

if (!processed.Add(invocation.ProjectFilePath))
{
continue;
}

if (!processed.Add(Path.GetFileNameWithoutExtension(invocation.ProjectFilePath)))
{
continue;
}
Console.WriteLine($"Converting Project: {invocation.ProjectFilePath}");

Expand Down
2 changes: 1 addition & 1 deletion src/SourceBrowser/src/Common/Common.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Microsoft.SourceBrowser.Common</AssemblyName>
<TargetFrameworks>net472;net9.0</TargetFrameworks>
<TargetFrameworks>net472;net8.0</TargetFrameworks>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\key.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>Microsoft.SourceBrowser.SourceIndexServer</AssemblyName>
<RootNamespace>Microsoft.SourceBrowser.SourceIndexServer</RootNamespace>
<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>
Expand Down