diff --git a/package.json b/package.json index c75adadf1..777c969eb 100644 --- a/package.json +++ b/package.json @@ -3578,6 +3578,12 @@ "description": "%cmake-tools.configuration.cmake.useCMakePresets.description%", "scope": "resource" }, + "cmake.expandCMakePresets": { + "type": "boolean", + "default": true, + "description": "%cmake-tools.configuration.cmake.expandCMakePresets.description%", + "scope": "resource" + }, "cmake.useVsDeveloperEnvironment": { "type": "string", "enum": [ diff --git a/src/cmakeProject.ts b/src/cmakeProject.ts index afea14ba4..331c31dc9 100644 --- a/src/cmakeProject.ts +++ b/src/cmakeProject.ts @@ -196,9 +196,16 @@ export class CMakeProject { * Whether we use presets */ private _useCMakePresets = false; // The default value doesn't matter, value is set when folder is loaded + private _expandCMakePresets = false; // The default value doesn't matter, value is set when folder is loaded + get useCMakePresets(): boolean { return this._useCMakePresets; } + + get expandCMakePresets(): boolean { + return this._expandCMakePresets; + } + async setUseCMakePresets(useCMakePresets: boolean) { if (this.targetName.value === this.initTargetName) { if (useCMakePresets) { @@ -874,7 +881,7 @@ export class CMakeProject { * Dispose the instance */ dispose() { - log.debug(localize({key: 'disposing.extension', comment: ["'CMake Tools' shouldn't be localized"]}, 'Disposing CMake Tools extension')); + log.debug(localize({ key: 'disposing.extension', comment: ["'CMake Tools' shouldn't be localized"] }, 'Disposing CMake Tools extension')); this.disposeEmitter.fire(); this.termCloseSub.dispose(); this.launchTerminals.forEach(term => term.dispose()); @@ -1114,6 +1121,7 @@ export class CMakeProject { this.sourceDir, this.isMultiProjectFolder, this.useCMakePresets, + this.expandCMakePresets, this.activeKit, this.configurePreset, this.buildPreset, @@ -1130,6 +1138,7 @@ export class CMakeProject { this.sourceDir, this.isMultiProjectFolder, this.useCMakePresets, + this.expandCMakePresets, this.activeKit, this.configurePreset, this.buildPreset, @@ -1146,6 +1155,7 @@ export class CMakeProject { this.sourceDir, this.isMultiProjectFolder, this.useCMakePresets, + this.expandCMakePresets, this.activeKit, this.configurePreset, this.buildPreset, @@ -1243,7 +1253,7 @@ export class CMakeProject { * Second phase of two-phase init. Called by `create`. */ private async init(sourceDirectory: string) { - log.debug(localize({key: 'second.phase.init', comment: ["'CMake Tools' shouldn't be localized'"]}, 'Starting CMake Tools second-phase init')); + log.debug(localize({ key: 'second.phase.init', comment: ["'CMake Tools' shouldn't be localized'"] }, 'Starting CMake Tools second-phase init')); await this.setSourceDir(await util.normalizeAndVerifySourceDir(sourceDirectory, CMakeDriver.sourceDirExpansionOptions(this.workspaceContext.folder.uri.fsPath))); this.doStatusChange(this.workspaceContext.config.options); // Restore the debug target @@ -1292,12 +1302,16 @@ export class CMakeProject { return false; } - async doUseCMakePresetsChange(useCMakePresets?: string) { + async doUseCMakePresetsChange(useCMakePresets?: string, expandCMakePresets?: boolean) { if (useCMakePresets === undefined) { useCMakePresets = this.workspaceContext.config.useCMakePresets; } + if (expandCMakePresets === undefined) { + expandCMakePresets = this.workspaceContext.config.expandCMakePresets; + } const usingCMakePresets = useCMakePresets === 'always' ? true : useCMakePresets === 'never' ? false : await this.hasPresetsFiles(); + this._expandCMakePresets = expandCMakePresets; if (usingCMakePresets !== this.wasUsingCMakePresets) { this.wasUsingCMakePresets = usingCMakePresets; await this.setUseCMakePresets(usingCMakePresets); @@ -1327,7 +1341,6 @@ export class CMakeProject { this.onDidOpenTextDocumentListener = undefined; } } - this.onUseCMakePresetsChangedEmitter.fire(usingCMakePresets); } } @@ -2038,7 +2051,7 @@ export class CMakeProject { return drv ? this.tasksBuildCommandDrv(drv) : null; } - private activeBuild: Promise = Promise.resolve({exitCode: 0}); + private activeBuild: Promise = Promise.resolve({ exitCode: 0 }); /** * Implementation of `cmake.build` diff --git a/src/config.ts b/src/config.ts index 1048da7e9..63ee90f7b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -210,6 +210,7 @@ export interface ExtensionConfigurationSettings { touchbar: TouchBarConfig; options: OptionConfig; useCMakePresets: UseCMakePresets; + expandCMakePresets: boolean; useVsDeveloperEnvironment: UseVsDeveloperEnvironment; allowCommentsInPresetsFile: boolean; allowUnsupportedPresetsVersions: boolean; @@ -473,6 +474,9 @@ export class ConfigurationReader implements vscode.Disposable { get useCMakePresets(): UseCMakePresets { return this.configData.useCMakePresets; } + get expandCMakePresets(): boolean { + return this.configData.expandCMakePresets; + } get useVsDeveloperEnvironment(): UseVsDeveloperEnvironment { return this.configData.useVsDeveloperEnvironment; } @@ -659,6 +663,7 @@ export class ConfigurationReader implements vscode.Disposable { touchbar: new vscode.EventEmitter(), options: new vscode.EventEmitter(), useCMakePresets: new vscode.EventEmitter(), + expandCMakePresets: new vscode.EventEmitter(), useVsDeveloperEnvironment: new vscode.EventEmitter(), allowCommentsInPresetsFile: new vscode.EventEmitter(), allowUnsupportedPresetsVersions: new vscode.EventEmitter(), diff --git a/src/drivers/cmakeDriver.ts b/src/drivers/cmakeDriver.ts index 8c4e8c317..d79ff3ecf 100644 --- a/src/drivers/cmakeDriver.ts +++ b/src/drivers/cmakeDriver.ts @@ -37,7 +37,7 @@ import { CMakeBuildRunner } from '@cmt/cmakeBuildRunner'; import { DebuggerInformation } from '@cmt/debug/cmakeDebugger/debuggerConfigureDriver'; import { onBuildSettingsChange, onTestSettingsChange, onPackageSettingsChange } from '@cmt/ui/util'; import { CodeModelKind } from '@cmt/drivers/cmakeFileApi'; -import { CommandResult } from 'vscode-cmake-tools'; +import { CommandResult, EnvironmentWithNull } from 'vscode-cmake-tools'; nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })(); const localize: nls.LocalizeFunc = nls.loadMessageBundle(); @@ -400,11 +400,16 @@ export abstract class CMakeDriver implements vscode.Disposable { private _kitDetect: KitDetect | null = null; private _useCMakePresets: boolean = true; + private _expandPresets: boolean = false; get useCMakePresets(): boolean { return this._useCMakePresets; } + get expandCMakePresets(): boolean { + return this._expandPresets; + } + get configurePresetArchitecture(): string | preset.ValueStrategy | undefined { return this._configurePreset?.architecture; } @@ -1436,7 +1441,7 @@ export abstract class CMakeDriver implements vscode.Disposable { // Cache flags will construct the command line for cmake. const init_cache_flags = await this.generateInitCacheFlags(); // Make sure that we expand the config.configureArgs. Right now, preset args are expanded upon switching to the preset. - return init_cache_flags.concat(preset.configureArgs(configPreset), await Promise.all(this.config.configureArgs.map(async (value) => expand.expandString(value, { ...this.expansionOptions, envOverride: await this.getConfigureEnvironment()})))); + return init_cache_flags.concat(preset.configureArgs(configPreset), await Promise.all(this.config.configureArgs.map(async (value) => expand.expandString(value, { ...this.expansionOptions, envOverride: await this.getConfigureEnvironment() })))); } public async generateConfigArgsFromSettings(extra_args: string[] = [], withoutCmakeSettings: boolean = false): Promise { @@ -1502,8 +1507,14 @@ export abstract class CMakeDriver implements vscode.Disposable { log.debug(localize('no.config.Preset', 'No configure preset selected')); return { exitCode: -3, resultType: ConfigureResultType.NoConfigurePreset }; } - // For now, fields in presets are expanded when the preset is selected - expanded_flags = await this.generateConfigArgsFromPreset(configurePreset); + + if (this.expandCMakePresets) { + log.info(localize('expand.cmake.presets', 'Expanding CMake presets')); + expanded_flags = await this.generateConfigArgsFromPreset(configurePreset); + } else { + log.info(localize('use.preset.name', 'Using preset name {0}', configurePreset.name)); + expanded_flags = [("--preset=" + configurePreset.name)]; + } if (!showCommandOnly && !shouldUseCachedConfiguration && checkConfigureOverridesPresent(this.config)) { log.info(localize('configure.with.overrides', 'NOTE: You are configuring with preset {0}, but there are some overrides being applied from your VS Code settings.', configurePreset.displayName ?? configurePreset.name)); @@ -1915,23 +1926,31 @@ export abstract class CMakeDriver implements vscode.Disposable { // Create a command for a given build preset. async generateBuildCommandFromPreset(buildPreset: preset.BuildPreset, targets?: string[]): Promise { - if (targets && targets.length > 0) { - buildPreset.__targets = targets; - } else { - buildPreset.__targets = buildPreset.targets; - } - const args = preset.buildArgs(buildPreset, this.config.buildArgs, this.config.buildToolArgs); - const initialEnvironment = EnvironmentUtils.create(buildPreset.environment); - const build_env = await this.getCMakeBuildCommandEnvironment(initialEnvironment); - const expanded_args_promises = args.map(async (value: string) => expand.expandString(value, { ...this.expansionOptions, envOverride: build_env })); - const expanded_args = await Promise.all(expanded_args_promises) as string[]; - log.trace(localize('cmake.build.args.are', 'CMake build args are: {0}', JSON.stringify(args))); + let expanded_args: string[] = []; + let build_env: Environment = {}; - if (checkBuildOverridesPresent(this.config)) { - log.info(localize('build.with.overrides', 'NOTE: You are building with preset {0}, but there are some overrides being applied from your VS Code settings.', buildPreset.displayName ?? buildPreset.name)); + if (this.expandCMakePresets) { + if (targets && targets.length > 0) { + buildPreset.__targets = targets; + } else { + buildPreset.__targets = buildPreset.targets; + } + const args = preset.buildArgs(buildPreset, this.config.buildArgs, this.config.buildToolArgs); + const initialEnvironment = EnvironmentUtils.create(buildPreset.environment); + build_env = await this.getCMakeBuildCommandEnvironment(initialEnvironment); + const expanded_args_promises = args.map(async (value: string) => expand.expandString(value, { ...this.expansionOptions, envOverride: build_env })); + expanded_args = await Promise.all(expanded_args_promises) as string[]; + log.trace(localize('cmake.build.args.are', 'CMake build args are: {0}', JSON.stringify(args))); + + if (checkBuildOverridesPresent(this.config)) { + log.info(localize('build.with.overrides', 'NOTE: You are building with preset {0}, but there are some overrides being applied from your VS Code settings.', buildPreset.displayName ?? buildPreset.name)); + } + } else { + expanded_args = ["--build", "--preset=" + buildPreset.name, "-S", this.sourceDir]; + log.trace(localize('cmake.build.args.are', 'CMake build args are: {0}', JSON.stringify(expanded_args))); } - return { command: this.cmake.path, args: expanded_args, build_env}; + return { command: this.cmake.path, args: expanded_args, build_env }; } async generateBuildCommandFromSettings(targets?: string[]): Promise { @@ -2022,6 +2041,10 @@ export abstract class CMakeDriver implements vscode.Disposable { } } else { const exeOpt: proc.ExecutionOptions = { environment: buildcmd.build_env, outputEncoding: outputEnc }; + if (!this.expandCMakePresets) { + exeOpt.cwd = this.sourceDir; + } + this.cmakeBuildRunner.setBuildProcess(this.executeCommand(buildcmd.command, buildcmd.args, consumer, exeOpt)); } const result = await this.cmakeBuildRunner.getResult(); @@ -2062,6 +2085,7 @@ export abstract class CMakeDriver implements vscode.Disposable { abstract get cmakeCacheEntries(): Map; private async _baseInit(useCMakePresets: boolean, + expandCMakePresets: boolean, kit: Kit | null, configurePreset: preset.ConfigurePreset | null, buildPreset: preset.BuildPreset | null, @@ -2070,6 +2094,7 @@ export abstract class CMakeDriver implements vscode.Disposable { workflowPreset: preset.WorkflowPreset | null, preferredGenerators: CMakeGenerator[]) { this._useCMakePresets = useCMakePresets; + this._expandPresets = expandCMakePresets; const initBaseDriverWithPresetLoc = localize("init.driver.using.preset", "Initializing base driver using preset"); const initBaseDriverWithKitLoc = localize("init.driver.using.kit", "Initializing base driver using kit"); log.debug(`${useCMakePresets ? initBaseDriverWithPresetLoc : initBaseDriverWithKitLoc}`); @@ -2105,6 +2130,7 @@ export abstract class CMakeDriver implements vscode.Disposable { */ static async createDerived(inst: T, useCMakePresets: boolean, + expandCMakePresets: boolean, kit: Kit | null, configurePreset: preset.ConfigurePreset | null, buildPreset: preset.BuildPreset | null, @@ -2112,7 +2138,7 @@ export abstract class CMakeDriver implements vscode.Disposable { packagePreset: preset.PackagePreset | null, workflowPreset: preset.WorkflowPreset | null, preferredGenerators: CMakeGenerator[]): Promise { - await inst._baseInit(useCMakePresets, kit, configurePreset, buildPreset, testPreset, packagePreset, workflowPreset, preferredGenerators); + await inst._baseInit(useCMakePresets, expandCMakePresets, kit, configurePreset, buildPreset, testPreset, packagePreset, workflowPreset, preferredGenerators); return inst; } diff --git a/src/drivers/cmakeFileApiDriver.ts b/src/drivers/cmakeFileApiDriver.ts index ee820ac9a..dd28e889d 100644 --- a/src/drivers/cmakeFileApiDriver.ts +++ b/src/drivers/cmakeFileApiDriver.ts @@ -60,6 +60,7 @@ export class CMakeFileApiDriver extends CMakeDriver { sourceDir: string, isMultiProject: boolean, useCMakePresets: boolean, + expandCMakePresets: boolean, kit: Kit | null, configurePreset: ConfigurePreset | null, buildPreset: BuildPreset | null, @@ -72,6 +73,7 @@ export class CMakeFileApiDriver extends CMakeDriver { log.debug(localize('creating.instance.of', 'Creating instance of {0}', "CMakeFileApiDriver")); return this.createDerived(new CMakeFileApiDriver(cmake, config, sourceDir, isMultiProject, workspaceRootPath, preconditionHandler), useCMakePresets, + expandCMakePresets, kit, configurePreset, buildPreset, @@ -214,15 +216,20 @@ export class CMakeFileApiDriver extends CMakeDriver { // Dup args so we can modify them const args = Array.from(args_); - let has_gen = false; - for (const arg of args) { - if (arg.startsWith("-DCMAKE_GENERATOR:STRING=")) { - has_gen = true; + + let has_gen = this.useCMakePresets && !this.expandCMakePresets; + if (!has_gen) { + for (const arg of args) { + if (arg.startsWith("-DCMAKE_GENERATOR:STRING=")) { + has_gen = true; + } } } // -S and -B were introduced in CMake 3.13 and this driver assumes CMake >= 3.15 - args.push("-S", `${util.lightNormalizePath(this.sourceDir)}`); - args.push("-B", `${util.lightNormalizePath(binaryDir)}`); + if (!this.useCMakePresets || this.expandCMakePresets) { + args.push("-S", `${util.lightNormalizePath(this.sourceDir)}`); + args.push("-B", `${util.lightNormalizePath(binaryDir)}`); + } if (!has_gen) { const generator = (configurePreset) ? { @@ -286,9 +293,17 @@ export class CMakeFileApiDriver extends CMakeDriver { log.debug('Invoking CMake', cmake, 'with arguments', JSON.stringify(args)); const env = await this.getConfigureEnvironment(configurePreset, options?.environment); + let cwd = ""; + + if (this.expandCMakePresets) { + cwd = options?.cwd ?? binaryDir; + } else { + cwd = this.sourceDir; + } + const child = this.executeCommand(cmake, args, outputConsumer, { environment: env, - cwd: options?.cwd ?? binaryDir + cwd }); this.configureProcess = child; diff --git a/src/drivers/cmakeLegacyDriver.ts b/src/drivers/cmakeLegacyDriver.ts index 225551418..55b404c55 100644 --- a/src/drivers/cmakeLegacyDriver.ts +++ b/src/drivers/cmakeLegacyDriver.ts @@ -162,6 +162,7 @@ export class CMakeLegacyDriver extends CMakeDriver { sourceDir: string, isMultiProject: boolean, useCMakePresets: boolean, + expandCMakePresets: boolean, kit: Kit | null, configurePreset: ConfigurePreset | null, buildPreset: BuildPreset | null, @@ -174,6 +175,7 @@ export class CMakeLegacyDriver extends CMakeDriver { log.debug(localize('creating.instance.of', 'Creating instance of {0}', "LegacyCMakeDriver")); return this.createDerived(new CMakeLegacyDriver(cmake, config, sourceDir, isMultiProject, workspaceFolder, preconditionHandler), useCMakePresets, + expandCMakePresets, kit, configurePreset, buildPreset, diff --git a/src/drivers/cmakeServerDriver.ts b/src/drivers/cmakeServerDriver.ts index 933dd412c..daa8c59a5 100644 --- a/src/drivers/cmakeServerDriver.ts +++ b/src/drivers/cmakeServerDriver.ts @@ -441,6 +441,7 @@ export class CMakeServerDriver extends CMakeDriver { sourceDir: string, isMultiProject: boolean, useCMakePresets: boolean, + expandCMakePresets: boolean, kit: Kit | null, configurePreset: ConfigurePreset | null, buildPreset: BuildPreset | null, @@ -452,6 +453,7 @@ export class CMakeServerDriver extends CMakeDriver { preferredGenerators: CMakeGenerator[]): Promise { return this.createDerived(new CMakeServerDriver(cmake, config, sourceDir, isMultiProject, workspaceFolder, preconditionHandler), useCMakePresets, + expandCMakePresets, kit, configurePreset, buildPreset, diff --git a/test/unit-tests/config.test.ts b/test/unit-tests/config.test.ts index 1f857eb29..1bd101f40 100644 --- a/test/unit-tests/config.test.ts +++ b/test/unit-tests/config.test.ts @@ -73,6 +73,7 @@ function createConfig(conf: Partial): Configurat statusBarVisibility: "visible" }, useCMakePresets: 'never', + expandCMakePresets: true, useVsDeveloperEnvironment: 'auto', allowCommentsInPresetsFile: false, allowUnsupportedPresetsVersions: false, diff --git a/test/unit-tests/driver/cmakeFileApiDriver.test.ts b/test/unit-tests/driver/cmakeFileApiDriver.test.ts index d7a5ffad8..ab1545be1 100644 --- a/test/unit-tests/driver/cmakeFileApiDriver.test.ts +++ b/test/unit-tests/driver/cmakeFileApiDriver.test.ts @@ -7,7 +7,7 @@ import { makeCodeModelDriverTestsuite } from '@test/unit-tests/driver/driver-cod import { makeDriverTestsuite } from '@test/unit-tests/driver/driver-test'; async function cmakeFileApiDriverFactory(cmake: CMakeExecutable, config: ConfigurationReader, kit: Kit | null, workspaceFolder: string, preconditionHandler: CMakePreconditionProblemSolver, preferredGenerators: CMakeGenerator[]) { - const d: CMakeFileApiDriver = await CMakeFileApiDriver.create(cmake, config, workspaceFolder || "", false, false, kit, null, null, null, null, null, workspaceFolder, preconditionHandler, preferredGenerators); + const d: CMakeFileApiDriver = await CMakeFileApiDriver.create(cmake, config, workspaceFolder || "", false, false, true, kit, null, null, null, null, null, workspaceFolder, preconditionHandler, preferredGenerators); return d; } diff --git a/test/unit-tests/driver/cmakeServerDriver.test.ts b/test/unit-tests/driver/cmakeServerDriver.test.ts index a688098f4..a9db8678b 100644 --- a/test/unit-tests/driver/cmakeServerDriver.test.ts +++ b/test/unit-tests/driver/cmakeServerDriver.test.ts @@ -6,7 +6,7 @@ import { makeCodeModelDriverTestsuite } from '@test/unit-tests/driver/driver-cod import { makeDriverTestsuite } from '@test/unit-tests/driver/driver-test'; async function cmakeServerDriverFactory(cmake: CMakeExecutable, config: ConfigurationReader, kit: Kit | null, workspaceFolder: string, preconditionHandler: CMakePreconditionProblemSolver, preferredGenerators: CMakeGenerator[]) { - const d: CMakeServerDriver = await CMakeServerDriver.create(cmake, config, workspaceFolder || "", false, false, kit, null, null, null, null, null, workspaceFolder, preconditionHandler, preferredGenerators); + const d: CMakeServerDriver = await CMakeServerDriver.create(cmake, config, workspaceFolder || "", false, false, true, kit, null, null, null, null, null, workspaceFolder, preconditionHandler, preferredGenerators); return d; }