4
4
using System . Linq ;
5
5
using System . Text ;
6
6
using BenchmarkDotNet . Characteristics ;
7
+ using BenchmarkDotNet . Environments ;
7
8
using BenchmarkDotNet . Extensions ;
8
9
using BenchmarkDotNet . Jobs ;
9
10
using BenchmarkDotNet . Loggers ;
@@ -32,6 +33,9 @@ public class DotNetCliCommand
32
33
33
34
[ PublicAPI ] public bool LogOutput { get ; }
34
35
36
+ // Whether to use ArtifactsPath or IntermediateOutputPath. ArtifactsPath is only supported in dotnet sdk 8+.
37
+ private readonly bool _useArtifactsPath ;
38
+
35
39
public DotNetCliCommand ( string cliPath , string arguments , GenerateResult generateResult , ILogger logger ,
36
40
BuildPartition buildPartition , IReadOnlyList < EnvironmentVariable > environmentVariables , TimeSpan timeout , bool logOutput = false )
37
41
{
@@ -43,6 +47,8 @@ public DotNetCliCommand(string cliPath, string arguments, GenerateResult generat
43
47
EnvironmentVariables = environmentVariables ;
44
48
Timeout = timeout ;
45
49
LogOutput = logOutput || ( buildPartition is not null && buildPartition . LogBuildOutput ) ;
50
+
51
+ _useArtifactsPath = DotNetCliCommandExecutor . DotNetSdkSupportsArtifactsPath ( cliPath ) ;
46
52
}
47
53
48
54
public DotNetCliCommand WithArguments ( string arguments )
@@ -71,12 +77,12 @@ public BuildResult RestoreThenBuild()
71
77
if ( BuildPartition . ForcedNoDependenciesForIntegrationTests )
72
78
{
73
79
var restoreResult = DotNetCliCommandExecutor . Execute ( WithArguments (
74
- GetRestoreCommand ( GenerateResult . ArtifactsPaths , BuildPartition , $ "{ Arguments } --no-dependencies", "restore-no-deps" , excludeOutput : true ) ) ) ;
80
+ GetRestoreCommand ( GenerateResult . ArtifactsPaths , BuildPartition , _useArtifactsPath , $ "{ Arguments } --no-dependencies", "restore-no-deps" , excludeOutput : true ) ) ) ;
75
81
if ( ! restoreResult . IsSuccess )
76
82
return BuildResult . Failure ( GenerateResult , restoreResult . AllInformation ) ;
77
83
78
84
return DotNetCliCommandExecutor . Execute ( WithArguments (
79
- GetBuildCommand ( GenerateResult . ArtifactsPaths , BuildPartition , $ "{ Arguments } --no-restore --no-dependencies", "build-no-restore-no-deps" , excludeOutput : true ) ) )
85
+ GetBuildCommand ( GenerateResult . ArtifactsPaths , BuildPartition , _useArtifactsPath , $ "{ Arguments } --no-restore --no-dependencies", "build-no-restore-no-deps" , excludeOutput : true ) ) )
80
86
. ToBuildResult ( GenerateResult ) ;
81
87
}
82
88
else
@@ -130,59 +136,62 @@ public DotNetCliCommandResult AddPackages()
130
136
131
137
public DotNetCliCommandResult Restore ( )
132
138
=> DotNetCliCommandExecutor . Execute ( WithArguments (
133
- GetRestoreCommand ( GenerateResult . ArtifactsPaths , BuildPartition , Arguments , "restore" ) ) ) ;
139
+ GetRestoreCommand ( GenerateResult . ArtifactsPaths , BuildPartition , _useArtifactsPath , Arguments , "restore" ) ) ) ;
134
140
135
141
public DotNetCliCommandResult Build ( )
136
142
=> DotNetCliCommandExecutor . Execute ( WithArguments (
137
- GetBuildCommand ( GenerateResult . ArtifactsPaths , BuildPartition , Arguments , "build" ) ) ) ;
143
+ GetBuildCommand ( GenerateResult . ArtifactsPaths , BuildPartition , _useArtifactsPath , Arguments , "build" ) ) ) ;
138
144
139
145
public DotNetCliCommandResult BuildNoRestore ( )
140
146
=> DotNetCliCommandExecutor . Execute ( WithArguments (
141
- GetBuildCommand ( GenerateResult . ArtifactsPaths , BuildPartition , $ "{ Arguments } --no-restore", "build-no-restore" ) ) ) ;
147
+ GetBuildCommand ( GenerateResult . ArtifactsPaths , BuildPartition , _useArtifactsPath , $ "{ Arguments } --no-restore", "build-no-restore" ) ) ) ;
142
148
143
149
public DotNetCliCommandResult Publish ( )
144
150
=> DotNetCliCommandExecutor . Execute ( WithArguments (
145
- GetPublishCommand ( GenerateResult . ArtifactsPaths , BuildPartition , Arguments , "publish" ) ) ) ;
151
+ GetPublishCommand ( GenerateResult . ArtifactsPaths , BuildPartition , _useArtifactsPath , Arguments , "publish" ) ) ) ;
146
152
147
153
// PublishNoBuildAndNoRestore was removed because we set --output in the build step. We use the implicit build included in the publish command.
148
154
public DotNetCliCommandResult PublishNoRestore ( )
149
155
=> DotNetCliCommandExecutor . Execute ( WithArguments (
150
- GetPublishCommand ( GenerateResult . ArtifactsPaths , BuildPartition , $ "{ Arguments } --no-restore", "publish-no-restore" ) ) ) ;
156
+ GetPublishCommand ( GenerateResult . ArtifactsPaths , BuildPartition , _useArtifactsPath , $ "{ Arguments } --no-restore", "publish-no-restore" ) ) ) ;
151
157
152
158
internal static IEnumerable < string > GetAddPackagesCommands ( BuildPartition buildPartition )
153
159
=> GetNuGetAddPackageCommands ( buildPartition . RepresentativeBenchmarkCase , buildPartition . Resolver ) ;
154
160
155
- internal static string GetRestoreCommand ( ArtifactsPaths artifactsPaths , BuildPartition buildPartition , string ? extraArguments = null , string ? binLogSuffix = null , bool excludeOutput = false )
161
+ internal static string GetRestoreCommand ( ArtifactsPaths artifactsPaths , BuildPartition buildPartition ,
162
+ bool useArtifactsPath , string ? extraArguments = null , string ? binLogSuffix = null , bool excludeOutput = false )
156
163
=> new StringBuilder ( )
157
164
. AppendArgument ( "restore" )
158
165
. AppendArgument ( string . IsNullOrEmpty ( artifactsPaths . PackagesDirectoryName ) ? string . Empty : $ "--packages \" { artifactsPaths . PackagesDirectoryName } \" ")
159
166
. AppendArgument ( GetCustomMsBuildArguments ( buildPartition . RepresentativeBenchmarkCase , buildPartition . Resolver ) )
160
167
. AppendArgument ( extraArguments )
161
168
. AppendArgument ( GetMandatoryMsBuildSettings ( buildPartition . BuildConfiguration ) )
162
169
. AppendArgument ( GetMsBuildBinLogArgument ( buildPartition , binLogSuffix ) )
163
- . MaybeAppendOutputPaths ( artifactsPaths , true , excludeOutput )
170
+ . MaybeAppendOutputPaths ( artifactsPaths , useArtifactsPath , true , excludeOutput )
164
171
. ToString ( ) ;
165
172
166
- internal static string GetBuildCommand ( ArtifactsPaths artifactsPaths , BuildPartition buildPartition , string ? extraArguments = null , string ? binLogSuffix = null , bool excludeOutput = false )
173
+ internal static string GetBuildCommand ( ArtifactsPaths artifactsPaths , BuildPartition buildPartition ,
174
+ bool useArtifactsPath , string ? extraArguments = null , string ? binLogSuffix = null , bool excludeOutput = false )
167
175
=> new StringBuilder ( )
168
176
. AppendArgument ( $ "build -c { buildPartition . BuildConfiguration } ") // we don't need to specify TFM, our auto-generated project contains always single one
169
177
. AppendArgument ( GetCustomMsBuildArguments ( buildPartition . RepresentativeBenchmarkCase , buildPartition . Resolver ) )
170
178
. AppendArgument ( extraArguments )
171
179
. AppendArgument ( GetMandatoryMsBuildSettings ( buildPartition . BuildConfiguration ) )
172
180
. AppendArgument ( string . IsNullOrEmpty ( artifactsPaths . PackagesDirectoryName ) ? string . Empty : $ "/p:NuGetPackageRoot=\" { artifactsPaths . PackagesDirectoryName } \" ")
173
181
. AppendArgument ( GetMsBuildBinLogArgument ( buildPartition , binLogSuffix ) )
174
- . MaybeAppendOutputPaths ( artifactsPaths , excludeOutput : excludeOutput )
182
+ . MaybeAppendOutputPaths ( artifactsPaths , useArtifactsPath , excludeOutput : excludeOutput )
175
183
. ToString ( ) ;
176
184
177
- internal static string GetPublishCommand ( ArtifactsPaths artifactsPaths , BuildPartition buildPartition , string ? extraArguments = null , string ? binLogSuffix = null )
185
+ internal static string GetPublishCommand ( ArtifactsPaths artifactsPaths , BuildPartition buildPartition ,
186
+ bool useArtifactsPath , string ? extraArguments = null , string ? binLogSuffix = null )
178
187
=> new StringBuilder ( )
179
188
. AppendArgument ( $ "publish -c { buildPartition . BuildConfiguration } ") // we don't need to specify TFM, our auto-generated project contains always single one
180
189
. AppendArgument ( GetCustomMsBuildArguments ( buildPartition . RepresentativeBenchmarkCase , buildPartition . Resolver ) )
181
190
. AppendArgument ( extraArguments )
182
191
. AppendArgument ( GetMandatoryMsBuildSettings ( buildPartition . BuildConfiguration ) )
183
192
. AppendArgument ( string . IsNullOrEmpty ( artifactsPaths . PackagesDirectoryName ) ? string . Empty : $ "/p:NuGetPackageRoot=\" { artifactsPaths . PackagesDirectoryName } \" ")
184
193
. AppendArgument ( GetMsBuildBinLogArgument ( buildPartition , binLogSuffix ) )
185
- . MaybeAppendOutputPaths ( artifactsPaths )
194
+ . MaybeAppendOutputPaths ( artifactsPaths , useArtifactsPath )
186
195
. ToString ( ) ;
187
196
188
197
private static string GetMsBuildBinLogArgument ( BuildPartition buildPartition , string suffix )
@@ -257,15 +266,22 @@ internal static class DotNetCliCommandExtensions
257
266
// We force the project to output binaries to a new directory.
258
267
// Specifying --output and --no-dependencies breaks the build (because the previous build was not done using the custom output path),
259
268
// so we don't include it if we're building no-deps (only supported for integration tests).
260
- internal static StringBuilder MaybeAppendOutputPaths ( this StringBuilder stringBuilder , ArtifactsPaths artifactsPaths , bool isRestore = false , bool excludeOutput = false )
269
+ internal static StringBuilder MaybeAppendOutputPaths ( this StringBuilder stringBuilder , ArtifactsPaths artifactsPaths , bool useArtifactsPath , bool isRestore = false , bool excludeOutput = false )
261
270
=> excludeOutput
262
271
? stringBuilder
263
272
: stringBuilder
264
273
// Use AltDirectorySeparatorChar so it's not interpreted as an escaped quote `\"`.
265
- . AppendArgument ( $ "/p:IntermediateOutputPath=\" { artifactsPaths . IntermediateDirectoryPath } { Path . AltDirectorySeparatorChar } \" ")
274
+ . AppendArgument ( useArtifactsPath
275
+ // We set ArtifactsPath for dotnet sdk 8+, fallback to IntermediateOutputPath for older sdks.
276
+ ? $ "/p:ArtifactsPath=\" { artifactsPaths . BuildArtifactsDirectoryPath } { Path . AltDirectorySeparatorChar } \" "
277
+ // This is technically incorrect (#2664, #2425), but it's the best we can do for older sdks.
278
+ // MSBuild does not support setting BaseIntermediateOutputPath from command line. https://github.com/dotnet/sdk/issues/2003#issuecomment-369408964
279
+ : $ "/p:IntermediateOutputPath=\" { artifactsPaths . IntermediateDirectoryPath } { Path . AltDirectorySeparatorChar } \" "
280
+ )
266
281
. AppendArgument ( $ "/p:OutDir=\" { artifactsPaths . BinariesDirectoryPath } { Path . AltDirectorySeparatorChar } \" ")
267
282
// OutputPath is legacy, per-project version of OutDir. We set both just in case. https://github.com/dotnet/msbuild/issues/87
268
283
. AppendArgument ( $ "/p:OutputPath=\" { artifactsPaths . BinariesDirectoryPath } { Path . AltDirectorySeparatorChar } \" ")
284
+ . AppendArgument ( $ "/p:PublishDir=\" { artifactsPaths . PublishDirectoryPath } { Path . AltDirectorySeparatorChar } \" ")
269
285
. AppendArgument ( isRestore ? string . Empty : $ "--output \" { artifactsPaths . BinariesDirectoryPath } { Path . AltDirectorySeparatorChar } \" ") ;
270
286
}
271
287
}
0 commit comments