Allow overriding of CMakePresets cache variables and arguments (#3537)

* Update the already available settings to use in presets.

Turns out, we already have configure, build, buildTool, and test
args/envs that can override. I modified the code to use these in
presets. Also, I added a small sentence to the settings descriptions to
notify users that when using CMake Presets, they are designed for
overrides, not general configuration.

* pending further discussion, use general environment for all

* add temporary override string for presets to environment setting description

* don't remove configureSettings

* add text to specify that configureSettings isn't for presets scenario

* Add tentative treeview UI and output message for configure

Still need to do build/test/etc, and likely improve the strings
themselves.

* add output lines, improvement on the string to come, testing for location

* don't output message when we're using cache

* add handlers that update the nodes when a test or build setting is modified

* slight refactor and add * to status bar

* add button that only appears when overrides present that allows opening those settings

* share some code

* fix localize calls

* update tsconfig.json

* update eslint

* slightly reword the settings

* fix buildTool args

* avoid duplication

* ensure we only return -3 when testPreset isn't defined

* fix imports

* changelog and docs

* refactor to avoid circular dependency

* missed one

* fix imports
This commit is contained in:
Garrett Campbell 2024-01-19 15:52:13 -05:00 коммит произвёл GitHub
Родитель 0c3de560bd
Коммит 0e48ef9867
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
18 изменённых файлов: 349 добавлений и 77 удалений

Просмотреть файл

@ -92,7 +92,7 @@ module.exports = {
"no-trailing-spaces": "error",
"no-undef-init": "error",
"no-unsafe-finally": "error",
"no-unused-expressions": "error",
"no-unused-expressions": "off",
"no-unused-labels": "error",
"no-var": "error",
"one-var": [

Просмотреть файл

@ -10,6 +10,7 @@ Improvements:
- Improve when the "Configure with Debugger" popup appears and allow for "Do Not Show Again". [#3343](https://github.com/microsoft/vscode-cmake-tools/issues/3343)
- Add option to disable "Not all open documents were saved" popup. [#2889](https://github.com/microsoft/vscode-cmake-tools/issues/2889)
- Allow overriding of CMakePresets cache variables and arguments [#1836](https://github.com/microsoft/vscode-cmake-tools/issues/1836)
Bug Fixes:

Просмотреть файл

@ -223,7 +223,7 @@ CMake Tools supports command substitution for launch commands when `CMakePresets
`CMakePresets.json` should be the source of truth for all settings related to configure, build, and test. This eliminates behavior specific to Visual Studio Code and ensures that your CMake and CTest invocations can be reproduced from the command line.
The following settings in `settings.json` either duplicate options in `CMakePresets.json` or no longer apply. These settings will be ignored when `CMakePresets.json` integration is enabled. Ignored settings will be logged to the Output Window when you run **CMake: Configure**.
The following settings in `settings.json` either duplicate options in `CMakePresets.json` or no longer apply. These settings will be ignored when `CMakePresets.json` integration is enabled.
| Ignored setting in `settings.json` | `CMakePresets.json` equivalent |
|--|--|
@ -231,7 +231,6 @@ The following settings in `settings.json` either duplicate options in `CMakePres
| `cmake.buildDirectory` | `configurePresets.binaryDir` |
| `cmake.buildEnvironment` | `buildPresets.environment` |
| `cmake.buildToolsArgs` | `buildPresets.nativeToolOptions` |
| `cmake.cmakePath` | `configurePresets.cmakeExecutable` |
| `cmake.configureArgs` | Various options in `configurePreset` |
| `cmake.configureEnvironment` | `configurePresets.environment` |
| `cmake.configureSettings` | `configurePresets.cacheVariables` |
@ -249,6 +248,19 @@ The following settings in `settings.json` either duplicate options in `CMakePres
| `cmake.testEnvironment` | `testPresets.environment` |
| `cmake.toolset` | `configurePresets.toolset` |
## Settings that can be used to override CMakePresets.json settings for temporary testing
The following settings can be used temporarily when CMakePresets integration is enabled.
| Setting in `settings.json` | `CMakePresets.json` equivalent |
|--|--|
| `cmake.buildArgs` | Various options in `buildPreset` |
| `cmake.buildEnvironment` | `buildPresets.environment` |
| `cmake.buildToolsArgs` | `buildPresets.nativeToolOptions` |
| `cmake.configureArgs` | Various options in `configurePreset` |
| `cmake.configureEnvironment` | `configurePresets.environment` |
| `cmake.testEnvironment` | `testPresets.environment` |
## Unsupported commands
The following commands are not supported when `CMakePresets.json` integration is enabled:

Просмотреть файл

@ -92,6 +92,13 @@
"when": "cmake:enableFullFeatureSet && useCMakePresets",
"category": "CMake"
},
{
"command": "cmake.projectStatus.viewConfigureSettings",
"title": "%cmake-tools.command.cmake.viewConfigureSettings.title%",
"when": "cmake:enabelFullFeatureSet && useCMakePresets",
"category": "CMake",
"icon": "$(settings-gear)"
},
{
"command": "cmake.projectStatus.selectConfigurePreset",
"title": "%cmake-tools.command.cmake.selectConfigurePreset.title%",
@ -105,6 +112,13 @@
"when": "cmake:enableFullFeatureSet && useCMakePresets",
"category": "CMake"
},
{
"command": "cmake.projectStatus.viewBuildSettings",
"title": "%cmake-tools.command.cmake.viewBuildSettings.title%",
"when": "cmake:enableFullFeatureSet && useCMakePresets",
"category": "CMake",
"icon": "$(settings-gear)"
},
{
"command": "cmake.projectStatus.selectBuildPreset",
"title": "%cmake-tools.command.cmake.selectBuildPreset.title%",
@ -112,6 +126,13 @@
"category": "CMake",
"icon": "$(edit)"
},
{
"command": "cmake.projectStatus.viewTestSettings",
"title": "%cmake-tools.command.cmake.viewTestSettings.title%",
"when": "cmake:enableFullFeatureSet && useCMakePresets",
"category": "CMake",
"icon": "$(settings-gear)"
},
{
"command": "cmake.selectTestPreset",
"title": "%cmake-tools.command.cmake.selectTestPreset.title%",
@ -1304,10 +1325,18 @@
"command": "cmake.projectStatus.selectConfigurePreset",
"when": "never"
},
{
"command": "cmake.projectStatus.viewConfigureSettings",
"when": "never"
},
{
"command": "cmake.projectStatus.build",
"when": "never"
},
{
"command": "cmake.projectStatus.viewBuildSettings",
"when": "never"
},
{
"command": "cmake.projectStatus.setDefaultTarget",
"when": "never"
@ -1316,6 +1345,10 @@
"command": "cmake.projectStatus.selectBuildPreset",
"when": "never"
},
{
"command": "cmake.projectStatus.viewTestSettings",
"when": "never"
},
{
"command": "cmake.projectStatus.ctest",
"when": "never"
@ -1451,7 +1484,12 @@
},
{
"command": "cmake.projectStatus.selectConfigurePreset",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem == 'configPreset'",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem =~ /configPreset/",
"group": "inline"
},
{
"command": "cmake.projectStatus.viewConfigureSettings",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem == 'configPreset - overrides present'",
"group": "inline"
},
{
@ -1466,9 +1504,14 @@
},
{
"command": "cmake.projectStatus.selectBuildPreset",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem == 'buildPreset'",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem =~ /buildPreset/",
"group": "inline"
},
{
"command": "cmake.projectStatus.viewBuildSettings",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem == 'buildPreset - overrides present'",
"group": "inline"
},
{
"command": "cmake.projectStatus.ctest",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem == 'test'",
@ -1481,9 +1524,14 @@
},
{
"command": "cmake.projectStatus.selectTestPreset",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem == 'testPreset'",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem =~ /testPreset/",
"group": "inline"
},
{
"command": "cmake.projectStatus.viewTestSettings",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem == 'testPreset - overrides present'",
"group": "inline"
},
{
"command": "cmake.projectStatus.debugTarget",
"when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem == 'debug'",

Просмотреть файл

@ -4,8 +4,11 @@
"cmake-tools.command.cmake.addBuildPreset.title": "Add Build Preset",
"cmake-tools.command.cmake.addTestPreset.title": "Add Test Preset",
"cmake-tools.command.cmake.selectConfigurePreset.title": "Select Configure Preset",
"cmake-tools.command.cmake.viewConfigureSettings.title": "View the settings overriding your Configure Preset",
"cmake-tools.command.cmake.selectBuildPreset.title": "Select Build Preset",
"cmake-tools.command.cmake.viewBuildSettings.title": "View the settings overriding your Build Preset",
"cmake-tools.command.cmake.selectTestPreset.title": "Select Test Preset",
"cmake-tools.command.cmake.viewTestSettings.title": "View the settings overriding your Test Preset",
"cmake-tools.command.cmake.viewLog.title": "Open the CMake Tools Log File",
"cmake-tools.command.cmake.logDiagnostics.title": "Log Diagnostics",
"cmake-tools.command.cmake.editKits.title": "Edit User-Local CMake Kits",
@ -74,7 +77,7 @@
"cmake-tools.configuration.cmake.saveBeforeBuild.description": "Save open files before building.",
"cmake-tools.configuration.cmake.buildBeforeRun.description": "Build the target before running it.",
"cmake-tools.configuration.cmake.clearOutputBeforeBuild.description": "Clear build output before each build.",
"cmake-tools.configuration.cmake.configureSettings.description": "CMake variables to set on the command line.",
"cmake-tools.configuration.cmake.configureSettings.description": "CMake variables to set on the command line. This setting is specific to kits and will not be used for CMake Presets.",
"cmake-tools.configuration.cmake.cacheInit.string.description": "Path to a cache-initializing CMake file.",
"cmake-tools.configuration.cmake.cacheInit.array.description": "List of cache initializer files.",
"cmake-tools.configuration.cmake.cacheInit.array.string.description": "A cache initializing CMake file.",
@ -83,9 +86,9 @@
"cmake-tools.configuration.cmake.generator.description": "The CMake generator to use.",
"cmake-tools.configuration.cmake.toolset.description": "The CMake toolset to use when configuring.",
"cmake-tools.configuration.cmake.platform.description": "The CMake platform to use when configuring.",
"cmake-tools.configuration.cmake.configureArgs.description": "Additional arguments to pass to CMake when configuring.",
"cmake-tools.configuration.cmake.buildArgs.description": "Additional arguments to pass to CMake when building.",
"cmake-tools.configuration.cmake.buildToolArgs.description": "Additional arguments to pass to the underlying build tool when building.",
"cmake-tools.configuration.cmake.configureArgs.description": "Additional arguments to pass to CMake when configuring. When using CMake Presets, these arguments are temporarily appended to the arguments provided by the active configure preset.",
"cmake-tools.configuration.cmake.buildArgs.description": "Additional arguments to pass to CMake when building. When using CMake Presets, these arguments are temporarily appended to the arguments provided by the active build preset.",
"cmake-tools.configuration.cmake.buildToolArgs.description": "Additional arguments to pass to the underlying build tool when building. When using CMake Presets, these arguments are temporarily appended to the arguments provided by the active build preset to invoke the build tool.",
"cmake-tools.configuration.cmake.parallelJobs.description": "The number of parallel build jobs. Use zero to automatically detect the number of CPUs. Setting this to 1 will omit the parallelism flag (-j) from the underlying build command, which has a generator-dependent effect on build parallelism.",
"cmake-tools.configuration.cmake.ctestPath.description": "Path to CTest executable. If null, will be inferred from cmake.cmakePath (recommended to leave null).",
"cmake-tools.configuration.cmake.ctest.parallelJobs.markdownDescription": {
@ -136,13 +139,13 @@
"cmake-tools.configuration.cmake.defaultVariants.buildType.release.long": "Optimize for speed - exclude debug information.",
"cmake-tools.configuration.cmake.defaultVariants.buildType.minsize.long": "Optimize for smallest binary size - exclude debug information.",
"cmake-tools.configuration.cmake.defaultVariants.buildType.reldeb.long": "Optimize for speed - include debug information.",
"cmake-tools.configuration.cmake.ctestArgs.description": "Arguments to pass to CTest.",
"cmake-tools.configuration.cmake.ctestArgs.description": "Additional arguments to pass to CTest. When using CMake Presets, these arguments are temporarily added to the arguments provided by the active test preset.",
"cmake-tools.configuration.cmake.ctestDefaultArgs.description": "Arguments passed by default to CTest.",
"cmake-tools.configuration.cmake.environment.description": "Environment variables to set when running CMake commands.",
"cmake-tools.configuration.cmake.environment.description": "Environment variables to set when running CMake commands. When using CMake Presets, these are temporarily added to the environment used for CMake commands.",
"cmake-tools.configuration.cmake.environment.additionalProperties.description": "Value for the environment variable.",
"cmake-tools.configuration.cmake.configureEnvironment.description": "Environment variables to pass to CMake during configure.",
"cmake-tools.configuration.cmake.buildEnvironment.description": "Environment variables to pass to CMake during build.",
"cmake-tools.configuration.cmake.testEnvironment.description": "Environment variables to pass to CTest.",
"cmake-tools.configuration.cmake.configureEnvironment.description": "Environment variables to pass to CMake during configure. When using CMake Presets, these are temporarily added to the environment provided by the active configure preset.",
"cmake-tools.configuration.cmake.buildEnvironment.description": "Environment variables to pass to CMake during build. When using CMake Presets, these are temporarily added to the environment provided by the active build preset.",
"cmake-tools.configuration.cmake.testEnvironment.description": "Environment variables to pass to CTest. When using CMake Presets, these are temporarily added to the environment provided by the active test preset.",
"cmake-tools.configuration.cmake.mingwSearchDirs.description": "Directories where MinGW may be installed.",
"cmake-tools.configuration.cmake.additionalCompilerSearchDirs.description": "Additional directories to search for compilers.",
"cmake-tools.configuration.cmake.searchDirs.items.description": "Path to a directory.",

Просмотреть файл

@ -40,7 +40,7 @@ import { VariantManager } from './variant';
import * as nls from 'vscode-nls';
import { ConfigurationWebview } from './cacheView';
import { enableFullFeatureSet, extensionManager, updateFullFeatureSet } from './extension';
import { CMakeCommunicationMode, ConfigurationReader, OptionConfig, UseCMakePresets } from './config';
import { CMakeCommunicationMode, ConfigurationReader, OptionConfig, UseCMakePresets, checkConfigureOverridesPresent } from './config';
import * as preset from '@cmt/preset';
import * as util from '@cmt/util';
import { Environment, EnvironmentUtils } from './environmentVariables';
@ -2348,6 +2348,10 @@ export class CMakeProject {
// Add environment variables from ConfigureEnvironment.
const configureEnv = await drv?.getConfigureEnvironment();
if ((drv?.useCMakePresets ?? false) && (checkConfigureOverridesPresent(this.workspaceContext.config) ?? false)) {
log.info(localize('launch.with.overrides', `NOTE: You are launching a target and there are some environment overrides being applied from your VS Code settings.`));
}
return EnvironmentUtils.merge([env, configureEnv]);
}

Просмотреть файл

@ -604,3 +604,32 @@ const activeChangeEvents: PromiseTracker = new PromiseTracker();
export function getSettingsChangePromise(): Promise<any[]> {
return activeChangeEvents.getAwaiter();
}
export function checkConfigureOverridesPresent(config: ConfigurationReader): boolean {
if (config.configureArgs.length > 0 || Object.values(config.configureEnvironment).length > 0 || checkGeneralEnvironmentOverridesPresent(config)) {
return true;
}
return false;
}
export function checkBuildOverridesPresent(config: ConfigurationReader): boolean {
if (config.buildArgs.length > 0 || config.buildToolArgs.length > 0
|| Object.values(config.buildEnvironment).length > 0 || checkGeneralEnvironmentOverridesPresent(config)) {
return true;
}
return false;
}
export function checkTestOverridesPresent(config: ConfigurationReader): boolean {
if (Object.values(config.testEnvironment).length > 0 || config.ctestArgs.length > 0 || checkGeneralEnvironmentOverridesPresent(config)) {
return true;
}
return false;
}
export function checkGeneralEnvironmentOverridesPresent(config: ConfigurationReader): boolean {
return Object.values(config.environment).length > 0;
}

Просмотреть файл

@ -247,29 +247,29 @@ export class CTestDriver implements vscode.Disposable {
private async getCTestArgs(driver: CMakeDriver, customizedTask: boolean = false, testPreset?: TestPreset): Promise<string[] | undefined> {
let ctestArgs: string[];
const opts = driver.expansionOptions;
const initialArgs = await Promise.all(this.ws.config.ctestDefaultArgs.map(async (value) => expandString(value, driver.expansionOptions)));
const additionalArgs = await Promise.all(this.ws.config.ctestArgs.map(async (value) => expandString(value, driver.expansionOptions)));
ctestArgs = initialArgs.slice(0);
if (customizedTask && testPreset) {
ctestArgs = ['-T', 'test'].concat(testArgs(testPreset));
ctestArgs = ctestArgs.concat(testArgs(testPreset));
} else if (!customizedTask && driver.useCMakePresets) {
if (!driver.testPreset) {
// Test explorer doesn't handle errors well, so we need to deal with them ourselves
return undefined;
}
// Add a few more args so we can show the result in status bar
ctestArgs = ['-T', 'test'].concat(testArgs(driver.testPreset));
ctestArgs = ctestArgs.concat(testArgs(driver.testPreset));
} else {
const configuration = driver.currentBuildType;
const opts = driver.expansionOptions;
const jobs = await expandString(this.ws.config.numCTestJobs, opts);
const defaultArgs = [];
for (const value of this.ws.config.ctestDefaultArgs) {
defaultArgs.push(await expandString(value, opts));
}
const args = [];
for (const value of this.ws.config.ctestArgs) {
args.push(await expandString(value, opts));
}
ctestArgs = [`-j${jobs}`, '-C', configuration].concat(defaultArgs, args);
ctestArgs = [`-j${jobs}`, '-C', configuration].concat(ctestArgs);
}
ctestArgs = ctestArgs.concat(additionalArgs);
return ctestArgs;
}
@ -301,29 +301,11 @@ export class CTestDriver implements vscode.Disposable {
return -2;
}
let ctestArgs: string[];
if (customizedTask && testPreset) {
ctestArgs = ['-T', 'test'].concat(testArgs(testPreset));
} else if (!customizedTask && driver.useCMakePresets) {
if (!driver.testPreset) {
log.error(localize('test.preset.not.set', 'Test preset is not set'));
return -3;
}
// Add a few more args so we can show the result in status bar
ctestArgs = ['-T', 'test'].concat(testArgs(driver.testPreset));
} else {
const configuration = driver.currentBuildType;
const opts = driver.expansionOptions;
const jobs = await expandString(this.ws.config.numCTestJobs, opts);
const defaultArgs = [];
for (const value of this.ws.config.ctestDefaultArgs) {
defaultArgs.push(await expandString(value, opts));
}
const args = [];
for (const value of this.ws.config.ctestArgs) {
args.push(await expandString(value, opts));
}
ctestArgs = [`-j${jobs}`, '-C', configuration].concat(defaultArgs, args);
const ctestArgs = await this.getCTestArgs(driver, customizedTask, testPreset);
if (!driver.testPreset) {
log.error(localize('test.preset.not.set', 'Test preset is not set'));
return -3;
}
const child = driver.executeCommand(

Просмотреть файл

@ -9,7 +9,7 @@ import { CMakeExecutable } from '@cmt/cmake/cmakeExecutable';
import * as codepages from '@cmt/codePageTable';
import { ConfigureTrigger, DiagnosticsConfiguration } from "@cmt/cmakeProject";
import { CompileCommand } from '@cmt/compilationDatabase';
import { ConfigurationReader, defaultNumJobs } from '@cmt/config';
import { ConfigurationReader, checkBuildOverridesPresent, checkConfigureOverridesPresent, checkTestOverridesPresent, defaultNumJobs } from '@cmt/config';
import { CMakeBuildConsumer, CompileOutputConsumer } from '@cmt/diagnostics/build';
import { CMakeOutputConsumer } from '@cmt/diagnostics/cmake';
import { RawDiagnosticParser } from '@cmt/diagnostics/util';
@ -34,7 +34,7 @@ import { getValue } from '@cmt/preset';
import { CacheEntry } from '@cmt/cache';
import { CMakeBuildRunner } from '@cmt/cmakeBuildRunner';
import { DebuggerInformation } from '@cmt/debug/debuggerConfigureDriver';
import { onBuildSettingsChange, onTestSettingsChange } from '@cmt/ui/util';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@ -244,7 +244,7 @@ export abstract class CMakeDriver implements vscode.Disposable {
for (const term of this._compileTerms.values()) {
term.dispose();
}
for (const sub of [this._settingsSub, this._argsSub, this._envSub]) {
for (const sub of [this._settingsSub, this._argsSub, this._envSub, this._buildArgsSub, this._buildEnvSub, this._testArgsSub, this._testEnvSub, this._generalEnvSub]) {
sub.dispose();
}
rollbar.invokeAsync(localize('async.disposing.cmake.driver', 'Async disposing CMake driver'), () => this.asyncDispose());
@ -276,6 +276,8 @@ export abstract class CMakeDriver implements vscode.Disposable {
let envs;
if (this.useCMakePresets) {
envs = EnvironmentUtils.create(configurePreset ? configurePreset.environment : this._configurePreset?.environment);
envs = EnvironmentUtils.merge([envs, await this.computeExpandedEnvironment(this.config.environment, envs)]);
envs = EnvironmentUtils.merge([envs, await this.computeExpandedEnvironment(this.config.configureEnvironment, envs)]);
} else {
envs = this._kitEnvironmentVariables;
/* NOTE: By mergeEnvironment one by one to enable expanding self containd variable such as PATH properly */
@ -295,7 +297,10 @@ export abstract class CMakeDriver implements vscode.Disposable {
*/
async getCMakeBuildCommandEnvironment(in_env?: Environment): Promise<Environment> {
if (this.useCMakePresets) {
return EnvironmentUtils.merge([in_env, this._buildPreset?.environment]);
let envs = EnvironmentUtils.merge([in_env, this._buildPreset?.environment]);
envs = EnvironmentUtils.merge([envs, await this.computeExpandedEnvironment(this.config.environment, envs)]);
envs = EnvironmentUtils.merge([envs, await this.computeExpandedEnvironment(this.config.buildEnvironment, envs)]);
return envs;
} else {
let envs = EnvironmentUtils.merge([in_env, this._kitEnvironmentVariables]);
envs = EnvironmentUtils.merge([envs, await this.computeExpandedEnvironment(this.config.environment, envs)]);
@ -310,7 +315,15 @@ export abstract class CMakeDriver implements vscode.Disposable {
*/
async getCTestCommandEnvironment(): Promise<Environment> {
if (this.useCMakePresets) {
return EnvironmentUtils.create(this._testPreset?.environment);
let envs = EnvironmentUtils.create(this._testPreset?.environment);
envs = EnvironmentUtils.merge([envs, await this.computeExpandedEnvironment(this.config.environment, envs)]);
envs = EnvironmentUtils.merge([envs, await this.computeExpandedEnvironment(this.config.testEnvironment, envs)]);
if (this.useCMakePresets && this.testPreset !== null && checkTestOverridesPresent(this.config)) {
log.info(localize('test.with.overrides', 'NOTE: You are testing with preset {0}, but there are some overrides being applied from your VS Code settings.', this.testPreset.displayName ?? this.testPreset.name));
}
return envs;
} else {
let envs = this._kitEnvironmentVariables;
envs = EnvironmentUtils.merge([envs, await this.computeExpandedEnvironment(this.config.environment, envs)]);
@ -453,6 +466,11 @@ export abstract class CMakeDriver implements vscode.Disposable {
*/
async runCompileCommand(cmd: CompileCommand): Promise<vscode.Terminal> {
const env = await this.getCMakeBuildCommandEnvironment();
if (this.useCMakePresets && this._buildPreset && checkBuildOverridesPresent(this.config)) {
log.info(localize('compile.with.overrides', 'NOTE: You are compiling with preset {0}, but there are some overrides being applied from your VS Code settings.', this._buildPreset.displayName ?? this._buildPreset.name));
}
const key = `${cmd.directory}${JSON.stringify(env)}`;
let existing = this._compileTerms.get(key);
if (existing && this.config.clearOutputBeforeBuild) {
@ -1282,10 +1300,11 @@ export abstract class CMakeDriver implements vscode.Disposable {
true : false;
}
public generateConfigArgsFromPreset(configPreset: preset.ConfigurePreset): string[] {
public async generateConfigArgsFromPreset(configPreset: preset.ConfigurePreset): Promise<string[]> {
// Cache flags will construct the command line for cmake.
const init_cache_flags = this.generateInitCacheFlags();
return init_cache_flags.concat(preset.configureArgs(configPreset));
// 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()}))));
}
public async generateConfigArgsFromSettings(extra_args: string[] = [], withoutCmakeSettings: boolean = false): Promise<string[]> {
@ -1349,7 +1368,11 @@ export abstract class CMakeDriver implements vscode.Disposable {
return { result: -3, resultType: ConfigureResultType.NoConfigurePreset };
}
// For now, fields in presets are expanded when the preset is selected
expanded_flags = this.generateConfigArgsFromPreset(configurePreset);
expanded_flags = await this.generateConfigArgsFromPreset(configurePreset);
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));
}
} else {
expanded_flags = await this.generateConfigArgsFromSettings(extra_args, withoutCmakeSettings);
}
@ -1683,14 +1706,31 @@ export abstract class CMakeDriver implements vscode.Disposable {
return true;
}
protected abstract doConfigureSettingsChange(): void;
protected abstract doConfigureSettingsChange(): Promise<void>;
/**
/**g
* Subscribe to changes that affect the CMake configuration
*/
private readonly _settingsSub = this.config.onChange('configureSettings', () => this.doConfigureSettingsChange());
private readonly _argsSub = this.config.onChange('configureArgs', () => this.doConfigureSettingsChange());
private readonly _envSub = this.config.onChange('configureEnvironment', () => this.doConfigureSettingsChange());
private readonly _settingsSub = this.config.onChange('configureSettings', async () => this.doConfigureSettingsChange());
private readonly _argsSub = this.config.onChange('configureArgs', async () => this.doConfigureSettingsChange());
private readonly _envSub = this.config.onChange('configureEnvironment', async () => this.doConfigureSettingsChange());
private readonly _buildArgsSub = this.config.onChange('buildArgs', async () => {
await onBuildSettingsChange();
});
private readonly _buildEnvSub = this.config.onChange('buildEnvironment', async () => {
await onBuildSettingsChange();
});
private readonly _testArgsSub = this.config.onChange('ctestArgs', async () => {
await onTestSettingsChange();
});
private readonly _testEnvSub = this.config.onChange('testEnvironment', async () => {
await onTestSettingsChange();
});
private readonly _generalEnvSub = this.config.onChange('environment', async () => {
await this.doConfigureSettingsChange();
await onBuildSettingsChange();
await onTestSettingsChange();
});
private cmakeBuildRunner: CMakeBuildRunner = new CMakeBuildRunner();
protected configureProcess: proc.Subprocess | null = null;
@ -1714,9 +1754,18 @@ export abstract class CMakeDriver implements vscode.Disposable {
} else {
buildPreset.__targets = buildPreset.targets;
}
const args = preset.buildArgs(buildPreset);
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)));
return { command: this.cmake.path, args, build_env: EnvironmentUtils.create(buildPreset.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));
}
return { command: this.cmake.path, args: expanded_args, build_env};
}
async generateBuildCommandFromSettings(targets?: string[]): Promise<proc.BuildCommand | null> {

Просмотреть файл

@ -32,6 +32,7 @@ import { DebuggerInformation } from '@cmt/debug/debuggerConfigureDriver';
import { CMakeOutputConsumer, StateMessage } from '@cmt/diagnostics/cmake';
import { ConfigureTrigger } from '@cmt/cmakeProject';
import { logCMakeDebuggerTelemetry } from '@cmt/debug/cmakeDebuggerTelemetry';
import { onConfigureSettingsChange } from '@cmt/ui/util';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@ -154,8 +155,9 @@ export class CMakeFileApiDriver extends CMakeDriver {
});
}
doConfigureSettingsChange() {
async doConfigureSettingsChange(): Promise<void> {
this._needsReconfigure = true;
await onConfigureSettingsChange();
}
async checkNeedsReconfigure(): Promise<boolean> {
return this._needsReconfigure;

Просмотреть файл

@ -19,6 +19,7 @@ import * as nls from 'vscode-nls';
import { BuildPreset, ConfigurePreset, getValue, TestPreset } from '@cmt/preset';
import { CodeModelContent } from './codeModel';
import { ConfigureTrigger } from '@cmt/cmakeProject';
import { onConfigureSettingsChange } from '@cmt/ui/util';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@ -43,8 +44,9 @@ export class CMakeLegacyDriver extends CMakeDriver {
}
private _needsReconfigure = true;
doConfigureSettingsChange() {
async doConfigureSettingsChange(): Promise<void> {
this._needsReconfigure = true;
await onConfigureSettingsChange();
}
async checkNeedsReconfigure(): Promise<boolean> {
return this._needsReconfigure;

Просмотреть файл

@ -26,6 +26,7 @@ import * as nls from 'vscode-nls';
import { BuildPreset, ConfigurePreset, TestPreset } from '@cmt/preset';
import { CodeModelConfiguration, CodeModelContent, CodeModelFileGroup, CodeModelProject, CodeModelTarget } from '@cmt/drivers/codeModel';
import { ConfigureTrigger } from '@cmt/cmakeProject';
import { onConfigureSettingsChange } from '@cmt/ui/util';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@ -307,8 +308,9 @@ export class CMakeServerDriver extends CMakeDriver {
* Track if the user changes the settings of the configure via settings.json
*/
private _hadConfigurationChanged = true;
protected doConfigureSettingsChange() {
protected async doConfigureSettingsChange(): Promise<void> {
this._hadConfigurationChanged = true;
await onConfigureSettingsChange();
}
async checkNeedsReconfigure(): Promise<boolean> {

Просмотреть файл

@ -1714,6 +1714,10 @@ export class ExtensionManager implements vscode.Disposable {
return presetSelected;
}
viewConfigureSettings(): void {
void vscode.commands.executeCommand('workbench.action.openSettings', '@id:cmake.configureArgs, @id:cmake.configureEnvironment, @id:cmake.environment');
}
/**
* Show UI to allow the user to select an active build preset
*/
@ -1739,6 +1743,10 @@ export class ExtensionManager implements vscode.Disposable {
return presetSelected;
}
viewBuildSettings(): void {
void vscode.commands.executeCommand('workbench.action.openSettings', '@id:cmake.buildArgs, @id:cmake.buildToolArgs @id:cmake.buildEnvironment @id:cmake.environment');
}
/**
* Show UI to allow the user to select an active test preset
*/
@ -1764,6 +1772,10 @@ export class ExtensionManager implements vscode.Disposable {
return presetSelected;
}
viewTestSettings(): void {
void vscode.commands.executeCommand('workbench.action.openSettings', '@id:cmake.ctestArgs, @id:cmake.testEnvironment, @id:cmake.environment');
}
public api: CMakeToolsApiImpl;
get onBuildTargetChanged() {
@ -1843,8 +1855,11 @@ async function setup(context: vscode.ExtensionContext, progress?: ProgressHandle
'addBuildPreset',
'addTestPreset',
'selectConfigurePreset',
'viewConfigureSettings',
'selectBuildPreset',
'viewBuildSettings',
'selectTestPreset',
'viewTestSettings',
'selectActiveFolder',
'editKits',
'scanForKits',

Просмотреть файл

@ -1558,7 +1558,7 @@ export function configureArgs(preset: ConfigurePreset): string[] {
return result;
}
export function buildArgs(preset: BuildPreset): string[] {
export function buildArgs(preset: BuildPreset, tempOverrideArgs?: string[], tempOverrideBuildToolArgs?: string[]): string[] {
const result: string[] = [];
preset.__binaryDir && result.push('--build', preset.__binaryDir);
@ -1573,7 +1573,9 @@ export function buildArgs(preset: BuildPreset): string[] {
result.push('--target', ...preset.__targets);
}
tempOverrideArgs && result.push(...tempOverrideArgs);
preset.nativeToolOptions && result.push('--', ...preset.nativeToolOptions);
tempOverrideBuildToolArgs && result.push(...tempOverrideBuildToolArgs);
return result;
}

Просмотреть файл

@ -3,7 +3,7 @@ import * as nls from 'vscode-nls';
import CMakeProject from './cmakeProject';
import * as preset from './preset';
import { runCommand } from './util';
import { OptionConfig } from './config';
import { OptionConfig, checkBuildOverridesPresent, checkConfigureOverridesPresent, checkTestOverridesPresent } from './config';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@ -12,7 +12,7 @@ const noConfigPresetSelected = localize('no.configure.preset.selected', '[No Con
const noBuildPresetSelected = localize('no.build.preset.selected', '[No Build Preset Selected]');
const noTestPresetSelected = localize('no.test.preset.selected', '[No Test Preset Selected]');
let treeDataProvider: TreeDataProvider;
export let treeDataProvider: TreeDataProvider;
export class ProjectStatus {
@ -43,6 +43,9 @@ export class ProjectStatus {
await runCommand('selectConfigurePreset');
await this.refresh(node);
}),
vscode.commands.registerCommand('cmake.projectStatus.viewConfigureSettings', async (_node: Node) => {
await runCommand('viewConfigureSettings');
}),
vscode.commands.registerCommand('cmake.projectStatus.configure', async (_node: Node) => {
void runCommand('configure');
}),
@ -61,6 +64,9 @@ export class ProjectStatus {
await runCommand('selectBuildPreset');
await this.refresh(node);
}),
vscode.commands.registerCommand('cmake.projectStatus.viewBuildSettings', async (_node: Node) => {
await runCommand('viewBuildSettings');
}),
vscode.commands.registerCommand('cmake.projectStatus.ctest', async (_node: Node) => {
void runCommand('ctest');
}),
@ -71,6 +77,9 @@ export class ProjectStatus {
await runCommand('selectTestPreset');
await this.refresh(node);
}),
vscode.commands.registerCommand('cmake.projectStatus.viewTestSettings', async (_node: Node) => {
await runCommand('viewTestSettings');
}),
vscode.commands.registerCommand('cmake.projectStatus.debugTarget', async (_node: Node) => {
await runCommand('debugTarget');
}),
@ -151,6 +160,9 @@ class TreeDataProvider implements vscode.TreeDataProvider<Node>, vscode.Disposab
private isDebugButtonHidden: boolean = false;
private isLaunchButtonHidden: boolean = false;
private isBusy: boolean = false;
private configNode: ConfigNode | undefined;
private buildNode: BuildNode | undefined;
private testNode: TestNode | undefined;
get onDidChangeTreeData(): vscode.Event<Node | undefined> {
return this._onDidChangeTreeData.event;
@ -180,6 +192,25 @@ class TreeDataProvider implements vscode.TreeDataProvider<Node>, vscode.Disposab
await this.refresh();
}
public async refreshNode(node: ConfigNode | BuildNode | TestNode | undefined): Promise<any> {
if (node) {
await node.refresh();
this._onDidChangeTreeData.fire(node);
}
}
public async refreshConfigNode(): Promise<any> {
await this.refreshNode(this.configNode);
}
public async refreshBuildNode(): Promise<any> {
await this.refreshNode(this.buildNode);
}
public async refreshTestNode(): Promise<any> {
await this.refreshNode(this.testNode);
}
public async refresh(node?: Node): Promise<any> {
if (node) {
await node.refresh();
@ -218,6 +249,7 @@ class TreeDataProvider implements vscode.TreeDataProvider<Node>, vscode.Disposab
}
if (!this.isConfigButtonHidden) {
const configNode = new ConfigNode();
this.configNode = configNode;
await configNode.initialize();
if (this.isBusy) {
configNode.convertToStopCommand();
@ -226,6 +258,7 @@ class TreeDataProvider implements vscode.TreeDataProvider<Node>, vscode.Disposab
}
if (!this.isBuildButtonHidden) {
const buildNode = new BuildNode();
this.buildNode = buildNode;
await buildNode.initialize();
if (this.isBusy) {
buildNode.convertToStopCommand();
@ -234,6 +267,7 @@ class TreeDataProvider implements vscode.TreeDataProvider<Node>, vscode.Disposab
}
if (!this.isTestButtonHidden) {
const testNode = new TestNode();
this.testNode = testNode;
await testNode.initialize();
if (this.isBusy) {
testNode.convertToStopCommand();
@ -420,6 +454,10 @@ class ConfigNode extends Node {
return this.initialize();
}
async refresh(): Promise<void> {
await this.configPreset?.refresh();
}
}
class BuildNode extends Node {
@ -472,6 +510,10 @@ class BuildNode extends Node {
return this.initialize();
}
async refresh(): Promise<void> {
await this.buildPreset?.refresh();
}
}
class TestNode extends Node {
@ -514,6 +556,10 @@ class TestNode extends Node {
}
}
async refresh(): Promise<void> {
await this.testPreset?.refresh();
}
}
class DebugNode extends Node {
@ -621,6 +667,7 @@ class ConfigPreset extends Node {
this.tooltip = 'Change Configure Preset';
this.contextValue = 'configPreset';
this.collapsibleState = vscode.TreeItemCollapsibleState.None;
await this.updateDescription();
}
async refresh() {
@ -628,6 +675,21 @@ class ConfigPreset extends Node {
return;
}
this.label = (treeDataProvider.cmakeProject.configurePreset?.displayName ?? treeDataProvider.cmakeProject.configurePreset?.name) || noConfigPresetSelected;
await this.updateDescription();
}
private async updateDescription(): Promise<void> {
if (!treeDataProvider.cmakeProject) {
return;
}
const config = (await treeDataProvider.cmakeProject.getCMakeDriverInstance())?.config;
if (config && checkConfigureOverridesPresent(config)) {
this.description = "Override settings applied";
this.contextValue = 'configPreset - overrides present';
} else {
this.description = "";
this.contextValue = 'configPreset';
}
}
}
@ -644,6 +706,7 @@ class BuildPreset extends Node {
this.tooltip = 'Change Build Preset';
this.contextValue = 'buildPreset';
this.collapsibleState = vscode.TreeItemCollapsibleState.None;
await this.updateDescription();
}
async refresh() {
@ -651,6 +714,22 @@ class BuildPreset extends Node {
return;
}
this.label = (treeDataProvider.cmakeProject.buildPreset?.displayName ?? treeDataProvider.cmakeProject.buildPreset?.name) || noBuildPresetSelected;
await this.updateDescription();
}
private async updateDescription(): Promise<void> {
if (!treeDataProvider.cmakeProject) {
return;
}
const config = (await treeDataProvider.cmakeProject.getCMakeDriverInstance())?.config;
if (config && checkBuildOverridesPresent(config)) {
this.description = "Override settings applied";
this.contextValue = 'buildPreset - overrides present';
} else {
this.description = "";
this.contextValue = 'buildPreset';
}
}
}
@ -667,6 +746,7 @@ class TestPreset extends Node {
this.tooltip = 'Change Test Preset';
this.contextValue = 'testPreset';
this.collapsibleState = vscode.TreeItemCollapsibleState.None;
await this.updateDescription();
}
async refresh() {
@ -674,6 +754,22 @@ class TestPreset extends Node {
return;
}
this.label = (treeDataProvider.cmakeProject.testPreset?.displayName ?? treeDataProvider.cmakeProject.testPreset?.name) || noTestPresetSelected;
await this.updateDescription();
}
private async updateDescription(): Promise<void> {
if (!treeDataProvider.cmakeProject) {
return;
}
const config = (await treeDataProvider.cmakeProject.getCMakeDriverInstance())?.config;
if (config && checkTestOverridesPresent(config)) {
this.description = "Override settings applied";
this.contextValue = 'testPreset - overrides present';
} else {
this.description = "";
this.contextValue = 'testPreset';
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
import { ConfigurationReader, StatusBarOptionVisibility, StatusBarTextOptionVisibility, StatusBarStaticOptionVisibility, StatusBarIconOptionVisibility } from '@cmt/config';
import { ConfigurationReader, StatusBarOptionVisibility, StatusBarTextOptionVisibility, StatusBarStaticOptionVisibility, StatusBarIconOptionVisibility, checkConfigureOverridesPresent, checkBuildOverridesPresent, checkTestOverridesPresent } from '@cmt/config';
import { SpecialKits } from '@cmt/kit';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
@ -545,7 +545,7 @@ export class ConfigurePresetSelection extends Button {
if (text.length === 0) {
return ConfigurePresetSelection._noPresetSelected;
}
return this.bracketText;
return checkConfigureOverridesPresent(this.config) ? `*${this.bracketText}` : this.bracketText;
}
protected getTextShort(): string {
@ -588,7 +588,7 @@ export class BuildPresetSelection extends Button {
if (text.length === 0) {
return BuildPresetSelection._noPresetSelected;
}
return this.bracketText;
return checkBuildOverridesPresent(this.config) ? `*${this.bracketText}` : this.bracketText;
}
protected getTextShort(): string {
@ -631,7 +631,7 @@ export class TestPresetSelection extends Button {
if (text.length === 0) {
return TestPresetSelection._noPresetSelected;
}
return this.bracketText;
return checkTestOverridesPresent(this.config) ? `*${this.bracketText}` : this.bracketText;
}
protected getTextShort(): string {
@ -741,12 +741,21 @@ export class StatusBar implements vscode.Disposable {
setConfigurePresetName(v: string): void {
this._configurePresetButton.text = v;
}
updateConfigurePresetButton(): void {
this._configurePresetButton.update();
}
setBuildPresetName(v: string): void {
this._buildPresetButton.text = v;
}
updateBuildPresetButton(): void {
this._buildPresetButton.update();
}
setTestPresetName(v: string): void {
this._testPresetButton.text = v; this.setCTestEnabled(true);
}
updateTestPresetButton(): void {
this._testPresetButton.update();
}
hideLaunchButton(shouldHide: boolean = true): void {
this._launchButton.hidden = shouldHide;

17
src/ui/util.ts Normal file
Просмотреть файл

@ -0,0 +1,17 @@
import { getStatusBar } from "@cmt/extension";
import { treeDataProvider } from "@cmt/projectStatus";
export async function onConfigureSettingsChange(): Promise<void> {
await treeDataProvider.refreshConfigNode();
getStatusBar()?.updateConfigurePresetButton();
}
export async function onBuildSettingsChange(): Promise<void> {
await treeDataProvider.refreshBuildNode();
getStatusBar()?.updateBuildPresetButton();
}
export async function onTestSettingsChange(): Promise<void> {
await treeDataProvider.refreshTestNode();
getStatusBar()?.updateTestPresetButton();
}

Просмотреть файл

@ -15,7 +15,6 @@
"rootDir": ".",
"strict": true,
"experimentalDecorators": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitThis": true,
"skipLibCheck": true