If you are working with C++ code chances are that you are using CMake to build your code, and for good reason. CMake is a powerful tool that allows you to target a wide range of compilers and platforms with a single buildsystem. Several large open source projects like Qt and KDE use CMake for that reason.

However, CMake does have a reputation for not always being the most ergonomic. For example, some useful options aren't enabled by default and need to be manually passed when invoking CMake, either from the command-line or an IDE.

For example, you might want to use the Ninja generator over the default one (e.g. Unix Makefiles on Linux) for faster builds. Enabling that is easy enough by passing -G Ninja on the command line. Remembering to do that every time a new build folder is created gets old fast though.

Another thing you might want to always enable is the CMAKE_EXPORT_COMPILE_COMMANDS option. This generates a compile_commands.json file that is used by tools like clang-tidy or the clangd language server (used for integration with code editors like Kate and Visual Studio Code).

One way to deal with repetitive CMake options are CMake presets. CMake presets are per-project configuration files that define sets of options to be applied. With that you can, for example, define presets for local development, CI builds, and release deployments, each with different options applied.

While CMake presets are a great tool for many use cases they don't help as much for quickly creating new projects. Fortunately, there's a different way to save yourself some typing: CMake environment variables.

CMake accepts configuration values not only from the command-line, but also environment variables from the system environment. For example, the default CMake generator is read from the CMAKE_GENERATOR environment variable. Likewise, you can enable compile_commands.json generation by setting the CMAKE_EXPORT_COMPILE_COMMANDS environment variable to ON.

By putting this

in your bashrc or equivalent you get those options enabled any time you create a new build folder, without specifying them manually every time. How handy is that?

This applies not only to cmake but also other tools provided by the CMake project. If you're using CMake, chances are that you're also using ctest to drive your test suite, and it, too, can be configured through environment variables. When invoking ctest on the commandline it will not show any of the tests’ output by default, making it hard to spot why a given test is failing. For this reason ctest accepts the --output-on-failure argument, which shows the test output for any failing tests. By setting CTEST_OUTPUT_ON_FAILURE=1 in the environment you can apply this to all ctest invocations automatically.

There are more environment variables than those even, see here for the full list.

That's not all, though. Not only can you set environment environment variables understood by CMake, you can also read custom environment variables in your CMake code:

This can be useful for customizing the build process when using CMake parameters is not an option.

Environment variables are a small feature that's easy to overlook, but they can noticeably improve your day-to-day workflow. By moving your personal defaults into your shell configuration, you can spend less time remembering command-line options and more time writing code. And because these settings are applied automatically whenever you create a new build directory, they complement project-specific tools like CMake presets rather than replacing them. Hopefully this tip helps you make your CMake workflow just a little more convenient.