CMake the way CLion does it (profiles and presets, targets, run and debug configurations, CTest) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Tomáš Černík <Tom.cernik@gmail.com> Reviewed-on: #1
8.5 KiB
VS Code CMake Helper
CMake in VS Code the way CLion does it. Standalone: it doesn't need (or want) Microsoft's CMake Tools, so turn that off in workspaces where this one runs. Projects are read through CMake's File API (CMake 3.14+; presets need 3.19+, test results 3.21+).
What it does
- Profiles (the Profiles view, the
$(layers)item in the status bar): each one is a build directory with its own build type, generator, toolchain, cache variables and environment. They come from thecmakeHelper.profilessetting and from the configure presets inCMakePresets.json/CMakeUserPresets.json. With neither, there's CLion's default: Debug incmake-build-debug. Switching profiles reads that directory's last configure if there is one, and configures otherwise. - Targets (the Targets view): executables, libraries and custom targets (
add_custom_target;showUtilityTargetsturns them off; CTest's dashboard targets are never listed), each with its sources in CMake's source groups. Inline buttons ▶ Run, 🐞 Debug, 🔨 Build. The menu has Set as Active, Edit Run Configuration…, Rebuild, Go to Definition in CMakeLists and Copy Path of the Built File. - One active target in the status bar:
$(target) app, then 🔨 ▶ 🐞. Keys as in CLion: Ctrl+F9 build, Shift+F10 run, Shift+F9 debug, Alt+Shift+F10 choose the target. - Run configurations per target, edited as CLion's Run/Debug Configurations (Edit Run Configuration… on a target, or Edit Configurations… in the target picker): every target on the left, by kind; on the right its executable (the target's own, another target's, or a file: what a custom target or a library runs after it's built), program arguments, working directory (default: the executable's directory), environment (
A=1;B=2) and Before launch: Build. A custom target with no executable is only built by ▶, as in CLion; 🐞 debugs the program its command runs (COMMAND app --flag:appwith--flag, in the command's directory, withcmake -E env's variables), after building what the target depends on (not the target itself, which would run the command). The command comes from the build system, so this needs a Ninja or Makefile generator. They're kept in the workspace settings undercmakeHelper.runConfigurations. - Debugging through C/C++ (
cppdbg, orcppvsdbgwith MSVC), CodeLLDB or LLDB DAP: the first one installed, or the one set incmakeHelper.debugger. Extra launch properties go incmakeHelper.debugConfiguration. - CTest in the Test Explorer: tests are grouped by the target whose executable they run, and by suite for names like
Suite.Test. Each one sits at itsTEST(…)/TEST_CASE("…")/BOOST_AUTO_TEST_CASE(…)in the sources (with ▶ in the gutter), or else at itsadd_test. Running builds the tests' targets first, then callsctestand reads the results from JUnit. Debugging starts the test's command under the debugger. Tests thatgtest_discover_testsfinds only after a build show up once the build is done. - Code lenses: ▶ Run / 🐞 Debug above
main()in an executable's sources, and Run / Debug / Build above eachadd_executable/add_custom_target, and Build above eachadd_library, in CMake files. - Load CMake Project on a
CMakeLists.txt(the explorer's and the editor's context menu, as in CLion): that folder becomes the project (cmakeHelper.sourceDirectory) and it's configured; on the project's ownCMakeLists.txtthe menu has Reload CMake Project. - Reload: when one of the project's CMake files changes, a notification and a
Reload CMakeitem in the status bar appear (cmakeHelper.autoReload:ask,always,never). Reset Cache and Reload Project removesCMakeCache.txtandCMakeFiles/first. A generator mismatch offers the reset by itself. compile_commands.jsonis exported (exportCompileCommands), and can be copied where clangd looks for it (copyCompileCommands, e.g.${sourceDir}/compile_commands.json).- For
launch.json/tasks.json:${command:cmakeHelper.activeProgram},${command:cmakeHelper.activeTarget},${command:cmakeHelper.buildDirectory},${command:cmakeHelper.buildType}.
Embedded and remote debugging
As CLion's Embedded GDB Server and Remote GDB Server run configurations: CMake: Edit GDB Server Configurations… (or New GDB Server Configuration… in the target picker). A configuration chosen in the target picker (it shows there under the targets) is what the toolbar's 🔨, ▶ and 🐞 act on; choosing a target goes back to running it here.
- Embedded GDB Server: a GDB server started here (OpenOCD, SEGGER J-Link, ST-LINK's st-util, pyOCD: Fill in for sets the usual arguments), gdb (
gdb-multiarch,arm-none-eabi-gdb…) connected withtarget remote, the program downloaded (Always, If updated, Never) between two reset commands. 🐞 debugs it; ▶ is Download & Run: flash, start it (monitor reset runby default), detach, no debugger. - Remote GDB Server: gdb connected to a gdbserver elsewhere, with a sysroot and path mappings. With an SSH host the program is first uploaded (scp) and gdbserver started there over SSH, and ▶ runs it there.
Debugging goes through C/C++ (ms-vscode.cpptools, cppdbg), which starts the server and connects. The configurations are kept in the workspace setting cmakeHelper.gdbConfigurations.
Profiles in settings
CMake: Edit Profiles… (the ⚙ on a profile, or in the profile picker) edits them as CLion's Settings › Build › CMake does: the list with add, remove, copy and move, and each profile's name, Enable profile, build type, toolchain file, generator, CMake options, build directory, build options and environment; OK / Cancel / Apply. Presets are shown read-only; copying one makes a profile of it. It writes the workspace setting below (cache variables become -D CMake options).
"cmakeHelper.profiles": [
{ "name": "Debug", "buildType": "Debug" },
{ "name": "Release", "buildType": "Release", "generator": "Ninja" },
{
"name": "ASan",
"buildType": "RelWithDebInfo",
"buildDirectory": "cmake-build-asan",
"cacheVariables": { "CMAKE_CXX_FLAGS": "-fsanitize=address", "BUILD_TESTING": true },
"environment": { "ASAN_OPTIONS": "detect_leaks=1" }
}
]
Toolbar
cmakeHelper.toolbar says where CLion's toolbar (profile, target, Build, Run,
Debug) goes:
statusBar(default): in the status bar.editorTitle: Build, Run, Debug and the profile and target pickers as buttons at the top of the editors; the names stay in the status bar.titleBar: in VS Code's title bar, as in Jarvis's web IDE. An extension can't put anything there, so VS Code itself is patched:media/titlebar.jsgoes next to itsworkbench.htmland into it, andproduct.json's checksum is updated so VS Code doesn't call its installation corrupt. VS Code is usually root's, so it asks for your password (pkexec). After a VS Code update (which drops the patch) or an update of this extension, it offers to patch again. CMake: Remove the CMake Toolbar from the Title Bar undoes it.
Updates
The extension looks at the latest release of shin/VS-Code-CMake-helper on
git.cernikovi.cz on start and every 10 minutes, and offers a newer one: Install
downloads its .vsix and installs it. The repository is private, so it needs a
Gitea access token with read access: CMake: Set Gitea Token for CMake Helper
Updates (kept in VS Code's secret storage). CMake: Check for CMake Helper
Updates looks now; cmakeHelper.updates.check turns it off.
A release is made by the CI on a v* tag matching the version in package.json.
Development
Everything runs in the image of the Dockerfile: Node for the extension, and
CMake, Ninja, g++ and GDB for what it drives.
- Dev container: open this folder in VS Code and Reopen in Container
(Dev Containers extension).
npm ciruns on creation; F5 Run Extension (example) opensexample/, a small project (a library, an executable, a CTest test) to try it on. - Without VS Code:
./scripts/docker.sh <command>runs a command in the image, in this folder and as you, e.g../scripts/docker.sh npm run package -- --skip-license; without a command it's a shell.
The title bar patch (cmakeHelper.toolbar: titleBar) can't be tried in the
container: there the extension runs remotely and VS Code's installation is
the host's.
Building
npm install
npm run compile # out/
npm run package # .vsix
To try it, open this folder in VS Code and press F5 (Run Extension), or install the .vsix.