Version-less CMake targets (Qt 5.15)

We are working full steam on porting Qt 6 to CMake as the internal build system. While Qt 6 is still some months away, you can see already some benefits of this work in Qt 5.15. Cristian Adam already blogged about improvements in CMake 3.17, and how for instance AUTOMOC in QT 5.15 got improved. This blog post is about how you can prepare for Qt 6 in your CMake projects ...

Looking back: Qt 4 to Qt 5

While Qt 4 to Qt 5 was largely source compatible in terms of C++, this was unfortunately not the case for the CMake integration itself. You had sometimes to adapt much of your CMake code that dealt with integrating Qt, see KDAB's blog post from 2012 about some of the issues.

Nowadays CMake is much more common for Qt projects, and the CMake support itself has matured a lot. Hence we do not plan to do any drastic changes in the integration, but instead try to make the transition as smooth as possible ...

The issue: Versioned targets and commands

One obvious issue is that basically all of the CMake API (targets, variables, commands) that Qt provides contains the Qt major version in the name. This is true even for the 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 - provided that the actual semantics do not change - replacing all Qt5::, qt5_ calls in your CMake file with Qt6::, qt6_ is simple enough. This is true, but doesn't help you if you want to support both Qt 5 and Qt 6 for a while.

Version-less targets and commands

So let me introduce the new version-less targets and commands in Qt 5.15. Above example can be written as:

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)

 

Except for the find_package call this should work for Qt 6 too.

If you are wondering about the additional 5.15 argument to find_package: This lets CMake error out with an appropriate error message if your Qt version is older than Qt 5.15.

You can opt out of these new targets and commands by setting  QT_NO_CREATE_VERSIONLESS_TARGETS or  QT_NO_CREATE_VERSIONLESS_FUNCTIONS variables  before find_package. This is helpful for instance if you have defined these already yourself, or if you (for reasons that are beyond my imagination) want to still access Qt 3's qt_wrap_cpp ...

Mixing Qt 5 and Qt 6

Let me start with a big disclaimer: Qt doesn't support mixing different Qt versions in one application! Anyhow, there are advanced use cases where you might want to build separate artifacts using Qt 5 and Qt 6 in one project.

For these cases, you can  define the new QT_DEFAULT_MAJOR_VERSION variable to either 5 or 6. If this variable is set before the find_package call loading either Qt5 or Qt 6, the versionless functions will use the logic from the respective Qt version.

Outlook

With Qt 5.15 nearing it's first release, we will be more and more conservative in touching the existing CMake infrastructure in this version. Anyhow, we plan to still improve the documentation on how to best use CMake with Qt.

For Qt 6, we will see much more API to not only use Qt modules, but also on how to define your own Qt modules and plugins. But this is a topic for a future blog post ...


Blog Topics:

Comments