How to support both Qt5 and Qt6 using CMake
If you are using Qt5 with CMake already, you are prepared for what is expected to come with Qt6. If not, be prepared to port your pro files to use CMake. Though there still is support for QMake, planes are to deprecate it as it is more limited compared to CMake. Also many official IDEs, toolchains and build systems have good CMake support. Heck, even Google with its NDK is migrating from ndk-build to CMake. So it makes sense switching to CMake and improve your project sustainability. To learn more about how to build Qt6 on your system and port your projects, I recommend the following read:
https://www.qt.io/blog/qt-6-build-system
Even though the „Good News“ say that there is no immediate need to port, the support of QMake will be dropped one day, so why not already go to CMake and not be urged to port it when QMake is not going to work anymore and you need to hit the deadline very soon?
Of course this does not mean you want to drop Qt5 and why should you? With CMake it works perfectly fine. Also, do you want to drop the Qt5 support of your application? I guess not, because Qt6 is very new and on many systems it does not run yet. But CMake has been since 2000 and has become very stable after so many years of growth pain.
Now you can download Qt6 officially from its website: https://www.qt.io/download
No need to build it yourself and yes, the setup also provides you with CMake so you also don’t have worry about that.
But are you really ready to use Qt6 in your application? Well you should check some aspects as follows.
C++17 Standard
If your code warns you about deprecated C++ features, you should take a closer look on those and fix them. Otherwise you might get them as errors now and your project will not build. Getting warnings normally gives your more hints than errors telling you what is not possible anymore. Qt6 requires C++17, while on Qt5 you could get around with C++98, keep that in mind. Still though C++17 works with Qt5 just fine. So it’s a good chance to improve your overall source code!
Deprecated features in Qt6
Of course Qt6 got cleaned up a lot meaning many Qt5 features will not work anymore. Also, if while using Qt5 you see warnings about deprecation, take a special look on these, because they most probably will become errors on Qt6. For example the sprintf method of QString is pretty popular, but it does not work with Qt6 anymore.
CMake Version 3.16
I think you can use an older version, but Qt recommends 3.16. Qt Setup provides a recent version of CMake, for Linux distros with package managers and so on you might have to worry more maybe…
CMakeLists.txt adjustments
And if you want have CMake working with Qt5 and Qt6 together, I recommend using an option where you can switch between the Qt versions. Here is an example:
cmake_minimum_required(VERSION 3.16.0)
project(helloworld VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
option(USE_QT6 "Enable this if you want to use Qt6, instead of Qt5" no)
if(USE_QT6)
find_package(Qt6 COMPONENTS Widgets REQUIRED)
else(USE_QT6)
find_package(Qt5 COMPONENTS Widgets REQUIRED)
endif(USE_QT6)
add_executable(helloworld
mainwindow.ui
mainwindow.cpp
main.cpp
resources.qrc
)
if(USE_QT6)
target_link_libraries(helloworld PRIVATE Qt6::Widgets)
else(USE_QT6)
target_link_libraries(helloworld PRIVATE Qt5::Widgets)
endif(USE_QT6)
Now you might criticize this as, why can CMake not just detect the Qt version installed on your system? Well, you can implement it that way and I can write an article how to do that, but I believe an option in which you consciously enable it will make you care more of what you have running on your system, especially if you have both Qt5 and Qt6 installed, which at these times is very likely. Also this scales well if you are using QtCreator and quick switching between the Qt5 and Qt6 builds for testing both variants.
So if you want to port your project from QMake and support both Qt5 and Qt6 using CMake, feel free to use my example.
Here by default CMake will use Qt5, you can enable Qt6 with cmake -DUSE_QT6=yes
or within your favorite configurator ticking the option to become enabled.
Versionless approach
A versionless is approach is also possible, which makes it a bit simpler (https://doc.qt.io/qt-6/cmake-qt5-and-qt6-compatibility.html):
cmake_minimum_required(VERSION 3.16.0)
project(helloworld VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(Qt6 COMPONENTS Widgets)
if (NOT Qt6_FOUND)
find_package(Qt5 5.15 COMPONENTS Core REQUIRED)
endif()
add_executable(helloworld
mainwindow.ui
mainwindow.cpp
main.cpp
resources.qrc
)
target_link_libraries(helloworld PRIVATE Qt::Widgets)
But there is one catch: Versionless approach is supported since Qt 5.15. If you need to support older versions, you should avoid versionless approach.
What you can do though is detect the version, store it in a variable and use it in your CMakeLists.txt:
cmake_minimum_required(VERSION 3.16.0)
project(helloworld VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
add_executable(helloworld
mainwindow.ui
mainwindow.cpp
main.cpp
resources.qrc
)
target_link_libraries(helloworld PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
Not entirely versionless but with that you have a way to use Qt6 but also versions before Qt5.15.
Neueste Kommentare