qt-compatibility-build

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

qt-compatibility-build

qt-compatibility-build

Overview

概述

Unifies CMake configuration for deepin V25/V20 dual-version support by automatically detecting Qt5/Qt6 and dynamically mapping DTK versions, eliminating hard-coded version references throughout the build system.
通过自动检测Qt5/Qt6并动态映射DTK版本,统一CMake配置以支持deepin V25/V20双版本,消除构建系统中所有硬编码的版本引用。

File Convention

文件约定

FileDeepin VersionQt Version
debian/control
V25Qt6
debian/control.1
V20Qt5
Why:
control
(no suffix) = latest version (V25),
control.1
(with suffix) = previous version (V20).
文件Deepin版本Qt版本
debian/control
V25Qt6
debian/control.1
V20Qt5
原因:无后缀的
control
对应最新版本(V25),带后缀的
control.1
对应旧版本(V20)。

When to Use

适用场景

dot
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"];
}
Use when:
  • CMakeLists.txt has hard-coded
    Qt5::
    or
    Qt6::
    in
    target_link_libraries
  • CMakeLists.txt has hard-coded
    Dtk::
    or
    Dtk6::
    in
    find_package
    or linking
  • Projects need both V25 (Qt6) and V20 (Qt5) builds from same code
  • Need dynamic library linking based on detected Qt version
  • DTK dependencies need to map automatically to installed Qt version
Do NOT use when:
  • Projects without CMake build system
  • Projects without Qt dependencies
  • Single version support only (V25-only or V20-only)
dot
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)

Quick Reference

快速参考

TaskCommand/Pattern
Auto-detect Qt
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
Map DTK to Qt
if (QT_VERSION_MAJOR MATCHES 6) set(DTK_VERSION_MAJOR 6)
Dynamic Qt find
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${QT} REQUIRED)
Dynamic DTK find
find_package(Dtk${DTK_VERSION_MAJOR}Widget REQUIRED)
Dynamic Qt linking
Qt${QT_VERSION_MAJOR}::Core
Dynamic DTK linking
Dtk${DTK_VERSION_MAJOR}::Core
V25 build
cmake -B build -DQT_DIR=/usr/lib/x86_64-linux-gnu/cmake/Qt6
V20 build
cmake -B build5 -DQT_DIR=/usr/lib/x86_64-linux-gnu/cmake/Qt5
Note:
-DQT_DIR
is optional for local build convenience. CMake auto-detects if not specified.
任务命令/模式
自动检测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会自动检测。

Implementation

实现步骤

Step 1: Add Qt Detection (CMakeLists.txt top)

步骤1:添加Qt检测(CMakeLists.txt顶部)

cmake
undefined
cmake
undefined

Auto-detect Qt version (tries Qt6 first, falls back to Qt5)

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}")
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)

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}")
undefined
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}")
undefined

Step 2: Update All find_package Calls

步骤2:更新所有find_package调用

Before (hard-coded):
cmake
find_package(Qt6 COMPONENTS Core Gui Widgets Network REQUIRED)
find_package(DtkWidget REQUIRED)
After (dynamic):
cmake
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)
修改前(硬编码):
cmake
find_package(Qt6 COMPONENTS Core Gui Widgets Network REQUIRED)
find_package(DtkWidget REQUIRED)
修改后(动态):
cmake
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)

Step 3: Update All target_link_libraries

步骤3:更新所有target_link_libraries

Before (hard-coded):
cmake
target_link_libraries(mylib
    Dtk::Core
    Dtk::Gui
    Qt6::Network
)
After (dynamic):
cmake
target_link_libraries(mylib
    Dtk${DTK_VERSION_MAJOR}::Core
    Dtk${DTK_VERSION_MAJOR}::Gui
    Qt${QT_VERSION_MAJOR}::Network
)
Replacement pattern:
  • Qt5::
    Qt${QT_VERSION_MAJOR}::
  • Qt6::
    Qt${QT_VERSION_MAJOR}::
  • Dtk::
    Dtk${DTK_VERSION_MAJOR}::
  • Dtk6::
    Dtk${DTK_VERSION_MAJOR}::
修改前(硬编码):
cmake
target_link_libraries(mylib
    Dtk::Core
    Dtk::Gui
    Qt6::Network
)
修改后(动态):
cmake
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}::

Step 4: Translation Generation (if needed)

步骤4:生成翻译文件(如有需要)

Create
cmake/translation-generate.cmake
:
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()
Usage:
cmake
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)
创建
cmake/translation-generate.cmake
:
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()
使用方式:
cmake
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)

Step 5: Create Control Files

步骤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
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

Dependency Mapping

依赖映射

PurposeV25 (Qt6)V20 (Qt5)
Base
qt6-base-dev
qtbase5-dev
Tools
qt6-tools-dev
qttools5-dev
SVG
qt6-svg-dev
libqt5svg5-dev
DTK Widget
libdtk6widget-dev
libdtkwidget-dev
DTK Core
libdtk6core-dev
libdtkcore-dev
用途V25 (Qt6)V20 (Qt5)
基础库
qt6-base-dev
qtbase5-dev
工具
qt6-tools-dev
qttools5-dev
SVG支持
qt6-svg-dev
libqt5svg5-dev
DTK组件库
libdtk6widget-dev
libdtkwidget-dev
DTK核心库
libdtk6core-dev
libdtkcore-dev

Common Mistakes

常见错误

MistakeWhy It's WrongFix
Hard-coded
Qt5::Core
/
Qt6::Core
Forces specific Qt versionUse
Qt${QT_VERSION_MAJOR}::Core
Hard-coded
Dtk::Core
/
Dtk6::Core
Forces specific DTK versionUse
Dtk${DTK_VERSION_MAJOR}::Core
Missing
DTK_VERSION_MAJOR
DTK won't map to Qt versionAdd variable mapping from Qt detection
Only using
control
without
control.1
Won't support V20Create both control files
Using OR dependencies in single controlShould use separate filesSplit into control and control.1
Only testing one Qt versionBoth must work for dual supportTest V25 and V20 builds
Not using
find_package(QT NAMES Qt6 Qt5 ...)
Won't auto-detect bothUse correct find_package pattern
错误原因修复方案
硬编码
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两种构建
Qt检测未使用
find_package(QT NAMES Qt6 Qt5 ...)
无法检测两个版本使用正确的find_package格式

Red Flags - STOP and Check

警示信号 - 立即检查

  • Hard-coded Qt5/Qt6 in CMakeLists.txt → Must use
    QT_VERSION_MAJOR
    variable
  • Hard-coded DTK5/DTK6 in CMakeLists.txt → Must use
    DTK_VERSION_MAJOR
    variable
  • Missing
    DTK_VERSION_MAJOR
    variable
    → DTK won't map to Qt version
  • Using OR dependencies instead of separate control files → Should use control/control.1
  • Only testing one Qt version → Both versions must work
  • Qt detection not using
    find_package(QT NAMES Qt6 Qt5 ...)
    → Won't detect both versions
  • CMakeLists.txt中硬编码Qt5/Qt6 → 必须使用
    QT_VERSION_MAJOR
    变量
  • CMakeLists.txt中硬编码DTK5/DTK6 → 必须使用
    DTK_VERSION_MAJOR
    变量
  • 缺少
    DTK_VERSION_MAJOR
    变量
    → DTK无法映射到Qt版本
  • 使用OR依赖而非分离的control文件 → 应该使用control/control.1
  • 仅测试一个Qt版本 → 两个版本都必须能正常工作
  • Qt检测未使用
    find_package(QT NAMES Qt6 Qt5 ...)
    → 无法检测两个版本