Skip to content

feat: Evaluate environmentSetupScript before CMake executable search#4763

Draft
Copilot wants to merge 4 commits intomainfrom
copilot/allow-path-alterations-pre-cmake-search
Draft

feat: Evaluate environmentSetupScript before CMake executable search#4763
Copilot wants to merge 4 commits intomainfrom
copilot/allow-path-alterations-pre-cmake-search

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 26, 2026

This change addresses item #2301

This changes visible behavior

The following changes are proposed:

  • Evaluate the kit's environmentSetupScript before resolving the CMake executable path, so $PATH modifications from the script are respected during cmake/ctest/cpack lookup
  • Thread an optional searchPATH parameter through Paths.which()getCMakePath() / getCTestPath() / getCPackPath()DirectoryContext wrappers, using the which npm package's native path option
  • In getCMakePathofProject(), call effectiveKitEnvironment() when the active kit has an environmentSetupScript and pass the resulting PATH into the resolution chain

The purpose of this change

The extension resolved the cmake binary via process.env.PATH (VS Code launch-time PATH) before effectiveKitEnvironment() ever ran. Kits whose environmentSetupScript added cmake to $PATH could never have that cmake found — the script ran too late (during driver _setKit()).

Other Notes/Information

Backward compatible: All new parameters are optional. No behavior change when environmentSetupScript is absent.

Presets mode unaffected: Presets use configurePreset.cmakeExecutable, orthogonal to kit environment.

extension.ts init() unchanged: Startup cmake check runs before any kit is active — left as-is (best-effort).

Double script execution: The setup script may run once for cmake resolution and again in the driver's _setKit(). Accepted as pragmatic; optimizable with caching later if needed.

Key change in src/cmakeProject.ts:

async getCMakePathofProject(): Promise<string> {
    const overWriteCMakePathSetting = this.useCMakePresets ? this.configurePreset?.cmakeExecutable : undefined;
    let searchPATH: string | undefined;
    if (this._activeKit?.environmentSetupScript) {
        const kitEnv = await effectiveKitEnvironment(this._activeKit);
        searchPATH = kitEnv['PATH'];
    }
    return await this.workspaceContext.getCMakePath(overWriteCMakePathSetting, searchPATH) || '';
}
Original prompt

This section details on the original issue you should resolve

<issue_title>Allow alterations to the $PATH in an environmentSetupScript to take effect before searching for the CMake executable</issue_title>
<issue_description>### Discussed in #2299

Currently the extension searches for the CMake executable before environmentSetupScript is evaluated. In the event that the setup script alters the $PATH, those changes won't be in effect when looking for the CMake binary.</issue_description>

<agent_instructions>You are Copilot coding agent acting as a senior maintainer/contributor for the VS Code extension repository microsoft/vscode-cmake-tools. You are deeply familiar with CMake, CMake kits, CMake Presets, VS Code extension APIs, and the architecture of this repo (TypeScript-heavy, commands in src/extension.ts, project logic in src/cmakeProject.ts, drivers in src/drivers/, kit management in src/kits/kit.ts, path resolution in src/paths.ts, workspace context in src/workspace.ts, configuration schema in package.json, typed config access in src/config.ts).

Source of Truth
Implement the following feature request: #2301 - #2301 — Allow alterations to the $PATH in an environmentSetupScript to take effect before searching for the CMake executable

Feature Summary
When a kit defines an environmentSetupScript, the script may modify $PATH to include a directory containing the cmake binary. Currently, the extension searches for the CMake executable before the kit's environmentSetupScript is evaluated, so any $PATH changes from the script are ignored during cmake lookup. The fix is to evaluate the kit's environment (including running the setup script) before resolving the cmake executable path, so that a script-modified $PATH is respected.

Understanding the Problem (orient yourself here first)
The ordering issue spans several files. Read these carefully before writing code — the analysis below reflects the current codebase, but you should verify each claim and adjust your approach if anything has changed.

