QT 5 和 QT 6 兼容性

The semantics of the CMake API in Qt 5 and Qt 6 are largely compatible, though some differences exist in the behavior of these commands and additional interfaces only in the latter versions. This guide is primarily meant for projects looking into gradual migration from one major release to another.

Up to Qt 5.14, all imported Qt library targets and commands contained the version number as part of the name, for example qt5_add_library . This makes writing CMake code that should work with both Qt 5 and Qt 6 somewhat cumbersome. Qt 5.15 therefore introduced versionless targets and commands, that is qt_add_library , to enable writing CMake code that is largely agnostic to the different Qt versions.

无版本目标

除现有导入目标外,Qt 5.15 引入 versionless 目标。也就是说,要链接到 Qt Core 可以引用 Qt6::Core ,或 Qt::Core :

find_package(Qt6 COMPONENTS Core)
if (NOT Qt6_FOUND)
    find_package(Qt5 5.15 REQUIRED COMPONENTS Core)
endif()
add_executable(helloworld
    ...
)
target_link_libraries(helloworld PRIVATE Qt::Core)
					

以上片段首先试着查找 Qt 6 安装。若失败,试着查找 Qt 5.15 包。独立于是使用 Qt 6 或 Qt 5,可以使用导入的 Qt::Core target. To skip the Qt 6 check, set CMAKE_DISABLE_FIND_PACKAGE_Qt6 先于 find_package 调用。

The versionless targets are defined by default. Set QT_NO_CREATE_VERSIONLESS_TARGETS 先于第一 find_package() call to disable them.

无版本命令

从 Qt 5.15 起,Qt 模块还提供了无版本变体的 命令 。例如,现在可以使用 qt_add_translation 编译翻译文件,独立于是使用 Qt 5 还是 Qt 6。

Set QT_NO_CREATE_VERSIONLESS_FUNCTIONS 先于第一 find_package() 调用以阻止创建无版本命令。

混合 Qt 5 和 Qt 6

There might be projects that need to load both Qt 5 and Qt 6 in one CMake context (though mixing Qt versions in one library or executable is not supported, so be careful there).

在这样的设置中,无版本目标和命令将隐式引用找到的首个 Qt 版本凭借 find_package 。设置 QT_DEFAULT_MAJOR_VERSION CMake 变量先于首个 find_package call to make the version explicit.

Supporting Qt 5 versions older than 5.15

If you need to support also Qt 5 versions older than Qt 5.15, you can do so by storing the current version in an CMake variable ( QT_VERSION_MAJOR ):

find_package(Qt6 COMPONENTS Core)
if(Qt6_FOUND)
    set(QT_VERSION_MAJOR 6)
else()
    find_package(Qt5 REQUIRED COMPONENTS Core)
    set(QT_VERSION_MAJOR 5)
endif()
add_executable(helloworld
    ...
)
target_link_libraries(helloworld PRIVATE Qt${QT_VERSION_MAJOR}::Core)
					

Compared to the versionless approach, the targets point to Qt${QT_VERSION_MAJOR}::Core , which gets resolved to either Qt5::Core or Qt6::Core during the call of target_link_libraries .

Use the versionless variants of the CMake commands where possible.

Use the versioned targets unless you have to support Qt 5 and Qt 6 in the same project.

If you have to use versionless targets, be aware of the 使用无版本目标时的陷阱 .

Use the versioned versions of the CMake commands and targets if you need to support Qt 5 versions older than Qt 5.15, or if you cannot control whether your CMake code is loaded in a context where QT_NO_CREATE_VERSIONLESS_FUNCTIONS or QT_NO_CREATE_VERSIONLESS_TARGETS might be defined. In this case you can still simplify your code by determining the actual command or target name through a variable.

使用无版本目标时的陷阱

Using the versionless targets has several downsides.

The versionless targets are usually ALIAS targets and you cannot make an ALIAS target pointing to an ALIAS target. Instead, use the ALIASED_TARGET target property.

For older Qt 6 versions, the imported Qt::Core target didn't feature all the target properties exposed by Qt6::Core . This is fixed if you link against Qt 6.8 or newer, with CMake 3.18 or newer.

Projects must not export targets that expose the versionless targets. For example, a library that is consumed by another project must not export targets that link publicly against versionless targets. Otherwise, transitive dependencies might be broken, or the user of that library mixes Qt5 and Qt6 targets involuntarily.

Windows 的 Unicode 支持

在 Qt 6, UNICODE and _UNICODE compiler definitions are set by default for targets that link against Qt modules. This is in line with the qmake behavior, but it is a change compared to the CMake API behavior in Qt 5.

调用 qt_disable_unicode_defines() on the target to not set the definitions.

find_package(Qt6 COMPONENTS Core)
add_executable(helloworld
    ...
)
qt_disable_unicode_defines(helloworld)