Qt 5 和 Qt 6 兼容性

Qt 5 和 Qt 6 中 CMake API 的语义基本兼容。然而,在 Qt 5.14 及之前,所有导入的 Qt 库目标和命令都包括版本号作为名称的一部分。这使得编写既适用于 Qt 5 又适用于 Qt 6 的 CMake 代码变得有些繁琐。因此,Qt 5.15 引入了无版本的标签和命令,以便编写主要与不同的 Qt 版本无关的 CMake 代码。

无版本标签

除了现有的导入目标,Qt 5.15 还引入了无版本标签。也就是说,为了连接到 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 目标。

无版本标签默认定义。在第一个 find_package() 调用之前设置 QT_NO_CREATE_VERSIONLESS_TARGETS 来禁用。

注意:导入的 Qt::Core 目标将不具有 Qt6::Core 目标 中可用的目标属性。

无版本命令

从 Qt 5.15 开始,Qt 模块也提供其命令的无版本变体。例如,现在您可以使用 qt_add_translation 编译翻译文件,而不管您使用的是 Qt 5 还是 Qt 6。

在第一个 find_package() 调用之前设置 QT_NO_CREATE_VERSIONLESS_FUNCTIONS 以阻止创建无版本命令。

混合 Qt 5 和 Qt 6

可能存在需要在一个 CMake 上下文中同时加载 Qt 5 和 Qt 6 的项目(尽管在一个库或可执行文件中混合 Qt 版本是不受支持的,所以请小心)。

在这种配置下,无版本目标和命令将隐式引用第一个通过 find_package 找到的 Qt 版本。在第一个 find_package 调用之前设置 CMake 变量 QT_DEFAULT_MAJOR_VERSION 以明确版本。

支持较老的 Qt 5 版本

如果您需要支持比 Qt 5.15 更老的 Qt 5 版本,可以通过将当前版本存储在一个 CMake 变量中来实现。

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)

add_executable(helloworld
    ...
)

target_link_libraries(helloworld PRIVATE Qt${QT_VERSION_MAJOR}::Core)

在此,我们让 find_package(<PackageName>...) 尝试首先寻找 Qt 6,如果失败则寻找 Qt 5,名称为 QT。如果找到了任何一个,find_package 将成功,并且 CMake 变量 QT_VERSION_MAJOR 将定义为 56

然后我们再次通过网络创建名称为 Qt${QT_VERSION_MAJOR} 的包来加载确定的 Qt 版本。这是必要的,因为 CMAKE_AUTOMOC 预期包名称为 Qt5Qt6,否则会打印错误。

我们可以使用相同的模式来指定导入库的名称。在调用 target_link_libraries 之前,CMake 将将 Qt${QT_VERSION_MAJOR}::Widgets 解析为 Qt5::WidgetsQt6::Widgets

在可能的情况下,使用版本无关的 CMake 命令的变体。

除非你必须在一个项目中同时支持 Qt 5 和 Qt 6,否则请使用版本目标。

如果你必须使用版本无关的目标,请注意在 使用版本无关目标时的潜在风险

如果你需要支持比 Qt 5.15 更旧的 Qt 5 版本,或者你无法控制你的 CMake 代码是否在可能定义 QT_NO_CREATE_VERSIONLESS_FUNCTIONSQT_NO_CREATE_VERSIONLESS_TARGETS 的上下文中被加载,请使用 CMake 命令和目标的版本化版本。在这种情况下,你仍然可以通过变量确定实际的命令或目标名称来简化你的代码。

使用版本无关目标时的潜在风险

使用版本无关目标有几个缺点。

版本无关的目标是 ALIAS 目标,并且缺乏版本化目标的属性。

项目不得导出暴露版本无关目标的目标。例如,一个被另一个项目消耗的库不得导出链接到版本无关目标的公开目标。否则,递归依赖关系可能会损坏,或者该库的用户无意中混合了 Qt5 和 Qt6 目标。

Windows 中的 Unicode 支持

在 Qt 6 中,默认为链接到 Qt 模块的目标设置了 UNICODE_UNICODE 编译器定义。这与 qmake 的行为一致,但与 Qt 5 中的 CMake API 行为不同。

在目标上调用 qt_disable_unicode_defines() 不设置定义。

find_package(Qt6 COMPONENTS Core)

add_executable(helloworld
    ...
)

qt_disable_unicode_defines(helloworld)

© 2024 Qt 公司有限公司。此处包含的文档贡献属于其各自的拥有者。此处提供的文档根据自由软件基金会发布的条款,在 GNU 自由文档许可证版本 1.3 下许可。Qt 及相关标志为芬兰和/或其他国家的 Qt 公司有限公司的商标。所有其他商标均为其各自的拥有者的财产。