Skip to content

Commit a14eccb

Browse files
committed
Build again with actual tfm if the first build failed.
1 parent cc3a4e3 commit a14eccb

File tree

3 files changed

+87
-34
lines changed

3 files changed

+87
-34
lines changed

src/BenchmarkDotNet/Environments/Runtimes/CoreRuntime.cs

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using System.Reflection;
66
using System.Runtime.Versioning;
7+
using BenchmarkDotNet.Helpers;
78
using BenchmarkDotNet.Jobs;
89
using BenchmarkDotNet.Portability;
910

@@ -47,10 +48,11 @@ public static CoreRuntime CreateForNewVersion(string msBuildMoniker, string disp
4748
}
4849

4950
internal static CoreRuntime GetTargetOrCurrentVersion(Assembly? assembly)
50-
// Try to determine the Framework version that the assembly was compiled for.
51-
=> GetTargetFrameworkVersion(assembly)
51+
// Try to determine the version that the assembly was compiled for.
52+
=> FrameworkVersionHelper.GetTargetCoreVersion(assembly) is { } version
53+
? FromVersion(version)
5254
// Fallback to the current running version.
53-
?? GetCurrentVersion();
55+
: GetCurrentVersion();
5456

5557
internal static CoreRuntime GetCurrentVersion()
5658
{
@@ -249,24 +251,5 @@ private static CoreRuntime GetPlatformSpecific(CoreRuntime fallback)
249251

250252
return new CoreRuntime(fallback.RuntimeMoniker, $"{fallback.MsBuildMoniker}-{platformName}", fallback.Name);
251253
}
252-
253-
private static CoreRuntime? GetTargetFrameworkVersion(Assembly? assembly)
254-
{
255-
//.NETCoreApp,Version=vX.Y
256-
const string FrameworkPrefix = ".NETCoreApp,Version=v";
257-
// Look for a TargetFrameworkAttribute with a supported Framework version.
258-
string? framework = assembly?.GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName;
259-
if (framework?.StartsWith(FrameworkPrefix) == true
260-
&& Version.TryParse(framework[FrameworkPrefix.Length..], out var version)
261-
// We don't support netcoreapp1.X
262-
&& version.Major >= 2)
263-
{
264-
return FromVersion(version);
265-
}
266-
267-
// Null assembly, or TargetFrameworkAttribute not found, or the assembly targeted a version older than we support,
268-
// or the assembly targeted a non-core tfm (like netstandard2.0).
269-
return null;
270-
}
271254
}
272255
}

src/BenchmarkDotNet/Helpers/FrameworkVersionHelper.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Diagnostics.CodeAnalysis;
23
using System.IO;
34
using System.Linq;
45
using System.Reflection;
@@ -38,6 +39,26 @@ private static readonly (int minReleaseNumber, string version)[] FrameworkVersio
3839
_ => null,
3940
};
4041

