Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Features:
- Add support for the FASTBuild generator (CMake 4.2+). [#4690](https://github.com/microsoft/vscode-cmake-tools/pull/4690)
- Add support for `${workspaceFolder}`, `${workspaceFolder:name}` variables and relative paths in `cmake.exclude` setting for multi-root workspaces. [#4689](https://github.com/microsoft/vscode-cmake-tools/pull/4689)
- Add `onConfigureResult` event to the CMake Tools API that fires after every configure attempt (success or failure), allowing dependent extensions to detect and react to configure failures. [#4021](https://github.com/microsoft/vscode-cmake-tools/issues/4021)
- Add `cmake.preConfigureTask` setting to execute a named VS Code task before every CMake configure. [#2449](https://github.com/microsoft/vscode-cmake-tools/issues/2449) [#4960](https://github.com/microsoft/vscode-cmake-tools/pull/4960) [@erdemiru](https://github.com/erdemiru)

Improvements:
- Reduce CI pipeline time by parallelizing E2E test jobs and adding build artifact caching.
Expand Down
1 change: 1 addition & 0 deletions docs/cmake-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Options that support substitution, in the table below, allow variable references
| `cmake.cmakeProviderExtensions` | List of VS Code extension IDs that provide or install their own CMake binary. When CMake is not found during automatic configure-on-open and one of these extensions is installed, CMake Tools will briefly poll for CMake availability instead of showing an immediate error. Set to an empty array to disable this behavior. | `["stmicroelectronics.stm32-vscode-extension", "espressif.esp-idf-extension", "NXPSemiconductors.mcuxpresso", "nordic-semiconductor.nrf-connect"]` | no |
| `cmake.configureSettings` | An object containing `key:value` pairs, which will be passed to CMake when configuring. The same as passing `-DVAR_NAME=ON` via `cmake.configureArgs`. NOTE: Semicolons (`;`) in string values are passed through to CMake verbatim, CMake itself decides whether to treat them as list separators (matching how CMake Presets `cacheVariables` and `cmake-kits.json` `cmakeSettings` behave). To pass a CMake list, you can either use array notation (e.g. `"MY_LIST": [ "a", "b" ]`) or write the list as a string with `;` separators (e.g. `"MY_LIST": "a;b"`). If you genuinely need a literal `;` inside a single list element, pre-escape it as `\;` in your JSON. | `{}` (no values) | yes |
| `cmake.copyCompileCommands`| If not `null`, copies the `compile_commands.json` file generated by CMake to the path specified by this setting whenever CMake successfully configures. | `null` (do not copy the file) | yes |
| `cmake.preConfigureTask`| If not `null`, the task with this name is executed before CMake configures. | `null` (do not run any task) | yes |
| `cmake.postConfigureTask`| If not `null`, the task with this name is executed whenever CMake successfully configures. | `null` (do not run any task) | yes |
| `cmake.coverageInfoFiles` | LCOV coverage info files to be processed after running tests with coverage using the test explorer. | `[]` | yes |
| `cmake.cpackArgs` | An array of additional arguments to pass to cpack. | `[]` | yes |
Expand Down
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3108,6 +3108,12 @@
"description": "%cmake-tools.configuration.cmake.copyCompileCommands.description%",
"scope": "resource"
},
"cmake.preConfigureTask": {
"type": "string",
"default": null,
"description": "%cmake-tools.configuration.cmake.preConfigureTask.description%",
"scope": "resource"
},
"cmake.postConfigureTask": {
"type": "string",
"default": null,
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@
"cmake-tools.configuration.cmake.emscriptenSearchDirs.description": "Directories where Emscripten may be installed.",
"cmake-tools.configuration.cmake.mergedCompileCommands.description": "Recursively collect and merge all compile_commands.json found in the cmake.buildDirectory.",
"cmake-tools.configuration.cmake.copyCompileCommands.description": "Copy compile_commands.json to this location after a successful configure.",
"cmake-tools.configuration.cmake.preConfigureTask.description": "If set, this named task will be executed before CMake configure. Note that chaining the pre-configure task with other tasks in tasks.json may lead to multiple executions of the pre-configure task.",
"cmake-tools.configuration.cmake.postConfigureTask.description": "If set, this named task will be executed after a successful CMake configure.",
"cmake-tools.configuration.cmake.configureOnOpen.description": "Automatically configure CMake project directories when they are opened.",
"cmake-tools.configuration.cmake.configureOnEdit.description": "Automatically configure CMake project directories when cmake.sourceDirectory or CMakeLists.txt content are saved.",
Expand Down
76 changes: 76 additions & 0 deletions src/cmakeProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1717,6 +1717,71 @@ export class CMakeProject {

}

/**
* Execute the preConfigureTask if configured
*/
private async executePreConfigureTask(configureType: ConfigureType): Promise<ConfigureResult> {
const resultType = ConfigureResultType.NormalOperation;

if (configureType === ConfigureType.ShowCommandOnly) {
// only run for real configures
return { exitCode: 0, stdout: '', stderr: '', resultType: resultType };
}
const preConfigureTask = this.workspaceContext.config.preConfigureTask;

if (!preConfigureTask) {
// no pre-configure task is configured
return { exitCode: 0, stdout: '', stderr: '', resultType: resultType };
}

try {
// Fetch all available tasks
const tasks = await vscode.tasks.fetchTasks();

// Find the task by label
const task = tasks.find(t => t.name === preConfigureTask);

if (!task) {
const errorMsg = localize('task.not.found', 'Task "{0}" not found. Available tasks: {1}', preConfigureTask, tasks.map(t => t.name).join(', '));
void vscode.window.showErrorMessage(errorMsg);
log.error(errorMsg);
return { exitCode: -1, stdout: '', stderr: errorMsg, resultType: resultType };
}

log.info(localize('executing.pre.configure.task', 'Executing pre-configure task: {0}', preConfigureTask));

const taskExecution = await vscode.tasks.executeTask(task);

const start = new Date();

const endEvent = await new Promise<vscode.TaskProcessEndEvent>(resolve => {
const disposable = vscode.tasks.onDidEndTaskProcess(e => {
if (e.execution === taskExecution) {
disposable.dispose();
resolve(e);
}
});
});

const exitCode = endEvent.exitCode ?? -1;
const elapsed = (new Date().getTime() - start.getTime()) / 1000;
if (exitCode === 0) {
log.info(localize('executed.pre.configure.task', 'Executed pre-configure task: {0} ({1}s)', preConfigureTask, elapsed));
return { exitCode: exitCode, stdout: '', stderr: '', resultType: resultType };
} else {
const errorMsg = localize('pre.configure.task.failed', 'Pre-configure task: {0} failed: {1} ({2}s)', preConfigureTask, exitCode, elapsed);
void vscode.window.showErrorMessage(errorMsg);
log.error(errorMsg);
return { exitCode: exitCode, stdout: '', stderr: errorMsg, resultType: resultType };
}
} catch (error: any) {
const errorMsg = localize('failed.to.execute.pre.configure.task', 'Failed to execute pre-configure task: {0}', error.toString());
void vscode.window.showErrorMessage(errorMsg);
log.error(localize('pre.configure.task.error', 'Error executing pre configure task'), error);
return { exitCode: -1, stdout: '', stderr: errorMsg, resultType: resultType };
}
}

/**
* Execute the postConfigureTask if configured
*/
Expand Down Expand Up @@ -1764,6 +1829,11 @@ export class CMakeProject {
// Don't show a progress bar when the extension is using Cache for configuration.
// Using cache for configuration happens only one time.
if (drv && drv.shouldUseCachedConfiguration(trigger)) {
const preConfigureResult = await this.executePreConfigureTask(type);
if (preConfigureResult.exitCode !== 0) {
return preConfigureResult;
}

const result: ConfigureResult = await drv.configure(trigger, []);
if (result.exitCode === 0) {
await this.refreshCompileDatabase(drv.expansionOptions);
Expand Down Expand Up @@ -1836,8 +1906,14 @@ export class CMakeProject {
progress.report({ increment });
}
});
progress.report({message: localize('checking.preconfigure', 'Checking pre-configure task')});
const preConfigureResult = await this.executePreConfigureTask(type);
if (preConfigureResult.exitCode !== 0) {
return preConfigureResult;
}
try {
progress.report({ message: this.folderName });

let result: ConfigureResult;
await setContextAndStore(isConfiguringKey, true);
if (type === ConfigureType.Cache) {
Expand Down
5 changes: 5 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ export interface ExtensionConfigurationSettings {
emscriptenSearchDirs: string[];
mergedCompileCommands: string | null;
copyCompileCommands: string | null;
preConfigureTask: string | null;
postConfigureTask: string | null;
loadCompileCommands: boolean;
configureOnOpen: boolean;
Expand Down Expand Up @@ -604,6 +605,9 @@ export class ConfigurationReader implements vscode.Disposable {
get copyCompileCommands(): string | null {
return this.configData.copyCompileCommands;
}
get preConfigureTask(): string | null {
return this.configData.preConfigureTask;
}
get postConfigureTask(): string | null {
return this.configData.postConfigureTask;
}
Expand Down Expand Up @@ -738,6 +742,7 @@ export class ConfigurationReader implements vscode.Disposable {
emscriptenSearchDirs: new vscode.EventEmitter<string[]>(),
mergedCompileCommands: new vscode.EventEmitter<string | null>(),
copyCompileCommands: new vscode.EventEmitter<string | null>(),
preConfigureTask: new vscode.EventEmitter<string | null>(),
postConfigureTask: new vscode.EventEmitter<string | null>(),
loadCompileCommands: new vscode.EventEmitter<boolean>(),
configureOnOpen: new vscode.EventEmitter<boolean>(),
Expand Down
1 change: 1 addition & 0 deletions test/unit-tests/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ function createConfig(conf: Partial<ExtensionConfigurationSettings>): Configurat
postRunCoverageTarget: null,
coverageInfoFiles: [],
useFolderPropertyInBuildTargetDropdown: true,
preConfigureTask: null,
postConfigureTask: null,
additionalBuildProblemMatchers: [],
shell: null,
Expand Down
Loading