The current flow (simplified):
src/cmakeProject.ts → getCMakePathofProject() (~L1408): Calls this.workspaceContext.getCMakePath() to find the cmake binary.
src/workspace.ts → DirectoryContext.getCMakePath() (~L48): Delegates to paths.getCMakePath().
src/paths.ts → Paths.getCMakePath() (~L252): When the setting is 'auto' or 'cmake', calls this.which('cmake').
src/paths.ts → Paths.which() (~L196): Uses the which npm package, which searches process.env.PATH — the PATH at VS Code launch time.
Only later, when the CMake driver is created and _setKit() is called in src/drivers/cmakeDriver.ts (~L753), does effectiveKitEnvironment() in src/kits/kit.ts (~L1052) run the environmentSetupScript via getShellScriptEnvironment() and capture its environment.
Result: The cmake binary search at step 3-4 uses the stale process.env.PATH, not the kit's script-modified PATH.

Where the kit environment is built:
src/kits/kit.ts → effectiveKitEnvironment() (~L1052): This is the function that runs getShellScriptEnvironment() when kit.environmentSetupScript is defined, then layers on kit.environmentVariables and VS kit variables. It returns the full effective Environment for the kit.
src/kits/kit.ts → getShellScriptEnvironment() (~L670): Executes the user's setup script in a temp wrapper, captures the resulting environment variables (including PATH), and returns them.
Where the environment is consumed (too late for cmake search):
src/drivers/cmakeDriver.ts → _setKit() (~L753): Calls effectiveKitEnvironment() and stores the result in this._kitEnvironmentVariables. This happens when the driver is initialized — but the cmake executable was already resolved before the driver was created.
Files to Explore for Implementation
These are the files most likely to need changes. Read them to understand the current patterns and identify the best integration points. The suggestions below are starting points — you may find a cleaner approach after exploring the code.

src/paths.ts — which() method (~L196) and getCMakePath() (~L252). The which npm package accepts an options object with a path property for overriding the search PATH. Explore whether threading an optional Environment parameter through these methods is the right approach, or whether there's a simpler alternative. Also consider getCTestPath() and getCPackPath() which depend on getCMakePath().
src/workspace.ts — DirectoryContext.getCMakePath() (~L48) is a thin wrapper around paths.getCMakePath(). If the paths layer needs an environment parameter, this wrapper likely needs to forward it.
src/cmakeProject.ts — getCMakePathofProject() (~L1408) is the entry point for cmake resolution. This is probably where the kit's environment should be pre-evaluated before the path lookup. Also look at getCMakeExecutable() (~L1414) and getCMakeDriverInstance() (~L1434) to understand the...


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits February 26, 2026 15:34
…2301)

When a kit defines an environmentSetupScript that modifies $PATH, the
script is now evaluated before searching for the cmake executable, so
that PATH changes from the script are respected during cmake lookup.

Changes:
- src/paths.ts: Add optional searchPATH parameter to which(), getCMakePath(),
  getCTestPath(), getCPackPath() to allow overriding the search PATH
- src/workspace.ts: Forward searchPATH through DirectoryContext wrapper methods
- src/cmakeProject.ts: In getCMakePathofProject(), evaluate kit environment
  via effectiveKitEnvironment() when active kit has environmentSetupScript,
  and pass the kit's PATH to path resolution
- CHANGELOG.md: Add feature entry
- test/unit-tests/backend/paths.test.ts: Add tests for which with custom PATH

Co-authored-by: hanniavalera <90047725+hanniavalera@users.noreply.github.com>
Co-authored-by: hanniavalera <90047725+hanniavalera@users.noreply.github.com>
Copilot AI changed the title [WIP] Allow alterations to $PATH in environmentSetupScript for CMake search feat: Evaluate environmentSetupScript before CMake executable search Feb 26, 2026
On Windows, the `which` npm package uses PATHEXT (.EXE;.CMD;.BAT;.COM)
to resolve executables. The test was creating files without a recognized
extension, causing `which` to fail with 'not found' on Windows CI.

Fix: On Windows, create .cmd files and search by base name (which
appends .cmd via PATHEXT). On non-Windows, keep the existing behavior
with chmod +x.

Co-authored-by: hanniavalera <90047725+hanniavalera@users.noreply.github.com>
Copilot AI added a commit that referenced this pull request Mar 2, 2026
…se studies

Co-authored-by: hanniavalera <90047725+hanniavalera@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow alterations to the $PATH in an environmentSetupScript to take effect before searching for the CMake executable

2 participants