42+
internal static Version? GetTargetCoreVersion(Assembly? assembly)
43+
{
44+
//.NETCoreApp,Version=vX.Y
45+
const string FrameworkPrefix = ".NETCoreApp,Version=v";
46+
47+
// Look for a TargetFrameworkAttribute with a supported Framework version.
48+
string? framework = assembly?.GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName;
49+
if (framework?.StartsWith(FrameworkPrefix) == true
50+
&& Version.TryParse(framework[FrameworkPrefix.Length..], out var version)
51+
// We don't support netcoreapp1.X
52+
&& version.Major >= 2)
53+
{
54+
return version;
55+
}
56+
57+
// Null assembly, or TargetFrameworkAttribute not found, or the assembly targeted a version older than we support,
58+
// or the assembly targeted a non-core tfm (like netstandard2.0).
59+
return null;
60+
}
61+
4162
internal static string GetFrameworkDescription()
4263
{
4364
var fullName = System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription; // sth like .NET Framework 4.7.3324.0
@@ -102,5 +123,42 @@ private static bool IsDeveloperPackInstalled(string version) => Directory.Exists
102123
Environment.Is64BitOperatingSystem
103124
? Environment.SpecialFolder.ProgramFilesX86
104125
: Environment.SpecialFolder.ProgramFiles);
126+
127+
internal static string? GetTfm(Assembly assembly)
128+
{
129+
// We don't support exotic frameworks like Silverlight, WindowsPhone, Xamarin.Mac, etc.
130+
const string CorePrefix = ".NETCoreApp,Version=v";
131+
const string FrameworkPrefix = ".NETFramework,Version=v";
132+
const string StandardPrefix = ".NETStandard,Version=v";
133+
134+
// Look for a TargetFrameworkAttribute with a supported Framework version.
135+
string? framework = assembly.GetCustomAttribute<TargetFrameworkAttribute>()?.FrameworkName;
136+
if (TryParseVersion(CorePrefix, out var version))
137+
{
138+
return version.Major < 5
139+
? $"netcoreapp{version.Major}.{version.Minor}"
140+
: $"net{version.Major}.{version.Minor}";
141+
}
142+
if (TryParseVersion(FrameworkPrefix, out version))
143+
{
144+
return version.Build > 0
145+
? $"net{version.Major}{version.Minor}{version.Build}"
146+
: $"net{version.Major}{version.Minor}";
147+
}
148+
if (!TryParseVersion(StandardPrefix, out version))
149+
{
150+
return $"netstandard{version.Major}.{version.Minor}";
151+
}
152+
153+
// TargetFrameworkAttribute not found, or the assembly targeted a framework we don't support,
154+
return null;
155+
156+
bool TryParseVersion(string prefix, [NotNullWhen(true)] out Version? version)
157+
{
158+
version = null;
159+
return framework?.StartsWith(prefix) == true
160+
&& Version.TryParse(framework[CorePrefix.Length..], out version);
161+
}
162+
}
105163
}
106164
}

src/BenchmarkDotNet/Toolchains/CsProj/CsProjGenerator.cs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,18 +112,16 @@ protected override void GenerateProject(BuildPartition buildPartition, Artifacts
112112
protected void GatherReferences(string projectFilePath, BuildPartition buildPartition, ArtifactsPaths artifactsPaths, ILogger logger)
113113
{
114114
// Build the original project then reference all of the built dlls.
115-
var buildResult = new DotNetCliCommand(
116-
CliPath,
117-
projectFilePath,
118-
TargetFrameworkMoniker,
119-
null,
120-
GenerateResult.Success(artifactsPaths, []),
121-
logger,
122-
buildPartition,
123-
[],
124-
buildPartition.Timeout
125-
)
126-
.RestoreThenBuild();
115+
BuildResult buildResult = BuildProject(TargetFrameworkMoniker);
116+
117+
// The build could fail because the project doesn't have a tfm that matches the runtime, e.g. netstandard2.0 vs net10.0,
118+
// So we try to get the actual tfm of the assembly and build again.
119+
if (!buildResult.IsBuildSuccess
120+
&& FrameworkVersionHelper.GetTfm(buildPartition.RepresentativeBenchmarkCase.Descriptor.Type.Assembly) is { } actualTfm
121+
&& actualTfm != TargetFrameworkMoniker)
122+
{
123+
buildResult = BuildProject(actualTfm);
124+
}
127125

128126
if (!buildResult.IsBuildSuccess)
129127
{
@@ -153,6 +151,20 @@ protected void GatherReferences(string projectFilePath, BuildPartition buildPart
153151
}
154152

155153
xmlDoc.Save(artifactsPaths.ProjectFilePath);
154+
155+
BuildResult BuildProject(string tfm)
156+
=> new DotNetCliCommand(
157+
CliPath,
158+
projectFilePath,
159+
tfm,
160+
null,
161+
GenerateResult.Success(artifactsPaths, []),
162+
logger,
163+
buildPartition,
164+
[],
165+
buildPartition.Timeout
166+
)
167+
.RestoreThenBuild();
156168
}
157169

158170
/// <summary>

0 commit comments

Comments
 (0)