@@ -71,9 +71,9 @@ protected override void GenerateBuildScript(BuildPartition buildPartition, Artif
7171
7272 var content = new StringBuilder ( 300 )
7373 . AppendLine ( $ "call { CliPath ?? "dotnet" } { DotNetCliCommand . GetRestoreCommand ( artifactsPaths , buildPartition , projectFilePath ) } ")
74- . AppendLine ( $ "call { CliPath ?? "dotnet" } { DotNetCliCommand . GetPublishCommand ( artifactsPaths , buildPartition , projectFilePath , TargetFrameworkMoniker ) } ")
74+ . AppendLine ( $ "call { CliPath ?? "dotnet" } { DotNetCliCommand . GetBuildCommand ( artifactsPaths , buildPartition , projectFilePath , TargetFrameworkMoniker ) } ")
7575 . AppendLine ( $ "call { CliPath ?? "dotnet" } { DotNetCliCommand . GetRestoreCommand ( artifactsPaths , buildPartition , artifactsPaths . ProjectFilePath ) } ")
76- . AppendLine ( $ "call { CliPath ?? "dotnet" } { DotNetCliCommand . GetPublishCommand ( artifactsPaths , buildPartition , artifactsPaths . ProjectFilePath , TargetFrameworkMoniker ) } ")
76+ . AppendLine ( $ "call { CliPath ?? "dotnet" } { DotNetCliCommand . GetBuildCommand ( artifactsPaths , buildPartition , artifactsPaths . ProjectFilePath , TargetFrameworkMoniker ) } ")
7777 . ToString ( ) ;
7878
7979 File . WriteAllText ( artifactsPaths . BuildScriptFilePath , content ) ;
@@ -105,37 +105,63 @@ protected override void GenerateProject(BuildPartition buildPartition, Artifacts
105105 // Integration tests are built without dependencies, so we skip gathering dlls.
106106 if ( ! buildPartition . ForcedNoDependenciesForIntegrationTests )
107107 {
108- GatherReferences ( projectFile . FullName , buildPartition , artifactsPaths , logger ) ;
108+ GatherReferences ( buildPartition , artifactsPaths , logger ) ;
109109 }
110110 }
111111
112- protected void GatherReferences ( string projectFilePath , BuildPartition buildPartition , ArtifactsPaths artifactsPaths , ILogger logger )
112+ private static string GetDllGathererPath ( string filePath )
113+ => Path . Combine ( Path . GetDirectoryName ( filePath ) , $ "DllGatherer{ Path . GetExtension ( filePath ) } ") ;
114+
115+ protected void GatherReferences ( BuildPartition buildPartition , ArtifactsPaths artifactsPaths , ILogger logger )
113116 {
114- // Build the original project then reference all of the built dlls.
115- BuildResult buildResult = BuildProject ( TargetFrameworkMoniker ) ;
117+ // Copy csproj template without the generated C# file to build the original project for all necessary runtime dlls.
118+ // We can't just build the original project directly because it could be a library project, so we need an exe project to reference it.
119+ var xmlDoc = new XmlDocument ( ) ;
120+ xmlDoc . Load ( artifactsPaths . ProjectFilePath ) ;
121+ var projectElement = xmlDoc . DocumentElement ;
122+ var compileNode = projectElement . SelectSingleNode ( "ItemGroup/Compile" ) ;
123+ string emptyMainFile = GetDllGathererPath ( artifactsPaths . ProgramCodePath ) ;
124+ compileNode . Attributes [ "Include" ] . Value = emptyMainFile ;
125+ string gathererProject = GetDllGathererPath ( artifactsPaths . ProjectFilePath ) ;
126+ xmlDoc . Save ( gathererProject ) ;
127+
128+ // Generate a C# file with an empty Main method to satisfy the exe build.
129+ File . WriteAllText ( emptyMainFile , """
130+ namespace BenchmarkDotNet.Autogenerated
131+ {
132+ public class UniqueProgramName
133+ {
134+ public static int Main(string[] args)
135+ {
136+ return 0;
137+ }
138+ }
139+ }
140+ """ ) ;
116141
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- }
142+ // Build the original project then reference all of the built dlls.
143+ BuildResult buildResult = new DotNetCliCommand (
144+ CliPath ,
145+ gathererProject ,
146+ TargetFrameworkMoniker ,
147+ null ,
148+ GenerateResult . Success ( artifactsPaths , [ ] ) ,
149+ logger ,
150+ buildPartition ,
151+ [ ] ,
152+ buildPartition . Timeout
153+ ) . RestoreThenBuild ( ) ;
125154
126155 if ( ! buildResult . IsBuildSuccess )
127156 {
128- if ( ! buildResult . TryToExplainFailureReason ( out string reason ) )
129- {
130- reason = buildResult . ErrorMessage ;
131- }
132- logger . WriteLineWarning ( $ "Failed to build source project to obtain dll references. Moving forward without it. Reason: { reason } ") ;
133- return ;
157+ throw buildResult . TryToExplainFailureReason ( out string reason )
158+ ? new Exception ( reason )
159+ : new Exception ( buildResult . ErrorMessage ) ;
134160 }
135161
136- var xmlDoc = new XmlDocument ( ) ;
162+ xmlDoc = new XmlDocument ( ) ;
137163 xmlDoc . Load ( artifactsPaths . ProjectFilePath ) ;
138- XmlElement projectElement = xmlDoc . DocumentElement ;
164+ projectElement = xmlDoc . DocumentElement ;
139165 var itemGroup = xmlDoc . CreateElement ( "ItemGroup" ) ;
140166 projectElement . AppendChild ( itemGroup ) ;
141167 foreach ( var assemblyFile in Directory . GetFiles ( artifactsPaths . BinariesDirectoryPath , "*.dll" ) )
@@ -151,20 +177,6 @@ protected void GatherReferences(string projectFilePath, BuildPartition buildPart
151177 }
152178
153179 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 ( ) ;
168180 }
169181
170182 /// <summary>
0 commit comments