关于 qt-compatibility-build
为 Deepin V25/V20 的 Qt/CMake 项目提供构建配置指导,帮助维护者用同一套代码兼容 Qt6 与 Qt5。通过自动检测 Qt 版本并映射 DTK 版本,避免在 CMake 中固定版本引用。
主要功能
- 01自动检测 Qt5 或 Qt6
- 02按 Qt 版本映射 DTK
- 03动态配置依赖与链接库
- 04区分 V25 和 V20 控制文件
- 05提供翻译生成配置指导
适用场景
- 01让同一项目支持 V25 与 V20
- 02替换 CMake 中固定的 Qt/DTK 引用
- 03按已安装的 Qt 版本配置链接
- 04为双版本构建检查 Debian 依赖
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ re2zero/ deepin-skills --skill qt-compatibility-build安装后在 Claude Code 中输入/qt-compatibility-build确认已加载。
详细介绍
qt-compatibility-build
概述
统一 CMake 配置,以支持 deepin V25/V20 双版本,并自动检测 Qt5/Qt6、动态映射 DTK 版本,从而消除整个构建系统中的硬编码版本引用。
文件约定
| 文件 | deepin 版本 | Qt 版本 |
|---|---|---|
debian/control | V25 | Qt6 |
debian/control.1 | V20 | Qt5 |
原因:control(无后缀)=最新版本(V25),control.1(带后缀)=上一版本(V20)。
适用场景
digraph when_to_use {
"Qt/CMake project?" [shape=diamond];
"V25/V20 dual support?" [shape=diamond];
"Hard-coded Qt/DTK?" [shape=diamond];
"Use this skill" [shape=box];
"Wrong tool" [shape=box];
"Qt/CMake project?" -> "V25/V20 dual support?" [label="yes"];
"V25/V20 dual support?" -> "Hard-coded Qt/DTK?" [label="yes"];
"Hard-coded Qt/DTK?" -> "Use this skill" [label="yes"];
}
适用于:
- CMakeLists.txt 的
target_link_libraries中硬编码了Qt5::或Qt6:: - CMakeLists.txt 的
find_package或链接中硬编码了Dtk::或Dtk6:: - 项目需要从同一份代码构建 V25(Qt6)和 V20(Qt5)
- 需要根据检测到的 Qt 版本动态链接库
- DTK 依赖需要自动映射到已安装的 Qt 版本
不适用于:
- 不使用 CMake 构建系统的项目
- 不依赖 Qt 的项目
- 仅支持单个版本(仅 V25 或仅 V20)
快速参考
| 任务 | 命令/模式 |
|---|---|
| 自动检测 Qt | find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) |
| 将 DTK 映射到 Qt | if (QT_VERSION_MAJOR MATCHES 6) set(DTK_VERSION_MAJOR 6) |
| 动态查找 Qt | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${QT} REQUIRED) |
| 动态查找 DTK | find_package(Dtk${DTK_VERSION_MAJOR}Widget REQUIRED) |
| 动态链接 Qt | Qt${QT_VERSION_MAJOR}::Core |
| 动态链接 DTK | Dtk${DTK_VERSION_MAJOR}::Core |
| V25 构建 | cmake -B build -DQT_DIR=/usr/lib/x86_64-linux-gnu/cmake/Qt6 |
| V20 构建 | cmake -B build5 -DQT_DIR=/usr/lib/x86_64-linux-gnu/cmake/Qt5 |
注意:为方便本地构建,-DQT_DIR 是可选项。未指定时,CMake 会自动检测。
实现
步骤 1:添加 Qt 检测(CMakeLists.txt 顶部)
# Auto-detect Qt version (tries Qt6 first, falls back to Qt5)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
message(STATUS "Found Qt version: ${QT_VERSION_MAJOR}")
# Map to DTK version (Qt6→DTK6, Qt5→DTK5)
if (QT_VERSION_MAJOR MATCHES 6)
set(DTK_VERSION_MAJOR 6)
else()
set(DTK_VERSION_MAJOR "")
endif()
message(STATUS "Build with DTK: ${DTK_VERSION_MAJOR}")
步骤 2:更新所有 find_package 调用
之前(硬编码):
find_package(Qt6 COMPONENTS Core Gui Widgets Network REQUIRED)
find_package(DtkWidget REQUIRED)
之后(动态):
set(QT Core Gui Widgets Network DBus Sql Svg Test WebChannel WebSockets)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${QT} REQUIRED)
find_package(Dtk${DTK_VERSION_MAJOR}Widget REQUIRED)
find_package(Dtk${DTK_VERSION_MAJOR}Core REQUIRED)
find_package(Dtk${DTK_VERSION_MAJOR}Gui REQUIRED)
步骤 3:更新所有 target_link_libraries
之前(硬编码):
target_link_libraries(mylib
Dtk::Core
Dtk::Gui
Qt6::Network
)
之后(动态):
target_link_libraries(mylib
Dtk${DTK_VERSION_MAJOR}::Core
Dtk${DTK_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Network
)
替换模式:
Qt5::→Qt${QT_VERSION_MAJOR}::Qt6::→Qt${QT_VERSION_MAJOR}::Dtk::→Dtk${DTK_VERSION_MAJOR}::Dtk6::→Dtk${DTK_VERSION_MAJOR}::
步骤 4:生成翻译(如有需要)
创建 cmake/translation-generate.cmake:
function(TRANSLATION_GENERATE QMS)
find_package(Qt${QT_VERSION_MAJOR}LinguistTools QUIET)
if (NOT Qt${QT_VERSION_MAJOR}_LRELEASE_EXECUTABLE)
set(QT_LRELEASE "/lib/qt${QT_VERSION_MAJOR}/bin/lrelease")
message(STATUS "NOT found lrelease, set QT_LRELEASE = ${QT_LRELEASE}")
else()
set(QT_LRELEASE "${Qt${QT_VERSION_MAJOR}_LRELEASE_EXECUTABLE}")
endif()
if(NOT ARGN)
message(SEND_ERROR "Error: TRANSLATION_GENERATE() called without any .ts path")
return()
endif()
file(GLOB TS_FILES "${ARGN}/*.ts")
set(${QMS})
foreach(TSFIL ${TS_FILES})
get_filename_component(FIL_WE ${TSFIL} NAME_WE)
set(QMFIL ${CMAKE_CURRENT_BINARY_DIR}/${FIL_WE}.qm)
list(APPEND ${QMS} ${QMFIL})
add_custom_command(
OUTPUT ${QMFIL}
COMMAND ${QT_LRELEASE} ${TSFIL} -qm ${QMFIL}
DEPENDS ${TSFIL}
COMMENT "Running ${QT_LRELEASE} on ${TSFIL}"
VERBATIM
)
endforeach()
set_source_files_properties(${${QMS}} PROPERTIES GENERATED TRUE)
set(${QMS} ${${QMS}} PARENT_SCOPE)
endfunction()
用法:
include(translation-generate)
TRANSLATION_GENERATE(QM_FILES ${CMAKE_SOURCE_DIR}/translations)
add_custom_target(${PROJECT_NAME}_qm_files DEPENDS ${QM_FILES})
add_dependencies(${PROJECT_NAME} ${PROJECT_NAME}_qm_files)
install(FILES ${QM_FILES} DESTINATION share/${PROJECT_NAME}/translations)
步骤 5:创建 control 文件
debian/control(V25/Qt6):
Build-Depends:
cmake,
pkg-config,
qt6-base-dev,
qt6-tools-dev,
qt6-svg-dev,
libdtk6widget-dev,
libdtk6core-dev
debian/control.1(V20/Qt5):
Build-Depends:
cmake,
pkg-config,
qtbase5-dev,
qttools5-dev,
libqt5svg5-dev,
libdtkwidget-dev,
libdtkcore-dev
依赖映射
| 用途 | V25 (Qt6) | V20 (Qt5) |
|---|---|---|
| 基础 | qt6-base-dev | qtbase5-dev |
| 工具 | qt6-tools-dev | qttools5-dev |
| SVG | qt6-svg-dev | libqt5svg5-dev |
| DTK Widget | libdtk6widget-dev | libdtkwidget-dev |
| DTK Core | libdtk6core-dev | libdtkcore-dev |
常见错误
| 错误 | 错误原因 | 修正方法 |
|---|---|---|
硬编码 Qt5::Core / Qt6::Core | 强制使用特定 Qt 版本 | 使用 Qt${QT_VERSION_MAJOR}::Core |
硬编码 Dtk::Core / Dtk6::Core | 强制使用特定 DTK 版本 | 使用 Dtk${DTK_VERSION_MAJOR}::Core |
缺少 DTK_VERSION_MAJOR | DTK 无法映射到 Qt 版本 | 添加从 Qt 检测结果映射变量的逻辑 |
只使用 control,没有 control.1 | 不支持 V20 | 创建两个 control 文件 |
| 在单个 control 文件中使用 OR 依赖 | 应使用单独的文件 | 拆分为 control 和 control.1 |
| 只测试一个 Qt 版本 | 双版本支持要求两个版本都能正常工作 | 测试 V25 和 V20 构建 |
未使用 find_package(QT NAMES Qt6 Qt5 ...) | 无法自动检测两个版本 | 使用正确的 find_package 模式 |
危险信号——停止并检查
- 在 CMakeLists.txt 中硬编码 Qt5/Qt6 → 必须使用
QT_VERSION_MAJOR变量 - 在 CMakeLists.txt 中硬编码 DTK5/DTK6 → 必须使用
DTK_VERSION_MAJOR变量 - 缺少
DTK_VERSION_MAJOR变量 → DTK 无法映射到 Qt 版本 - 使用 OR 依赖项,而不是单独的控制文件 → 应使用 control/control.1
- 只测试一个 Qt 版本 → 两个版本都必须可用
- Qt 检测未使用
find_package(QT NAMES Qt6 Qt5 ...)→ 无法检测两个版本
评论
支持 Markdown