diff --git a/Extension/.scripts/generateOptionsSchema.ts b/Extension/.scripts/generateOptionsSchema.ts index 346b21007..237945ed3 100644 --- a/Extension/.scripts/generateOptionsSchema.ts +++ b/Extension/.scripts/generateOptionsSchema.ts @@ -85,8 +85,13 @@ function replaceReferences(definitions: any, objects: any): any { objects[key].anyOf = replaceReferences(definitions, objects[key].anyOf); } - // Recursively replace references if this object has properties. - if (objects[key].hasOwnProperty('type') && objects[key].type === 'object' && objects[key].properties !== null) { + // Handle 'oneOf' with references + if (objects[key].hasOwnProperty('oneOf')) { + objects[key].oneOf = replaceReferences(definitions, objects[key].oneOf); + } + + // Recursively replace references if this schema node has properties. + if (objects[key].hasOwnProperty('properties') && objects[key].properties !== null) { objects[key].properties = replaceReferences(definitions, objects[key].properties); objects[key].properties = updateDefaults(objects[key].properties, objects[key].default); } @@ -117,11 +122,13 @@ function mergeReferences(baseDefinitions: any, additionalDefinitions: any): void export async function main() { const packageJSON: any = JSON.parse(await read(resolve($root, 'package.json'))); const schemaJSON: any = JSON.parse(await read(resolve($root, 'tools/OptionsSchema.json'))); + const taskDefinitionsJSON: any = JSON.parse(await read(resolve($root, 'tools/TaskDefinitionsSchema.json'))); const symbolSettingsJSON: any = JSON.parse(await read(resolve($root, 'tools/VSSymbolSettings.json'))); mergeReferences(schemaJSON.definitions, symbolSettingsJSON.definitions); schemaJSON.definitions = replaceReferences(schemaJSON.definitions, schemaJSON.definitions); + taskDefinitionsJSON.definitions = replaceReferences(taskDefinitionsJSON.definitions, taskDefinitionsJSON.definitions); // Hard Code adding in configurationAttributes launch and attach. // cppdbg @@ -132,6 +139,9 @@ export async function main() { packageJSON.contributes.debuggers[1].configurationAttributes.launch = schemaJSON.definitions.CppvsdbgLaunchOptions; packageJSON.contributes.debuggers[1].configurationAttributes.attach = schemaJSON.definitions.CppvsdbgAttachOptions; + // task definitions + packageJSON.contributes.taskDefinitions = [taskDefinitionsJSON.definitions.CppBuildTaskDefinition]; + let content: string = JSON.stringify(packageJSON, null, 4); // We use '\u200b' (unicode zero-length space character) to break VS Code's URL detection regex for URLs that are examples. This process will diff --git a/Extension/package.json b/Extension/package.json index 9b22073b8..24df79369 100644 --- a/Extension/package.json +++ b/Extension/package.json @@ -529,9 +529,332 @@ } } }, + "problemMatcher": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "%c_cpp.taskDefinitions.problemMatcher.description%" + }, "detail": { "type": "string", "description": "%c_cpp.taskDefinitions.detail.description%" + }, + "windows": { + "type": "object", + "properties": { + "command": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "required": [ + "value", + "quoting" + ], + "properties": { + "value": { + "type": "string", + "description": "%c_cpp.taskDefinitions.args.value.description%" + }, + "quoting": { + "type": "string", + "enum": [ + "escape", + "strong", + "weak" + ], + "enumDescriptions": [ + "%c_cpp.taskDefinitions.args.quoting.escape.description%", + "%c_cpp.taskDefinitions.args.quoting.strong.description%", + "%c_cpp.taskDefinitions.args.quoting.weak.description%" + ], + "default": "strong", + "description": "%c_cpp.taskDefinitions.args.quoting.description%" + } + } + } + ] + }, + "args": { + "type": "array", + "description": "%c_cpp.taskDefinitions.args.description%", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "required": [ + "value", + "quoting" + ], + "properties": { + "value": { + "type": "string", + "description": "%c_cpp.taskDefinitions.args.value.description%" + }, + "quoting": { + "type": "string", + "enum": [ + "escape", + "strong", + "weak" + ], + "enumDescriptions": [ + "%c_cpp.taskDefinitions.args.quoting.escape.description%", + "%c_cpp.taskDefinitions.args.quoting.strong.description%", + "%c_cpp.taskDefinitions.args.quoting.weak.description%" + ], + "default": "strong", + "description": "%c_cpp.taskDefinitions.args.quoting.description%" + } + } + } + ] + } + }, + "options": { + "type": "object", + "description": "%c_cpp.taskDefinitions.options.description%", + "properties": { + "cwd": { + "type": "string", + "description": "%c_cpp.taskDefinitions.options.cwd.description%" + } + } + }, + "problemMatcher": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "%c_cpp.taskDefinitions.problemMatcher.description%" + } + } + }, + "linux": { + "type": "object", + "properties": { + "command": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "required": [ + "value", + "quoting" + ], + "properties": { + "value": { + "type": "string", + "description": "%c_cpp.taskDefinitions.args.value.description%" + }, + "quoting": { + "type": "string", + "enum": [ + "escape", + "strong", + "weak" + ], + "enumDescriptions": [ + "%c_cpp.taskDefinitions.args.quoting.escape.description%", + "%c_cpp.taskDefinitions.args.quoting.strong.description%", + "%c_cpp.taskDefinitions.args.quoting.weak.description%" + ], + "default": "strong", + "description": "%c_cpp.taskDefinitions.args.quoting.description%" + } + } + } + ] + }, + "args": { + "type": "array", + "description": "%c_cpp.taskDefinitions.args.description%", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "required": [ + "value", + "quoting" + ], + "properties": { + "value": { + "type": "string", + "description": "%c_cpp.taskDefinitions.args.value.description%" + }, + "quoting": { + "type": "string", + "enum": [ + "escape", + "strong", + "weak" + ], + "enumDescriptions": [ + "%c_cpp.taskDefinitions.args.quoting.escape.description%", + "%c_cpp.taskDefinitions.args.quoting.strong.description%", + "%c_cpp.taskDefinitions.args.quoting.weak.description%" + ], + "default": "strong", + "description": "%c_cpp.taskDefinitions.args.quoting.description%" + } + } + } + ] + } + }, + "options": { + "type": "object", + "description": "%c_cpp.taskDefinitions.options.description%", + "properties": { + "cwd": { + "type": "string", + "description": "%c_cpp.taskDefinitions.options.cwd.description%" + } + } + }, + "problemMatcher": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "%c_cpp.taskDefinitions.problemMatcher.description%" + } + } + }, + "osx": { + "type": "object", + "properties": { + "command": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "required": [ + "value", + "quoting" + ], + "properties": { + "value": { + "type": "string", + "description": "%c_cpp.taskDefinitions.args.value.description%" + }, + "quoting": { + "type": "string", + "enum": [ + "escape", + "strong", + "weak" + ], + "enumDescriptions": [ + "%c_cpp.taskDefinitions.args.quoting.escape.description%", + "%c_cpp.taskDefinitions.args.quoting.strong.description%", + "%c_cpp.taskDefinitions.args.quoting.weak.description%" + ], + "default": "strong", + "description": "%c_cpp.taskDefinitions.args.quoting.description%" + } + } + } + ] + }, + "args": { + "type": "array", + "description": "%c_cpp.taskDefinitions.args.description%", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "required": [ + "value", + "quoting" + ], + "properties": { + "value": { + "type": "string", + "description": "%c_cpp.taskDefinitions.args.value.description%" + }, + "quoting": { + "type": "string", + "enum": [ + "escape", + "strong", + "weak" + ], + "enumDescriptions": [ + "%c_cpp.taskDefinitions.args.quoting.escape.description%", + "%c_cpp.taskDefinitions.args.quoting.strong.description%", + "%c_cpp.taskDefinitions.args.quoting.weak.description%" + ], + "default": "strong", + "description": "%c_cpp.taskDefinitions.args.quoting.description%" + } + } + } + ] + } + }, + "options": { + "type": "object", + "description": "%c_cpp.taskDefinitions.options.description%", + "properties": { + "cwd": { + "type": "string", + "description": "%c_cpp.taskDefinitions.options.cwd.description%" + } + } + }, + "problemMatcher": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "%c_cpp.taskDefinitions.problemMatcher.description%" + } + } } } } @@ -6943,4 +7266,4 @@ "uuid": "^11.1.1", "undici": "^7.28.0" } -} \ No newline at end of file +} diff --git a/Extension/package.nls.json b/Extension/package.nls.json index 17df9bcdb..68a7266a1 100644 --- a/Extension/package.nls.json +++ b/Extension/package.nls.json @@ -1005,6 +1005,7 @@ "c_cpp.taskDefinitions.args.quoting.weak.description": "Quotes the argument using the shell's weak quote character (e.g. \" under bash).", "c_cpp.taskDefinitions.options.description": "Additional command options.", "c_cpp.taskDefinitions.options.cwd.description": "The current working directory of the executed program or script. If omitted Code's current workspace root is used.", + "c_cpp.taskDefinitions.problemMatcher.description": "One or more problem matchers to use to detect compiler errors and warnings in task output.", "c_cpp.taskDefinitions.detail.description": "Additional details of the task.", "c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.description": "Current and compile-time paths to the same source trees. Files found under the EditorPath are mapped to the CompileTimePath path for breakpoint matching and mapped from CompileTimePath to EditorPath when displaying stacktrace locations.", "c_cpp.debuggers.sourceFileMap.sourceFileMapEntry.editorPath.description": "The path to the source tree the editor will use.", diff --git a/Extension/src/LanguageServer/cppBuildTaskProvider.ts b/Extension/src/LanguageServer/cppBuildTaskProvider.ts index e42b429c6..486e3df64 100644 --- a/Extension/src/LanguageServer/cppBuildTaskProvider.ts +++ b/Extension/src/LanguageServer/cppBuildTaskProvider.ts @@ -24,8 +24,18 @@ export interface CppBuildTaskDefinition extends TaskDefinition { type: string; label: string; // The label appears in tasks.json file. command: string | util.IQuotedString; - args: (string | util.IQuotedString)[]; - options: cp.ExecOptions | cp.SpawnOptions | undefined; + args?: (string | util.IQuotedString)[]; + options?: cp.ExecOptions | undefined; + windows?: CppBuildTaskPlatformOverride; + linux?: CppBuildTaskPlatformOverride; + osx?: CppBuildTaskPlatformOverride; +} + +interface CppBuildTaskPlatformOverride { + command?: string | util.IQuotedString; + args?: (string | util.IQuotedString)[]; + options?: cp.ExecOptions | undefined; + problemMatcher?: string | string[]; } export class CppBuildTask extends Task { @@ -50,7 +60,7 @@ export class CppBuildTaskProvider implements TaskProvider { const execution: ProcessExecution | ShellExecution | CustomExecution | undefined = _task.execution; if (!execution) { const definition: CppBuildTaskDefinition = _task.definition; - _task = this.getTask(definition.command, false, definition.args ? definition.args : [], definition, _task.detail); + _task = this.getTask(definition, _task.detail); return _task; } return undefined; @@ -59,7 +69,7 @@ export class CppBuildTaskProvider implements TaskProvider { public resolveInsiderTask(_task: CppBuildTask): CppBuildTask | undefined { const definition: CppBuildTaskDefinition = _task.definition; definition.label = definition.label.replace(ext.configPrefix, ""); - _task = this.getTask(definition.command, false, definition.args ? definition.args : [], definition, _task.detail); + _task = this.getTask(definition, _task.detail); return _task; } @@ -152,83 +162,118 @@ export class CppBuildTaskProvider implements TaskProvider { return emptyTasks; } - // Create a build task per compiler path + // Create a build task per compiler path. const result: CppBuildTask[] = []; - // Task for valid user compiler path setting + // Task for valid user compiler path setting. if (isCompilerValid && userCompilerPath) { - result.push(this.getTask(userCompilerPath, appendSourceToName, userCompilerPathAndArgs?.allCompilerArgs)); + result.push(this.generateTask(userCompilerPath, appendSourceToName, userCompilerPathAndArgs?.allCompilerArgs)); } - // Tasks for known compiler paths + // Tasks for known compiler paths. if (knownCompilerPaths) { - result.push(...knownCompilerPaths.map(compilerPath => this.getTask(compilerPath, appendSourceToName, undefined))); + result.push(...knownCompilerPaths.map(compilerPath => this.generateTask(compilerPath, appendSourceToName, undefined))); } return result; } - 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) => { + private generateTask(compilerPath: string | util.IQuotedString, appendSourceToName: boolean, compilerArgs?: (string | util.IQuotedString)[]): CppBuildTask { const compilerPathString: string = util.isString(compilerPath) ? compilerPath : compilerPath.value; - const compilerPathBase: string = path.basename(compilerPathString); - const isCl: boolean = compilerPathBase.toLowerCase() === "cl.exe"; - const isClang: boolean = !isCl && compilerPathBase.toLowerCase().includes("clang"); - // Double-quote the command if needed. - const resolvedCompilerPathString: string = isCl ? compilerPathBase : compilerPathString; - let resolvedCompilerPath: string | util.IQuotedString = compilerPath; - if (isCl) { - resolvedCompilerPath = compilerPathBase; - } - - if (!definition) { - const isWindows: boolean = os.platform() === 'win32'; - const taskLabel: string = ((appendSourceToName && !compilerPathBase.startsWith(ext.configPrefix)) ? - ext.configPrefix : "") + compilerPathBase + " " + localize("build.active.file", "build active file"); - const programName: string = util.defaultExePath(); - let args: (string | util.IQuotedString)[] = isCl ? - ['/Zi', '/EHsc', '/nologo', `/Fe${programName}`, '${file}'] : - isClang ? - ['-fcolor-diagnostics', '-fansi-escape-codes', '-g', '${file}', '-o', programName] : - ['-fdiagnostics-color=always', '-g', '${file}', '-o', programName]; - - if (compilerArgs && compilerArgs.length > 0) { - args = args.concat(compilerArgs); - } - const cwd: string = isWindows && !isCl && !process.env.PATH?.includes(path.dirname(compilerPathString)) ? path.dirname(compilerPathString) : "${fileDirname}"; - const options: cp.ExecOptions | cp.SpawnOptions | undefined = { cwd: cwd }; - definition = { - type: CppBuildTaskProvider.CppBuildScriptType, - label: taskLabel, - command: compilerPath, - args: args, - options: options - }; - if (isCl) { - definition.command = compilerPathBase; - } + const compilerName: string = path.basename(compilerPathString); + const isCl: boolean = compilerName.toLowerCase() === "cl.exe"; + const isClang: boolean = !isCl && compilerName.toLowerCase().includes("clang"); + + const isWindows: boolean = os.platform() === 'win32'; + const taskLabel: string = ((appendSourceToName && !compilerName.startsWith(ext.configPrefix)) ? + ext.configPrefix : "") + compilerName + " " + localize("build.active.file", "build active file"); + const programName: string = util.defaultExePath(); + let args: (string | util.IQuotedString)[] = isCl ? + ['/Zi', '/EHsc', '/nologo', `/Fe${programName}`, '${file}'] : + isClang ? + ['-fcolor-diagnostics', '-fansi-escape-codes', '-g', '${file}', '-o', programName] : + ['-fdiagnostics-color=always', '-g', '${file}', '-o', programName]; + + if (compilerArgs && compilerArgs.length > 0) { + args = args.concat(compilerArgs); } + const cwd: string = isWindows && !isCl && !process.env.PATH?.includes(path.dirname(compilerPathString)) ? path.dirname(compilerPathString) : "${fileDirname}"; + const options: cp.ExecOptions | undefined = { cwd: cwd }; + const definition: CppBuildTaskDefinition = { + type: CppBuildTaskProvider.CppBuildScriptType, + label: taskLabel, + command: isCl ? compilerName : compilerPath, + args: args, + options: options + }; + + return this.getTask(definition); + } + + private getTask(definition: CppBuildTaskDefinition, detail?: string): CppBuildTask { + const platformDefinition: CppBuildTaskDefinition = this.applyPlatformOverrides(definition); + const command: string = util.isString(platformDefinition.command) ? platformDefinition.command : platformDefinition.command.value; + const compilerName: string = path.basename(command); + const isCl: boolean = compilerName.toLowerCase() === "cl.exe"; + const isClang: boolean = !isCl && compilerName.toLowerCase().includes("clang"); const editor: TextEditor | undefined = window.activeTextEditor; const folder: WorkspaceFolder | undefined = editor ? workspace.getWorkspaceFolder(editor.document.uri) : undefined; - const taskUsesActiveFile: boolean = definition.args.some(arg => { + const taskUsesActiveFile: boolean = platformDefinition.args?.some(arg => { if (util.isString(arg)) { return arg.indexOf('${file}') >= 0; } return arg.value.indexOf('${file}') >= 0; - }); // Need to check this before ${file} is resolved + }) || false; // Need to check this before ${file} is resolved const scope: WorkspaceFolder | TaskScope = folder ? folder : TaskScope.Workspace; - const task: CppBuildTask = new Task(definition, scope, definition.label, ext.CppSourceStr, - new CustomExecution(async (resolvedDefinition: TaskDefinition): Promise => - // When the task is executed, this callback will run. Here, we setup for running the task. - new CustomBuildTaskTerminal(resolvedCompilerPath, resolvedDefinition.args, resolvedDefinition.options, { taskUsesActiveFile, insertStd: isClang && os.platform() === 'darwin' }) - ), isCl ? '$msCompile' : '$gcc'); + const customExecution: CustomExecution = new CustomExecution(async (resolvedDefinition: TaskDefinition): Promise => { + // When the task is executed, this callback will run. Here, we setup for running the task. + // Apply platform-specific overrides (windows/linux/osx) at execution time so that VS Code + // can still match the task definition by its original shape during the resolve phase. + const effectiveDefinition: CppBuildTaskDefinition = this.applyPlatformOverrides(resolvedDefinition as CppBuildTaskDefinition); + const effectiveArgs: (string | util.IQuotedString)[] = effectiveDefinition.args ? effectiveDefinition.args : []; + return new CustomBuildTaskTerminal( + effectiveDefinition.command, + effectiveArgs, + effectiveDefinition.options, + { taskUsesActiveFile, insertStd: isClang && os.platform() === 'darwin' } + ); + }); + const task: CppBuildTask = new CppBuildTask(definition, scope, definition.label, ext.CppSourceStr, customExecution, platformDefinition.problemMatcher ?? (isCl ? '$msCompile' : '$gcc')); task.group = TaskGroup.Build; - task.detail = detail ? detail : localize("compiler.details", "compiler:") + " " + resolvedCompilerPathString; + task.detail = detail ? detail : localize("compiler.details", "compiler:") + " " + (isCl ? compilerName : command); return task; - }; + } + + private applyPlatformOverrides(definition: CppBuildTaskDefinition): CppBuildTaskDefinition { + const platform: NodeJS.Platform = os.platform(); + let platformOverride: CppBuildTaskPlatformOverride | undefined; + + if (platform === 'win32') { + platformOverride = definition.windows; + } else if (platform === 'linux') { + platformOverride = definition.linux; + } else if (platform === 'darwin') { + platformOverride = definition.osx; + } + + if (!platformOverride) { + return definition; + } + + const mergedDefinition: CppBuildTaskDefinition = { + ...definition, + command: platformOverride.command ?? definition.command, + args: platformOverride.args ?? definition.args, + options: platformOverride.options ?? definition.options, + problemMatcher: platformOverride.problemMatcher ?? definition.problemMatcher + }; + + return mergedDefinition; + } public async getJsonTasks(): Promise { const rawJson: any = await this.getRawTasksJson(); @@ -242,9 +287,13 @@ export class CppBuildTaskProvider implements TaskProvider { label: task.label, command: task.command, args: task.args, - options: task.options + options: task.options, + windows: task.windows, + linux: task.linux, + osx: task.osx, + problemMatcher: task.problemMatcher }; - const cppBuildTask: CppBuildTask = new Task(definition, TaskScope.Workspace, task.label, ext.CppSourceStr); + const cppBuildTask: CppBuildTask = new CppBuildTask(definition, TaskScope.Workspace, task.label, ext.CppSourceStr); cppBuildTask.detail = task.detail; cppBuildTask.existing = true; if (util.isObject(task.group) && task.group.isDefault) { diff --git a/Extension/tools/TaskDefinitionsSchema.json b/Extension/tools/TaskDefinitionsSchema.json new file mode 100644 index 000000000..95da3f2e3 --- /dev/null +++ b/Extension/tools/TaskDefinitionsSchema.json @@ -0,0 +1,138 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VS Code task definitions", + "description": "A json schema for VS Code task definitions contributed by the C/C++ extension", + "type": "object", + "definitions": { + "TaskStringWithQuoting": { + "type": "object", + "required": [ + "value", + "quoting" + ], + "properties": { + "value": { + "type": "string", + "description": "%c_cpp.taskDefinitions.args.value.description%" + }, + "quoting": { + "type": "string", + "enum": [ + "escape", + "strong", + "weak" + ], + "enumDescriptions": [ + "%c_cpp.taskDefinitions.args.quoting.escape.description%", + "%c_cpp.taskDefinitions.args.quoting.strong.description%", + "%c_cpp.taskDefinitions.args.quoting.weak.description%" + ], + "default": "strong", + "description": "%c_cpp.taskDefinitions.args.quoting.description%" + } + } + }, + "TaskStringOrQuotedString": { + "oneOf": [ + { + "type": "string" + }, + { + "$ref": "#/definitions/TaskStringWithQuoting" + } + ] + }, + "CppBuildTaskOptions": { + "type": "object", + "description": "%c_cpp.taskDefinitions.options.description%", + "properties": { + "cwd": { + "type": "string", + "description": "%c_cpp.taskDefinitions.options.cwd.description%" + } + } + }, + "CppBuildTaskProblemMatcher": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "%c_cpp.taskDefinitions.problemMatcher.description%" + }, + "CppBuildTaskPlatformOverride": { + "type": "object", + "properties": { + "command": { + "$ref": "#/definitions/TaskStringOrQuotedString" + }, + "args": { + "type": "array", + "description": "%c_cpp.taskDefinitions.args.description%", + "items": { + "$ref": "#/definitions/TaskStringOrQuotedString" + } + }, + "options": { + "$ref": "#/definitions/CppBuildTaskOptions" + }, + "problemMatcher": { + "$ref": "#/definitions/CppBuildTaskProblemMatcher" + } + } + }, + "CppBuildTaskDefinition": { + "type": "cppbuild", + "required": [ + "command", + "label" + ], + "properties": { + "label": { + "type": "string", + "description": "%c_cpp.taskDefinitions.name.description%" + }, + "command": { + "$ref": "#/definitions/TaskStringOrQuotedString" + }, + "args": { + "type": "array", + "description": "%c_cpp.taskDefinitions.args.description%", + "items": { + "$ref": "#/definitions/TaskStringOrQuotedString" + } + }, + "options": { + "$ref": "#/definitions/CppBuildTaskOptions" + }, + "problemMatcher": { + "$ref": "#/definitions/CppBuildTaskProblemMatcher" + }, + "detail": { + "type": "string", + "description": "%c_cpp.taskDefinitions.detail.description%" + }, + "windows": { + "$ref": "#/definitions/CppBuildTaskPlatformOverride" + }, + "linux": { + "$ref": "#/definitions/CppBuildTaskPlatformOverride" + }, + "osx": { + "$ref": "#/definitions/CppBuildTaskPlatformOverride" + } + } + }, + "TaskDefinitions": [ + { + "$ref": "#/definitions/CppBuildTaskDefinition" + } + ] + } +} \ No newline at end of file