Skip to content

Commit ce206fb

Browse files
committed
Build source project directly.
1 parent 4025481 commit ce206fb

19 files changed

+140
-253
lines changed

src/BenchmarkDotNet/Diagnosers/PerfCollectProfiler.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,13 +229,14 @@ private void EnsureSymbolsForNativeRuntime(DiagnoserActionParameters parameters)
229229
// We install the tool in a dedicated directory in order to always use latest version and avoid issues with broken existing configs.
230230
string toolPath = Path.Combine(Path.GetTempPath(), "BenchmarkDotNet", "symbols");
231231
DotNetCliCommand cliCommand = new(
232-
projPath: string.Empty,
233232
cliPath: cliPath,
233+
filePath: string.Empty,
234+
tfm: string.Empty,
234235
arguments: $"tool install dotnet-symbol --tool-path \"{toolPath}\"",
235236
generateResult: null,
236237
logger: logger,
237238
buildPartition: null,
238-
environmentVariables: Array.Empty<EnvironmentVariable>(),
239+
environmentVariables: [],
239240
timeout: TimeSpan.FromMinutes(3),
240241
logOutput: true); // the following commands might take a while and fail, let's log them
241242

src/BenchmarkDotNet/Toolchains/ArtifactsPaths.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace BenchmarkDotNet.Toolchains
44
{
55
public class ArtifactsPaths
66
{
7-
public static readonly ArtifactsPaths Empty = new("", "", "", "", "", "", "", "", "", "", "", "", "");
7+
public static readonly ArtifactsPaths Empty = new("", "", "", "", "", "", "", "", "", "", "", "");
88

99
[PublicAPI] public string RootArtifactsFolderPath { get; }
1010
[PublicAPI] public string BuildArtifactsDirectoryPath { get; }
@@ -13,7 +13,6 @@ public class ArtifactsPaths
1313
[PublicAPI] public string ProgramCodePath { get; }
1414
[PublicAPI] public string AppConfigPath { get; }
1515
[PublicAPI] public string NuGetConfigPath { get; }
16-
[PublicAPI] public string BuildForReferencesProjectFilePath { get; }
1716
[PublicAPI] public string ProjectFilePath { get; }
1817
[PublicAPI] public string BuildScriptFilePath { get; }
1918
[PublicAPI] public string ExecutablePath { get; }
@@ -28,7 +27,6 @@ public ArtifactsPaths(
2827
string programCodePath,
2928
string appConfigPath,
3029
string nuGetConfigPath,
31-
string buildForReferencesProjectFilePath,
3230
string projectFilePath,
3331
string buildScriptFilePath,
3432
string executablePath,
@@ -42,7 +40,6 @@ public ArtifactsPaths(
4240
ProgramCodePath = programCodePath;
4341
AppConfigPath = appConfigPath;
4442
NuGetConfigPath = nuGetConfigPath;
45-
BuildForReferencesProjectFilePath = buildForReferencesProjectFilePath;
4643
ProjectFilePath = projectFilePath;
4744
BuildScriptFilePath = buildScriptFilePath;
4845
ExecutablePath = executablePath;

src/BenchmarkDotNet/Toolchains/CoreRun/CoreRunPublisher.cs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,11 @@
99

1010
namespace BenchmarkDotNet.Toolchains.CoreRun
1111
{
12-
public class CoreRunPublisher : IBuilder
12+
public class CoreRunPublisher(string tfm, FileInfo coreRun, FileInfo? customDotNetCliPath = null) : DotNetCliPublisher(tfm, customDotNetCliPath?.FullName)
1313
{
14-
public CoreRunPublisher(FileInfo coreRun, FileInfo? customDotNetCliPath = null)
14+
public override BuildResult Build(GenerateResult generateResult, BuildPartition buildPartition, ILogger logger)
1515
{
16-
CoreRun = coreRun;
17-
DotNetCliPublisher = new DotNetCliPublisher(customDotNetCliPath?.FullName);
18-
}
19-
20-
private FileInfo CoreRun { get; }
21-
22-
private DotNetCliPublisher DotNetCliPublisher { get; }
23-
24-
public BuildResult Build(GenerateResult generateResult, BuildPartition buildPartition, ILogger logger)
25-
{
26-
var buildResult = DotNetCliPublisher.Build(generateResult, buildPartition, logger);
16+
var buildResult = base.Build(generateResult, buildPartition, logger);
2717

2818
if (buildResult.IsBuildSuccess)
2919
UpdateDuplicatedDependencies(buildResult.ArtifactsPaths, logger);
@@ -37,7 +27,7 @@ public BuildResult Build(GenerateResult generateResult, BuildPartition buildPart
3727
private void UpdateDuplicatedDependencies(ArtifactsPaths artifactsPaths, ILogger logger)
3828
{
3929
var publishedDirectory = new DirectoryInfo(artifactsPaths.BinariesDirectoryPath);
40-
var coreRunDirectory = CoreRun.Directory;
30+
var coreRunDirectory = coreRun.Directory;
4131

4232
foreach (var publishedDependency in publishedDirectory
4333
.EnumerateFileSystemInfos()

src/BenchmarkDotNet/Toolchains/CoreRun/CoreRunToolchain.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public CoreRunToolchain(FileInfo coreRun, bool createCopy = true,
3434

3535
Name = displayName;
3636
Generator = new CoreRunGenerator(SourceCoreRun, CopyCoreRun, targetFrameworkMoniker, customDotNetCliPath?.FullName, restorePath?.FullName);
37-
Builder = new CoreRunPublisher(CopyCoreRun, customDotNetCliPath);
37+
Builder = new CoreRunPublisher(targetFrameworkMoniker, CopyCoreRun, customDotNetCliPath);
3838
Executor = new DotNetCliExecutor(customDotNetCliPath: CopyCoreRun.FullName); // instead of executing "dotnet $pathToDll" we do "CoreRun $pathToDll"
3939
}
4040

src/BenchmarkDotNet/Toolchains/CsProj/CsProjGenerator.cs

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using BenchmarkDotNet.Loggers;
1515
using BenchmarkDotNet.Running;
1616
using BenchmarkDotNet.Toolchains.DotNetCli;
17+
using BenchmarkDotNet.Toolchains.Results;
1718
using JetBrains.Annotations;
1819

1920
namespace BenchmarkDotNet.Toolchains.CsProj
@@ -61,58 +62,94 @@ protected override string GetBuildArtifactsDirectoryPath(BuildPartition buildPar
6162
protected override string GetProjectFilePath(string buildArtifactsDirectoryPath)
6263
=> Path.Combine(buildArtifactsDirectoryPath, "BenchmarkDotNet.Autogenerated.csproj");
6364

64-
protected override string GetProjectFilePathForReferences(string buildArtifactsDirectoryPath)
65-
=> Path.Combine(buildArtifactsDirectoryPath, "BenchmarkDotNet.Autogenerated.ForReferences.csproj");
66-
6765
protected override string GetBinariesDirectoryPath(string buildArtifactsDirectoryPath, string configuration)
6866
=> Path.Combine(buildArtifactsDirectoryPath, "bin", configuration, TargetFrameworkMoniker);
6967

70-
[SuppressMessage("ReSharper", "StringLiteralTypo")] // R# complains about $variables$
71-
private string LoadCsProj(BuildPartition buildPartition, ArtifactsPaths artifactsPaths, string projectFile, string customProperties, string sdkName)
72-
=> new StringBuilder(ResourceHelper.LoadTemplate("CsProj.txt"))
73-
.Replace("$PLATFORM$", buildPartition.Platform.ToConfig())
74-
.Replace("$CODEFILENAME$", Path.GetFileName(artifactsPaths.ProgramCodePath))
75-
.Replace("$CSPROJPATH$", projectFile)
76-
.Replace("$TFM$", TargetFrameworkMoniker)
77-
.Replace("$PROGRAMNAME$", artifactsPaths.ProgramName)
78-
.Replace("$RUNTIMESETTINGS$", GetRuntimeSettings(buildPartition.RepresentativeBenchmarkCase.Job.Environment.Gc, buildPartition.Resolver))
79-
.Replace("$COPIEDSETTINGS$", customProperties)
80-
.Replace("$SDKNAME$", sdkName)
68+
protected override void GenerateBuildScript(BuildPartition buildPartition, ArtifactsPaths artifactsPaths)
69+
{
70+
string projectFilePath = GetProjectFilePath(buildPartition.RepresentativeBenchmarkCase.Descriptor.Type, NullLogger.Instance).FullName;
71+
72+
var content = new StringBuilder(300)
73+
.AppendLine($"call {CliPath ?? "dotnet"} {DotNetCliCommand.GetRestoreCommand(artifactsPaths, buildPartition, projectFilePath)}")
74+
.AppendLine($"call {CliPath ?? "dotnet"} {DotNetCliCommand.GetPublishCommand(artifactsPaths, buildPartition, projectFilePath, TargetFrameworkMoniker)}")
75+
.AppendLine($"call {CliPath ?? "dotnet"} {DotNetCliCommand.GetRestoreCommand(artifactsPaths, buildPartition, artifactsPaths.ProjectFilePath)}")
76+
.AppendLine($"call {CliPath ?? "dotnet"} {DotNetCliCommand.GetPublishCommand(artifactsPaths, buildPartition, artifactsPaths.ProjectFilePath, TargetFrameworkMoniker)}")
8177
.ToString();
8278

79+
File.WriteAllText(artifactsPaths.BuildScriptFilePath, content);
80+
}
81+
82+
[SuppressMessage("ReSharper", "StringLiteralTypo")] // R# complains about $variables$
8383
protected override void GenerateProject(BuildPartition buildPartition, ArtifactsPaths artifactsPaths, ILogger logger)
8484
{
85-
var projectFile = GetProjectFilePath(buildPartition.RepresentativeBenchmarkCase.Descriptor.Type, logger);
85+
var benchmark = buildPartition.RepresentativeBenchmarkCase;
86+
var projectFile = GetProjectFilePath(benchmark.Descriptor.Type, logger);
8687

8788
var xmlDoc = new XmlDocument();
8889
xmlDoc.Load(projectFile.FullName);
8990
var (customProperties, sdkName) = GetSettingsThatNeedToBeCopied(xmlDoc, projectFile);
9091

91-
GenerateBuildForReferencesProject(buildPartition, artifactsPaths, projectFile.FullName, customProperties, sdkName);
92-
93-
var content = LoadCsProj(buildPartition, artifactsPaths, projectFile.FullName, customProperties, sdkName);
92+
var content = new StringBuilder(ResourceHelper.LoadTemplate("CsProj.txt"))
93+
.Replace("$PLATFORM$", buildPartition.Platform.ToConfig())
94+
.Replace("$CODEFILENAME$", Path.GetFileName(artifactsPaths.ProgramCodePath))
95+
.Replace("$CSPROJPATH$", projectFile.FullName)
96+
.Replace("$TFM$", TargetFrameworkMoniker)
97+
.Replace("$PROGRAMNAME$", artifactsPaths.ProgramName)
98+
.Replace("$RUNTIMESETTINGS$", GetRuntimeSettings(benchmark.Job.Environment.Gc, buildPartition.Resolver))
99+
.Replace("$COPIEDSETTINGS$", customProperties)
100+
.Replace("$SDKNAME$", sdkName)
101+
.ToString();
94102

95103
File.WriteAllText(artifactsPaths.ProjectFilePath, content);
104+
105+
// Integration tests are built without dependencies, so we skip gathering dlls.
106+
if (!buildPartition.ForcedNoDependenciesForIntegrationTests)
107+
{
108+
GatherReferences(projectFile.FullName, buildPartition, artifactsPaths, logger);
109+
}
96110
}
97111

98-
protected void GenerateBuildForReferencesProject(BuildPartition buildPartition, ArtifactsPaths artifactsPaths, string projectFile, string customProperties, string sdkName)
112+
protected void GatherReferences(string projectFilePath, BuildPartition buildPartition, ArtifactsPaths artifactsPaths, ILogger logger)
99113
{
100-
var content = LoadCsProj(buildPartition, artifactsPaths, projectFile, customProperties, sdkName);
114+
// 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();
127+
128+
if (!buildResult.IsBuildSuccess)
129+
{
130+
throw buildResult.TryToExplainFailureReason(out string reason)
131+
? new Exception(reason)
132+
: new Exception(buildResult.ErrorMessage);
133+
}
101134

102-
// We don't include the generated .notcs file when building the reference dlls, only in the final build.
103135
var xmlDoc = new XmlDocument();
104-
xmlDoc.Load(new StringReader(content));
136+
xmlDoc.Load(artifactsPaths.ProjectFilePath);
105137
XmlElement projectElement = xmlDoc.DocumentElement;
106-
projectElement.RemoveChild(projectElement.SelectSingleNode("ItemGroup/Compile").ParentNode);
107-
108-
var startupObjectElement = projectElement.SelectSingleNode("PropertyGroup/StartupObject");
109-
startupObjectElement.ParentNode.RemoveChild(startupObjectElement);
110-
111-
// We need to change the output type to library since we're only compiling for dlls.
112-
var outputTypeElement = projectElement.SelectSingleNode("PropertyGroup/OutputType");
113-
outputTypeElement.InnerText = "Library";
138+
var itemGroup = xmlDoc.CreateElement("ItemGroup");
139+
projectElement.AppendChild(itemGroup);
140+
foreach (var assemblyFile in Directory.GetFiles(artifactsPaths.BinariesDirectoryPath, "*.dll"))
141+
{
142+
var referenceElement = xmlDoc.CreateElement("Reference");
143+
itemGroup.AppendChild(referenceElement);
144+
referenceElement.SetAttribute("Include", Path.GetFileNameWithoutExtension(assemblyFile));
145+
var hintPath = xmlDoc.CreateElement("HintPath");
146+
referenceElement.AppendChild(hintPath);
147+
var locationNode = xmlDoc.CreateTextNode(assemblyFile);
148+
hintPath.AppendChild(locationNode);
149+
// TODO: Add Aliases here for extern alias #2289
150+
}
114151

115-
xmlDoc.Save(artifactsPaths.BuildForReferencesProjectFilePath);
152+
xmlDoc.Save(artifactsPaths.ProjectFilePath);
116153
}
117154

118155
/// <summary>
Lines changed: 6 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
using System;
2-
using System.IO;
3-
using System.Xml;
42
using BenchmarkDotNet.Jobs;
53
using BenchmarkDotNet.Loggers;
64
using BenchmarkDotNet.Running;
@@ -27,69 +25,24 @@ public DotNetCliBuilder(string targetFrameworkMoniker, string? customDotNetCliPa
2725

2826
public BuildResult Build(GenerateResult generateResult, BuildPartition buildPartition, ILogger logger)
2927
{
30-
var cliCommand = new DotNetCliCommand(
31-
generateResult.ArtifactsPaths.BuildForReferencesProjectFilePath,
28+
var buildResult = new DotNetCliCommand(
3229
CustomDotNetCliPath,
30+
generateResult.ArtifactsPaths.ProjectFilePath,
31+
TargetFrameworkMoniker,
3332
string.Empty,
3433
generateResult,
3534
logger,
3635
buildPartition,
37-
Array.Empty<EnvironmentVariable>(),
36+
[],
3837
buildPartition.Timeout,
39-
logOutput: LogOutput);
40-
41-
BuildResult buildResult;
42-
// Integration tests are built without dependencies, so we skip the first step.
43-
if (!buildPartition.ForcedNoDependenciesForIntegrationTests)
44-
{
45-
// We build the original project first to obtain all dlls.
46-
buildResult = cliCommand.RestoreThenBuild();
47-
48-
if (!buildResult.IsBuildSuccess)
49-
return buildResult;
50-
51-
// After the dlls are built, we gather the assembly references, then build the benchmark project.
52-
GatherReferences(generateResult.ArtifactsPaths);
53-
}
54-
55-
buildResult = cliCommand.WithProjPath(generateResult.ArtifactsPaths.ProjectFilePath)
56-
.RestoreThenBuild();
57-
38+
logOutput: LogOutput
39+
).RestoreThenBuild();
5840
if (buildResult.IsBuildSuccess &&
5941
buildPartition.RepresentativeBenchmarkCase.Job.Environment.LargeAddressAware)
6042
{
6143
LargeAddressAware.SetLargeAddressAware(generateResult.ArtifactsPaths.ExecutablePath);
6244
}
6345
return buildResult;
6446
}
65-
66-
internal static void GatherReferences(ArtifactsPaths artifactsPaths)
67-
{
68-
var xmlDoc = new XmlDocument();
69-
xmlDoc.Load(artifactsPaths.ProjectFilePath);
70-
XmlElement projectElement = xmlDoc.DocumentElement;
71-
72-
// Add reference to every dll.
73-
var itemGroup = xmlDoc.CreateElement("ItemGroup");
74-
projectElement.AppendChild(itemGroup);
75-
foreach (var assemblyFile in Directory.GetFiles(artifactsPaths.BinariesDirectoryPath, "*.dll"))
76-
{
77-
var assemblyName = Path.GetFileNameWithoutExtension(assemblyFile);
78-
// The dummy csproj was used to build the original project, but it also outputs a dll for itself which we need to ignore because it's not valid.
79-
if (assemblyName == artifactsPaths.ProgramName)
80-
{
81-
continue;
82-
}
83-
var referenceElement = xmlDoc.CreateElement("Reference");
84-
itemGroup.AppendChild(referenceElement);
85-
referenceElement.SetAttribute("Include", assemblyName);
86-
var hintPath = xmlDoc.CreateElement("HintPath");
87-
referenceElement.AppendChild(hintPath);
88-
var locationNode = xmlDoc.CreateTextNode(assemblyFile);
89-
hintPath.AppendChild(locationNode);
90-
}
91-
92-
xmlDoc.Save(artifactsPaths.ProjectFilePath);
93-
}
9447
}
9548
}

0 commit comments

Comments
 (0)