CMake is increasingly becoming the de-facto build system for C++ projects. While it has been possible to build Qt applications using CMake for a long time, with Qt6, Qt switched its own internal build system to CMake.
The KDE Community was among the first large, open-source projects that adopted CMake about 15 years ago. Over this time, a lot of experience with CMake has accumulated in the community and solutions for recurring problems have been implemented.
These solutions are available for everyone in the Extra CMake Modules framework, or ECM, for short.
Using Extra CMake Modules
ECM is available from many popular dependency managers, including Conan, Vcpkg, Yocto and, of course, directly from its git repository.
All you need to do to use it in your project is tell CMake to find it and adjust your CMAKE_MODULE_PATH:
Now you are ready to include() its modules. You can find a list of all available modules in the API documentation.
Find Modules
When writing a CMake buildsystem, one often writes custom find modules for integrating third-party dependencies. ECM comes with a number of find modules for various commonly used dependencies, including, for example, GLIB2, Gperf, Inotify, PulseAudio, QtWaylandScanner, wayland-protocols, XCB, TagLib, or EGL.
General Purpose Modules
Testing
(Unit)Testing is indispensable for writing and maintaining software. Qt comes with a rich test framework. When using it, you typically create a separate executable for each test. In plain CMake, this comes with some boilerplate:
An additional benefit of using ECMAddTest is that it enables Q_ASSERT when running the tests; it even does so when built in Release mode, where asserts are usually disabled. This helps your tests find issues in your code without having to build your project in Debug mode.
pkg-config Integration
When developing a library, CMake provides a convenient way for other projects to use your library, in the form of CMake config files. However, you likely also want projects that don't use CMake to use your library. A popular build-system-agnostic way of exporting libraries is by using pkg-config. Your library would install a mylib.pc file that describes the compiler flags necessary (include paths, libraries, etc.) for using your library. ECM comes with ECMGeneratePkgConfigFile, an easy way to generate the needed .pc file for your project.
This installs MyLib.pc to the appropriate location.
Versioning
You often want to define your project's version information in a central place in the build system and propagate the information to the source code, e.g. to make myapp --version work or show it in an "About MyApp" screen. CMake supports passing a VERSION argument to the project() call, which sets up some relevant CMake variables. A common way to pass these variables to the source code is to configure a version header. ECMSetupVersion offers a convenient way to do this:
Some features in ECM aim at making the interaction with Qt more pleasant.
QMake Integration
Similarly to providing pkg-config files, you may want to deploy the necessary files to use your library from QMake. ECMGeneratePriFile takes care of that for you:
Qt provides powerful support for categorized logging. However, defining the logging categories comes with some boilerplate. ECMQtDeclareLoggingCategory takes care of some of that boilerplate:
Now you can run QT_LOGGING_RULES="com.mycompany.myapp=true" myapp and enjoy your categorized logging.
It also provides integration with KDebugSettings, a graphical tool for dis/enabling logging categories.
These are only some of the functionalities provided by ECM. Check out the full list of modules!
This post is part of a series of posts about the KDE Frameworks. See Part 1 for an introduction to the KDE Frameworks in general and the KConfig Framework.
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications. In addition to being leading experts in Qt, C++ and 3D technologies for over two decades, KDAB provides deep expertise across the stack, including Linux, Rust and modern UI frameworks. With 100+ employees from 20 countries and offices in Sweden, Germany, USA, France and UK, we serve clients around the world.
Nicolas Fella
Software Engineer
Nicolas is a software engineer at KDAB with multiple years of experience developing with Qt/C++ and several contributions to Qt. He has a passion for open source and works as Software Platform Engineer at KDE e.V., the non-profit behind the KDE Community. There he has spearheaded the transition to Qt6 and is working on modernizing and improving the building blocks underpinning all KDE software.
Our hands-on Modern C++ training courses are designed to quickly familiarize newcomers with the language. They also update professional C++ developers on the latest changes in the language and standard library introduced in recent C++ editions.