@@ -21,8 +21,8 @@ const localize: nls.LocalizeFunc = nls.loadMessageBundle();
21
21
export interface CppBuildTaskDefinition extends TaskDefinition {
22
22
type : string ;
23
23
label : string ; // The label appears in tasks.json file.
24
- command : string ;
25
- args : string [ ] ;
24
+ command : string | util . IQuotedString ;
25
+ args : ( string | util . IQuotedString ) [ ] ;
26
26
options : cp . ExecOptions | cp . SpawnOptions | undefined ;
27
27
}
28
28
@@ -166,20 +166,24 @@ export class CppBuildTaskProvider implements TaskProvider {
166
166
return result ;
167
167
}
168
168
169
- private getTask : ( compilerPath : string , appendSourceToName : boolean , compilerArgs ?: string [ ] , definition ?: CppBuildTaskDefinition , detail ?: string ) => Task = ( compilerPath : string , appendSourceToName : boolean , compilerArgs ?: string [ ] , definition ?: CppBuildTaskDefinition , detail ?: string ) => {
170
- const compilerPathBase : string = path . basename ( compilerPath ) ;
169
+ private getTask : ( compilerPath : string | util . IQuotedString , appendSourceToName : boolean , compilerArgs ?: ( string | util . IQuotedString ) [ ] , definition ?: CppBuildTaskDefinition , detail ?: string ) => Task = ( compilerPath : string | util . IQuotedString , appendSourceToName : boolean , compilerArgs ?: ( string | util . IQuotedString ) [ ] , definition ?: CppBuildTaskDefinition , detail ?: string ) => {
170
+ const compilerPathString : string = util . isString ( compilerPath ) ? compilerPath : compilerPath . value ;
171
+ const compilerPathBase : string = path . basename ( compilerPathString ) ;
171
172
const isCl : boolean = compilerPathBase . toLowerCase ( ) === "cl.exe" ;
172
173
const isClang : boolean = ! isCl && compilerPathBase . toLowerCase ( ) . includes ( "clang" ) ;
173
174
// Double-quote the command if needed.
174
- let resolvedcompilerPath : string = isCl ? compilerPathBase : compilerPath ;
175
- resolvedcompilerPath = util . quoteArgument ( resolvedcompilerPath ) ;
175
+ const resolvedCompilerPathString : string = isCl ? compilerPathBase : compilerPathString ;
176
+ let resolvedCompilerPath : string | util . IQuotedString = compilerPath ;
177
+ if ( isCl ) {
178
+ resolvedCompilerPath = compilerPathBase ;
179
+ }
176
180
177
181
if ( ! definition ) {
178
182
const isWindows : boolean = os . platform ( ) === 'win32' ;
179
183
const taskLabel : string = ( ( appendSourceToName && ! compilerPathBase . startsWith ( ext . configPrefix ) ) ?
180
184
ext . configPrefix : "" ) + compilerPathBase + " " + localize ( "build.active.file" , "build active file" ) ;
181
185
const programName : string = util . defaultExePath ( ) ;
182
- let args : string [ ] = isCl ?
186
+ let args : ( string | util . IQuotedString ) [ ] = isCl ?
183
187
[ '/Zi' , '/EHsc' , '/nologo' , `/Fe${ programName } ` , '${file}' ] :
184
188
isClang ?
185
189
[ '-fcolor-diagnostics' , '-fansi-escape-codes' , '-g' , '${file}' , '-o' , programName ] :
@@ -188,30 +192,38 @@ export class CppBuildTaskProvider implements TaskProvider {
188
192
if ( compilerArgs && compilerArgs . length > 0 ) {
189
193
args = args . concat ( compilerArgs ) ;
190
194
}
191
- const cwd : string = isWindows && ! isCl && ! process . env . PATH ?. includes ( path . dirname ( compilerPath ) ) ? path . dirname ( compilerPath ) : "${fileDirname}" ;
195
+ const cwd : string = isWindows && ! isCl && ! process . env . PATH ?. includes ( path . dirname ( compilerPathString ) ) ? path . dirname ( compilerPathString ) : "${fileDirname}" ;
192
196
const options : cp . ExecOptions | cp . SpawnOptions | undefined = { cwd : cwd } ;
193
197
definition = {
194
198
type : CppBuildTaskProvider . CppBuildScriptType ,
195
199
label : taskLabel ,
196
- command : isCl ? compilerPathBase : compilerPath ,
200
+ command : compilerPath ,
197
201
args : args ,
198
202
options : options
199
203
} ;
204
+ if ( isCl ) {
205
+ definition . command = compilerPathBase ;
206
+ }
200
207
}
201
208
202
209
const editor : TextEditor | undefined = window . activeTextEditor ;
203
210
const folder : WorkspaceFolder | undefined = editor ? workspace . getWorkspaceFolder ( editor . document . uri ) : undefined ;
204
211
205
- const taskUsesActiveFile : boolean = definition . args . some ( arg => arg . indexOf ( '${file}' ) >= 0 ) ; // Need to check this before ${file} is resolved
212
+ const taskUsesActiveFile : boolean = definition . args . some ( arg => {
213
+ if ( util . isString ( arg ) ) {
214
+ return arg . indexOf ( '${file}' ) >= 0 ;
215
+ }
216
+ return arg . value . indexOf ( '${file}' ) >= 0 ;
217
+ } ) ; // Need to check this before ${file} is resolved
206
218
const scope : WorkspaceFolder | TaskScope = folder ? folder : TaskScope . Workspace ;
207
219
const task : CppBuildTask = new Task ( definition , scope , definition . label , ext . CppSourceStr ,
208
220
new CustomExecution ( async ( resolvedDefinition : TaskDefinition ) : Promise < Pseudoterminal > =>
209
221
// When the task is executed, this callback will run. Here, we setup for running the task.
210
- new CustomBuildTaskTerminal ( resolvedcompilerPath , resolvedDefinition . args , resolvedDefinition . options , { taskUsesActiveFile, insertStd : isClang && os . platform ( ) === 'darwin' } )
222
+ new CustomBuildTaskTerminal ( resolvedCompilerPath , resolvedDefinition . args , resolvedDefinition . options , { taskUsesActiveFile, insertStd : isClang && os . platform ( ) === 'darwin' } )
211
223
) , isCl ? '$msCompile' : '$gcc' ) ;
212
224
213
225
task . group = TaskGroup . Build ;
214
- task . detail = detail ? detail : localize ( "compiler.details" , "compiler:" ) + " " + resolvedcompilerPath ;
226
+ task . detail = detail ? detail : localize ( "compiler.details" , "compiler:" ) + " " + resolvedCompilerPathString ;
215
227
216
228
return task ;
217
229
} ;
@@ -354,7 +366,7 @@ class CustomBuildTaskTerminal implements Pseudoterminal {
354
366
public get onDidClose ( ) : Event < number > { return this . closeEmitter . event ; }
355
367
private endOfLine : string = "\r\n" ;
356
368
357
- constructor ( private command : string , private args : string [ ] , private options : cp . ExecOptions | cp . SpawnOptions | undefined , private buildOptions : BuildOptions ) {
369
+ constructor ( private command : string | util . IQuotedString , private args : ( string | util . IQuotedString ) [ ] , private options : cp . ExecOptions | undefined , private buildOptions : BuildOptions ) {
358
370
}
359
371
360
372
async open ( _initialDimensions : TerminalDimensions | undefined ) : Promise < void > {
@@ -380,22 +392,29 @@ class CustomBuildTaskTerminal implements Pseudoterminal {
380
392
381
393
private async doBuild ( ) : Promise < any > {
382
394
// Do build.
383
- let command : string = util . resolveVariables ( this . command ) ;
384
- let activeCommand : string = command ;
395
+ let resolvedCommand : string | util . IQuotedString | undefined ;
396
+ if ( util . isString ( this . command ) ) {
397
+ resolvedCommand = util . resolveVariables ( this . command ) ;
398
+ } else {
399
+ resolvedCommand = {
400
+ value : util . resolveVariables ( this . command . value ) ,
401
+ quoting : this . command . quoting
402
+ } ;
403
+ }
385
404
386
405
// Create the exe folder path if it doesn't exist.
387
406
const exePath : string | undefined = util . resolveVariables ( util . findExePathInArgs ( this . args ) ) ;
388
407
util . createDirIfNotExistsSync ( exePath ) ;
389
408
390
409
this . args . forEach ( ( value , index ) => {
391
- value = util . quoteArgument ( util . resolveVariables ( value ) ) ;
392
- activeCommand = activeCommand + " " + value ;
393
- this . args [ index ] = value ;
410
+ if ( util . isString ( value ) ) {
411
+ this . args [ index ] = util . resolveVariables ( value ) ;
412
+ } else {
413
+ value . value = util . resolveVariables ( value . value ) ;
414
+ }
394
415
} ) ;
395
- if ( this . options ) {
396
- this . options . shell = true ;
397
- } else {
398
- this . options = { "shell" : true } ;
416
+ if ( this . options === undefined ) {
417
+ this . options = { } ;
399
418
}
400
419
if ( this . options . cwd ) {
401
420
this . options . cwd = util . resolveVariables ( this . options . cwd . toString ( ) ) ;
@@ -425,15 +444,12 @@ class CustomBuildTaskTerminal implements Pseudoterminal {
425
444
}
426
445
} ;
427
446
428
- if ( os . platform ( ) === 'win32' ) {
429
- command = `cmd /c chcp 65001>nul && ${ command } ` ;
430
- }
431
-
447
+ const activeCommand : string = util . buildShellCommandLine ( resolvedCommand , this . command , this . args ) ;
432
448
this . writeEmitter . fire ( activeCommand + this . endOfLine ) ;
433
449
434
450
let child : cp . ChildProcess | undefined ;
435
451
try {
436
- child = cp . spawn ( command , this . args , this . options ? this . options : { } ) ;
452
+ child = cp . exec ( activeCommand , this . options ) ;
437
453
let error : string = "" ;
438
454
let stdout : string = "" ;
439
455
let stderr : string = "" ;
0 commit comments