Working on ROOT
as a user is one thing, working on ROOT
as a developer is something else entirely. ROOT
is a large C++ project with decades of history, thousands of contributors, and every corner of C++ put to use. To do meaningful development inside it, you need more than just a make
command, you need a setup that lets you move quickly, inspect the codebase with precision, and debug effectively.
I’ve settled on a workflow based on VSCode
, the CMake Tools
extension, and compile_commands.json
. It gives me fast builds, accurate navigation through ROOT’s
labyrinth of headers, and a debugger that can step cleanly through shared libraries and test binaries. To make it reproducible and portable across machines, I also rely on CMakePresets.json
, which plays well with VSCode out of the box.
The first step is still an out-of-source build. ROOT’s
tree should stay clean, and the build artifacts go into a dedicated directory:
&&
CMake configuration is where development time is usually won or lost. For a development build, I prefer a minimal but functional feature set, with testing enabled and compile commands exported.
A direct invocation looks like:
I generally use RelWithDebInfo
to keep optimization realistic but retain symbols (-O2 -g3 -fno-omit-frame-pointer
) for profiling and backtraces.
At this stage, the editor can be wired in. I open the repository root in VSCode
, point CMake Tools
to .build
, and symlink compile_commands.json
into the workspace:
In .vscode/settings.json
:
Or, if I prefer clangd
over cpptools
:
With this in place, navigation, autocompletion, and diagnostics all behave correctly across ROOT’s headers.
One improvement I find essential for portability is CMakePresets.json
. This file lets me capture the entire configuration in version-controlled form, so I don’t need to remember long command lines. A simple preset looks like this:
Once this file is in the repository root, VSCode
automatically detects it. From the Command Palette I just pick CMake: Select Configure Preset → dev-relwithdebinfo
, and builds/tests can be run directly through the extension. This makes the workflow reproducible across machines and simplifies onboarding when collaborating with others.
Sometimes I want more than one configuration handy. For example, a minimal developer build for fast iteration, and another with extra components like roofit
or pyroot
enabled. Presets make this trivial. Here’s a snippet showing two side by side:
Switching between them in VSCode is as simple as changing the active configure preset. This way, I can keep one build tree lean for day-to-day hacking and another with heavier options enabled for feature-specific work.
Debugging is the final piece. The main ROOT
binary lives in .build/bin/root.exe
, and that’s usually where I attach. For gdb
, .vscode/launch.json
includes:
For Clang-based builds, switching to lldb
works just as well, with a nearly identical config.
Tests are equally straightforward. Running ctest -N
in .build
lists available executables, any of which can be added to launch.json
. With CMake Tools
, it’s also possible to right-click and debug a specific test, reusing the same environment.
This combination, minimal build, compile_commands.json
, multiple presets for different workflows, and debugger integration gives a development environment that is both reproducible and flexible. Presets remove boilerplate, the editor stays in sync with the build system, and debugging works smoothly across ROOT’s plugin-heavy architecture. That’s the setup I rely on when hacking on ROOT, and it keeps the focus where it belongs, on the code itself.