The Qt developers are working on porting Qt 6 to CMake as their internal build system. While Qt 6 is still a few months away, you can already see some of the benefits of this work in Qt 5.15. Christian Adam has already blogged about the improvements in CMake 3.17 and how, for example, AUTOMOC has improved in QT 5.15. This article is about how you can prepare for Qt 6 in your CMake projects.
Looking back: from Qt 4 to Qt 5
While Qt 4 - Qt 5 have been largely source compatible from a C++ perspective, unfortunately this is not the case with the CMake integration itself. Sometimes you had to adapt a large part of the CMake code, in the case of Qt integration.
CMake is now much more commonly used in Qt projects, and CMake support itself has matured significantly. Consequently, the developers do not plan to make any drastic changes to the integration, but instead try to make the transition as smooth as possible.
Problem: versioned targets and commands
One obvious problem is that basically all the CMake APIs (targets, variables, commands) that Qt provides have the major version of Qt in their name. This is true even for very simple examples:
cmake_minimum_required(VERSION 3.5) project(hellotr LANGUAGES CXX) find_package(Qt5 COMPONENTS Widgets LinguistTools REQUIRED) qt5_add_translation(QM_FILES hellotr_en.ts) add_executable(hellotr main.cpp ${QM_FILES} ) target_link_libraries(hellotr Qt5::Widgets)
Now you can argue that, assuming the actual semantics don't change, replacing all calls to Qt5::, qt5_ in your CMake file with Qt6::, qt6_ is easy enough. However, this won't help you if you want to support Qt 5 and Qt 6 for a while.
Versionless targets and commands
So let me introduce the new versionless targets and commands in Qt 5.15. The example above can be written like this:
cmake_minimum_required(VERSION 3.5) project(hellotr LANGUAGES CXX) find_package(Qt5 5.15 COMPONENTS Widgets LinguistTools REQUIRED) qt_add_translation(QM_FILES hellotr_en.ts) add_executable(hellotr main.cpp ${QM_FILES} ) target_link_libraries(hellotr Qt::Widgets)
With the exception of the find_package call, this should work for Qt 6 as well.
If you're interested in the additional 5.15 argument to find_package: this allows CMake to throw an error with the appropriate error message if your version of Qt is older than Qt 5.15.
You can opt out of these new targets and commands by setting the QT_NO_CREATE_VERSIONLESS_TARGETS or QT_NO_CREATE_VERSIONLESS_FUNCTIONS variables before find_package. This is useful, for example, if you have already defined them yourself, or if you still want to access qt_wrap_cpp in Qt 3.
Mixing Qt 5 and Qt 6
Let me start with a big disclaimer: Qt does not support mixing different versions of Qt in the same application! Anyway, there are advanced use cases where you can build separate artifacts using Qt 5 and Qt 6 in the same project.
For these cases, you can set the new variable QT_DEFAULT_MAJOR_VERSION to 5 or 6. If this variable is set before a find_package call that loads Qt 5 or Qt 6, the versionless functions will use the logic from the corresponding Qt version.
Prospects for the future
With the first release of Qt 5.15 approaching, developers will be more and more conservative about the existing CMake framework in this version. In any case, there are plans to further improve the documentation on how it is more productive to use CMake with Qt.
In Qt 6 we will see many more APIs to not only use Qt modules, but also how to define your own Qt modules and plugins.