# CMake kits

A _kit_ defines project-agnostic and configuration-agnostic info about how to build code. A kit can include:

- A set of compilers: these are locked at specific versions so that you can switch your compiler version quickly and easily.
- A Visual Studio installation: building for Visual Studio involves more than just finding the necessary compiler executable. Visual C++ requires certain environment variables to be set to tell it how to find and link to the Visual C++ toolchain headers and libraries.
- A toolchain file: The low-level way to instruct CMake how to compile and link for a target. CMake Tools handles toolchain files using kits.

Kits are mostly CMake-generator-agnostic (a CMake generator writes the input files for the native build system). The exception is Visual Studio kits: when you [scan for kits](#scan-for-kits), CMake Tools looks up the VS version and sets `preferredGenerator` on the kit to the matching CMake generator (e.g., `"Visual Studio 18 2026"` for VS 2026). If a kit was scanned before CMake Tools added support for that VS version, the extension derives the correct VS generator at runtime as a last-resort fallback — it is tried only after other generators like Ninja. If the version can't be determined, the kit falls through to default generators.

> **Note:**
> * If you use the [Ninja](https://ninja-build.org/) build system, don't worry about Visual Studio CMake Generators. CMake Tools will prefer Ninja if it is present, unless configured otherwise or the kit has a `preferredGenerator` set at scan time. To explicitly use a specific generator, set `cmake.generator` in your settings.
> * If you change the active kit while a project is configured, the project configuration will be re-generated with the chosen kit.
> * When the selected generator doesn't match what's already in an existing `CMakeCache.txt`, CMake Tools cleans the prior configuration instead of letting CMake error out.
> * Using a kit is recommended but optional. If you don't use a kit, CMake will perform its own automatic detection.

## How kits are found and defined

When the CMake Tools extension runs for the first time, it will [scan for kits](#scan-for-kits) to find available toolchains. It populates the initial list of kits by looking in directories where known compilers are typically installed, and uses `vswhere` to find Visual Studio installations.

### User-local kits

A user-local kit is a kit that is available to a particular user for all projects open with CMake Tools.

The user-local list of kits is stored in the `cmake-tools-kits.json` file, which you can edit by invoking **Edit User-Local CMake Kits** from the command palette:

![Example cmake_kits_json file](images/cmake_kits_json.png)

You can manually edit this file to define new global kits, however the contents of this file will be automatically updated by CMake Tools during a [scan for kits](#scan-for-kits).

> **Tip:**
> Define a new kit with your desired settings rather than modify kits that the CMake Tools extension creates so that your changes aren't overwritten during the next [scan for kits](#scan-for-kits).

### Project kits

Default user-local kits are available for all projects that use CMake Tools. To define a project-local kit, create a `.vscode/cmake-kits.json` file in the project directory. You manage the contents of this file manually, but CMake Tools will automatically reload and refresh when it sees this file added, removed, or changed. When changing kits, you can select from both user-local and project-local kits.

An example of when a project-local kit is useful is when the project defines its own CMake toolchain file(s). A [toolchain kit](#specify-a-toolchain) can be defined that specifies this file to be loaded. You can commit the `.vscode/cmake-kits.json` to source control and share it with other developers for easier collaboration using the named toolchain.

### Scan for kits

Update [user-local kits](#user-local-kits) by running **Scan for Kits** from the VS Code command palette. The following process is used to find available kits:

**1. Search the current PATH for compilers**

 - CMake tools uses the `PATH` environment variable to get a list of directories where compilers can be found.
 - CMake Tools looks for `gcc` and `clang` binaries on the `PATH` and gets version information from each executable it finds. For `gcc`, if a corresponding `g++` executable resides in the same directory it is added to the kit as the corresponding C++ compiler. The same applies for a `clang++` binary in the directory of a `clang` executable.
 
> **Note:**
> CMake Tools only automatically detects `Clang` and `GCC`. If you'd like auto-detection for more tools, please [open a Github issue](https://github.com/microsoft/vscode-cmake-tools/issues) with information about the compiler binary names and how to parse its version information.

**2. Find Visual Studio installations**

- CMake tools includes `vswhere.exe`, which it uses to find Visual Studio instances installed on the system.
 
- For each of `x86`, `amd64`, `x86_amd64`, `x86_arm`, `x86_arm64`, `amd64_x86`, `amd64_arm`, and `amd64_arm64`, CMake Tools checks for installed Visual C++ environments. A kit is generated for each existing MSVC toolchain that is found. For known VS versions (2019, 2022, 2026, etc.), the kit gets a `preferredGenerator` pointing at the right CMake generator, like `"Visual Studio 18 2026"`. If the VS version wasn't recognized at scan time, CMake Tools derives the correct generator at runtime as a last-resort fallback. Re-running **Scan for Kits** will set `preferredGenerator` permanently.

**3. Save results to the user-local kits file**

- The [user-local kit](#user-local-kits) `cmake-tools-kits.json` file is updated with the new kit information.

> **Warning:**
> The name of each kit is generated from the kit compiler and version information. Kits with the same name will be overwritten. To prevent custom kits from being overwritten, give them unique names.
>
> By default, scans preserve existing entries in `cmake-tools-kits.json`. If `cmake.removeStaleKitsOnScan` is enabled, compiler-based kits (those with a `compilers` field) that are no longer rediscovered during a full scan are removed automatically. Set `"keep": true` in a kit entry to preserve it even when this cleanup is enabled. Kits without a `compilers` field (toolchain-only kits and Visual Studio kits) are always preserved.

## Kit options

CMake defines different options that can be specified for each kit in their definition in `cmake-tools-kits.json` (user-local) or `.vscode/cmake-kits.json` (project-level), and these options can be mixed-and-matched as needed. For example, a single kit may request a Visual Studio environment, while specifying `clang-cl` as a compiler.

See [Configure CMake](configure.md) for more information about how kits are applied during configuration.

### Specify a compiler

To specify a compiler, list the path to the compiler in the `cmake-tools-kits.json` or `.vscode/cmake-kits.json` file.

The most common CMake languages are `C` and `CXX`, and CMake Tools has built-in support for finding these. However, any language can be specified:

```json
[
    {
        "name": "My Compiler Kit",
        "compilers": {
            "C": "/usr/bin/gcc",
            "CXX": "/usr/bin/g++",
            "Fortran": "/usr/bin/gfortran"
        }
    }
]
```

### Specify a toolchain

CMake Tools doesn't automatically detect toolchains, but you can specify a CMake toolchain file in a kit, like this:

```json
[
    {
        "name": "Emscripten",
        "toolchainFile": "/path/to/emscripten/toolchain.cmake"
    }
]
```

CMake Tools will pass this path for `CMAKE_TOOLCHAIN_FILE` during configuration.

### Visual Studio

CMake Tools automatically sets up the environment for working with Visual C++. It is best to let CMake Tools generate the kits first, then duplicate and modify them:

```json
[
    {
        "name": "A Visual Studio",
        "visualStudio": "Visual Studio Build Tools 2017",
        "visualStudioArchitecture": "amd64",
        "visualStudioArguments": ["uwp", "10.0.10240.0"]
    }
]
```

Keys:
> `visualStudio` : the name of a Visual Studio installation obtained by `VSWhere`.\
> `visualStudioArchitecture`: the Visual Studio target architecture that would be passed to the `vcvarsall.bat` file when entering the VS dev environment.
> `visualStudioArguments`: the extra arguments that would be passed to the `vcvarsall.bat` file when entering the VS dev environment, those arguments are `[platform_type] [winsdk_version] [-vcvars_ver=vc_version] [-vcvars_spectre_libs=spectre_mode]`

> **Note:**
> To use Visual C++, both `visualStudio` and `visualStudioArchitecture` must be specified. Omitting either one won't work.

## Unsupported commands

The following commands are not supported when kits and variants are active:
- **CMake: Scan for Compilers**
- **CMake: Add Configure Preset**
- **CMake: Add Build Preset**
- **CMake: Add Test Preset**
- **CMake: Add Package Preset**
- **CMake: Add Workflow Preset**
- **CMake: Select Configure Preset**
- **CMake: Select Build Preset**
- **CMake: Select Test Preset**
- **CMake: Select Package Preset**
- **CMake: Select Workflow Preset**

### General options

The following additional options may be specified:

`preferredGenerator`

> The CMake generator to use with this kit if not the default. For Visual Studio kits, this is set during [kit scanning](#scan-for-kits) based on the VS version. When picking a generator, CMake Tools checks these in order:
>
> 1. `cmake.generator` from your settings — if set, this wins outright; nothing below is consulted.
> 2. The kit's `preferredGenerator` (set at scan time for VS kits).
> 3. `cmake.preferredGenerators` from your settings, in order.
> 4. `Ninja`, then `Unix Makefiles` — only consulted when neither #2 nor #3 produced any candidate (i.e. the kit has no `preferredGenerator` and `cmake.preferredGenerators` is empty).
> 5. For VS kits that have no `preferredGenerator` of their own: the VS generator derived at runtime from the kit's VS version — pushed to the end of the candidate list, so it's tried after the Ninja/Unix Makefiles fallback when both apply.
>
> If a VS kit was scanned before the VS version mapping existed, CMake Tools derives the correct generator at runtime (#5) — but only after Ninja and Unix Makefiles. To make the VS generator the unconditional choice, either re-run **Scan for Kits** so the kit gets its own `preferredGenerator`, or set `cmake.generator` in your settings.

`cmakeSettings`

> A JSON object passed as a list of cache settings when running CMake configure. Don't use this for project-specific settings and options. Instead, use `settings.json` for that purpose.

> This setting is most useful when the toolchain file respects additional options that can be passed as cache variables.

> **Semicolon Handling:**
>
> CMake uses semicolons as list separators. The type of value you use determines how semicolons are handled:
>
> - **String values**: Passed through to CMake verbatim. A `;` inside a string keeps its natural CMake list-separator meaning. If you genuinely need a literal `;` inside a single list element, pre-escape it as `\;` in your JSON — CMake Tools no longer transforms strings.
>
> - **Array values**: Elements are joined with semicolons to produce a CMake list. This is the declarative, JSON-native way to express a list.
>
> - **Boolean values**: Emitted as a CMake BOOL cache variable, so the CMake Cache Editor renders them as a checkbox.
>
> **Example - Passing a CMake list (string notation):**
> ```jsonc
> "cmakeSettings": {
>     "CMAKE_PREFIX_PATH": "C:/vcpkg/packages/zlib_x64-windows;C:/vcpkg/packages/curl_x64-windows"
>     // Produces: -DCMAKE_PREFIX_PATH:STRING=C:/vcpkg/packages/zlib_x64-windows;C:/vcpkg/packages/curl_x64-windows
> }
> ```
>
> **Example - Passing a CMake list (array notation):**
> ```jsonc
> "cmakeSettings": {
>     "LLVM_ENABLE_PROJECTS": ["clang", "lld"]
>     // Produces: -DLLVM_ENABLE_PROJECTS:STRING=clang;lld
> }
> ```
>
> **Example - Boolean value:**
> ```jsonc
> "cmakeSettings": {
>     "BUILD_TESTING": true
>     // Produces: -DBUILD_TESTING:BOOL=TRUE
> }
> ```
>
> **Windows path tip:** Prefer forward slashes in path lists. If you must use backslashes, take care that none of them sit immediately before a `;` — JSON parses `\\` as one `\`, so the string CMake actually receives ends in `\;`, which CMake treats as an *escaped* semicolon and collapses the surrounding paths into a single element:
>
> ```jsonc
> // JSON you write in cmake-kits.json:
> "CMAKE_PREFIX_PATH": "C:\\foo\\;C:\\bar"
> // String CMake receives:  C:\foo\;C:\bar
> // CMake parses as:        ONE element (because \; is an escaped separator)
> ```
>
> Use forward slashes (`"C:/foo;C:/bar"`) or an array (`["C:/foo", "C:/bar"]`) to avoid the trap.

`environmentVariables`

> A JSON object of key-value pairs specifying additional environment variables to be defined when using this kit.

`environmentSetupScript`

> The absolute path to a script or a string in form of `"script path" [arg ...]`that modifies/adds environment variables for the kit. 
Uses `call` on Windows and `source` in `bash` otherwise.

### Kit environment and CMake executable resolution

When using kits mode (not CMake Presets), the active kit's environment—including variables set via `environmentSetupScript` and `environmentVariables`—influences how CMake Tools resolves the CMake executable path:

1. **Auto discovery (`cmake.cmakePath: auto` or `cmake`):**  
   The active kit's `PATH` is searched first before falling back to the system `PATH`. This allows a kit's setup script to prepend a custom directory containing a CMake binary, and that binary will be discovered and used.

2. **Environment variable substitution:**  
   If `cmake.cmakePath` uses `${env:VARIABLE_NAME}` syntax, the substitution resolves to values from the active kit's environment. For example, if a kit defines `MY_CMAKE_PATH` via `environmentVariables` or `environmentSetupScript`, you can set `"cmake.cmakePath": "${env:MY_CMAKE_PATH}/cmake"` and it will resolve using the kit-provided value.

**Example:**

In `.vscode/cmake-kits.json`, define the environment variable in the kit:
```json
[
  {
    "name": "Cross-Compile Kit",
    "environmentSetupScript": "${workspaceFolder}/scripts/setup.sh",
    "environmentVariables": {
      "MY_CMAKE_PATH": "/custom/cmake/path"
    }
  }
]
```

In `.vscode/settings.json`, reference the variable (do not define it here):
```json
{
  "cmake.cmakePath": "${env:MY_CMAKE_PATH}/cmake"
}
```

When this kit is selected, `cmake.cmakePath` will resolve to `/custom/cmake/path/cmake` using the kit's environment variable. Environment variables are resolved from the active kit's context, not from workspace settings.

`description`

> A short description of the kit, which will appear next to its name in the selection menu.

## Next steps

- Explore the [CMake Tools documentation](README.md)
