@@ -50,6 +50,20 @@ internal sealed partial class CSharpCompilerCommand
5050 public required string ArtifactsPath { get ; init ; }
5151 public required bool CanReuseAuxiliaryFiles { get ; init ; }
5252
53+ public string BaseDirectory => field ??= Path . GetDirectoryName ( EntryPointFileFullPath ) ! ;
54+
55+ /// <summary>
56+ /// Compiler command line arguments to use. If empty, default arguments are used.
57+ /// These should be already properly escaped.
58+ /// </summary>
59+ public required ImmutableArray < string > CscArguments { get ; init ; }
60+
61+ /// <summary>
62+ /// Path to the <c>bin/Program.dll</c> file. If specified,
63+ /// the compiled output (<c>obj/Program.dll</c>) will be copied to this location.
64+ /// </summary>
65+ public required string ? BuildResultFile { get ; init ; }
66+
5367 /// <param name="fallbackToNormalBuild">
5468 /// Whether the returned error code should not cause the build to fail but instead fallback to full MSBuild.
5569 /// </param>
@@ -64,7 +78,7 @@ public int Execute(out bool fallbackToNormalBuild)
6478 requestId : EntryPointFileFullPath ,
6579 language : RequestLanguage . CSharpCompile ,
6680 arguments : [ "/noconfig" , "/nologo" , $ "@{ EscapeSingleArg ( rspPath ) } "] ,
67- workingDirectory : Environment . CurrentDirectory ,
81+ workingDirectory : BaseDirectory ,
6882 tempDirectory : Path . GetTempPath ( ) ,
6983 keepAlive : null ,
7084 libDirectory : null ,
@@ -87,7 +101,18 @@ public int Execute(out bool fallbackToNormalBuild)
87101 cancellationToken : default ) ;
88102
89103 // Process the response.
90- return ProcessBuildResponse ( responseTask . Result , out fallbackToNormalBuild ) ;
104+ var exitCode = ProcessBuildResponse ( responseTask . Result , out fallbackToNormalBuild ) ;
105+
106+ // Copy from obj to bin.
107+ if ( BuildResultFile != null &&
108+ CSharpCommandLineParser . Default . Parse ( CscArguments , BaseDirectory , sdkDirectory : null ) is { OutputFileName : { } outputFileName } parsedArgs )
109+ {
110+ var objFile = parsedArgs . GetOutputFilePath ( outputFileName ) ;
111+ Reporter . Verbose . WriteLine ( $ "Copying '{ objFile } ' to '{ BuildResultFile } '.") ;
112+ File . Copy ( objFile , BuildResultFile , overwrite : true ) ;
113+ }
114+
115+ return exitCode ;
91116
92117 static string GetCompilerCommitHash ( )
93118 {
@@ -129,6 +154,14 @@ static int ProcessBuildResponse(BuildResponse response, out bool fallbackToNorma
129154
130155 private void PrepareAuxiliaryFiles ( out string rspPath )
131156 {
157+ rspPath = Path . Join ( ArtifactsPath , "csc.rsp" ) ;
158+
159+ if ( ! CscArguments . IsDefaultOrEmpty )
160+ {
161+ File . WriteAllLines ( rspPath , CscArguments ) ;
162+ return ;
163+ }
164+
132165 string fileDirectory = Path . GetDirectoryName ( EntryPointFileFullPath ) ?? string . Empty ;
133166 string fileNameWithoutExtension = Path . GetFileNameWithoutExtension ( EntryPointFileFullPath ) ;
134167
@@ -283,7 +316,6 @@ private void PrepareAuxiliaryFiles(out string rspPath)
283316 """ ) ;
284317 }
285318
286- rspPath = Path . Join ( ArtifactsPath , "csc.rsp" ) ;
287319 if ( ShouldEmit ( rspPath ) )
288320 {
289321 IEnumerable < string > args = GetCscArguments (
@@ -315,18 +347,18 @@ private static string EscapeSingleArg(string arg)
315347 {
316348 if ( IsPathOption ( arg , out var colonIndex ) )
317349 {
318- return arg [ ..( colonIndex + 1 ) ] + EscapeCore ( arg [ ( colonIndex + 1 ) ..] ) ;
350+ return arg [ ..( colonIndex + 1 ) ] + EscapePathArgument ( arg [ ( colonIndex + 1 ) ..] ) ;
319351 }
320352
321- return EscapeCore ( arg ) ;
353+ return EscapePathArgument ( arg ) ;
354+ }
322355
323- static string EscapeCore ( string arg )
356+ internal static string EscapePathArgument ( string arg )
357+ {
358+ return ArgumentEscaper . EscapeSingleArg ( arg , additionalShouldSurroundWithQuotes : static ( string arg ) =>
324359 {
325- return ArgumentEscaper . EscapeSingleArg ( arg , additionalShouldSurroundWithQuotes : static ( string arg ) =>
326- {
327- return arg . ContainsAny ( s_additionalShouldSurroundWithQuotes ) ;
328- } ) ;
329- }
360+ return arg . ContainsAny ( s_additionalShouldSurroundWithQuotes ) ;
361+ } ) ;
330362 }
331363
332364 public static bool IsPathOption ( string arg , out int colonIndex )
0 commit comments