AgentSkillsCN

qt-compatibility-build

在维护需同时支持 Qt5 和 Qt6 的 Debian 软件包时使用;当 CMakeLists.txt 中硬编码了 Qt5/Qt6 或 DTK5/DTK6 版本,或项目需要根据检测到的 Qt 版本动态链接动态库以实现对 deepin V25/V20 的兼容性时,可选用此技能。

SKILL.md
--- frontmatter
name: qt-compatibility-build
description: Use when maintaining Debian packages that need Qt5/Qt6 dual support, CMakeLists.txt has hard-coded Qt5/Qt6 or DTK5/DTK6 versions, or projects need dynamic library linking based on detected Qt version for deepin V25/V20 compatibility

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.

File Convention

FileDeepin VersionQt Version
debian/controlV25Qt6
debian/control.1V20Qt5

Why: control (no suffix) = latest version (V25), control.1 (with suffix) = previous version (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)

Quick Reference

TaskCommand/Pattern
Auto-detect Qtfind_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
Map DTK to Qtif (QT_VERSION_MAJOR MATCHES 6) set(DTK_VERSION_MAJOR 6)
Dynamic Qt findfind_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${QT} REQUIRED)
Dynamic DTK findfind_package(Dtk${DTK_VERSION_MAJOR}Widget REQUIRED)
Dynamic Qt linkingQt${QT_VERSION_MAJOR}::Core
Dynamic DTK linkingDtk${DTK_VERSION_MAJOR}::Core
V25 buildcmake -B build -DQT_DIR=/usr/lib/x86_64-linux-gnu/cmake/Qt6
V20 buildcmake -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.

Implementation

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

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

Step 2: Update All find_package Calls

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)

Step 3: Update All 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}::

Step 4: Translation Generation (if needed)

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)

Step 5: Create Control Files

debian/control (V25/Qt6):

code
Build-Depends:
 cmake,
 pkg-config,
 qt6-base-dev,
 qt6-tools-dev,
 qt6-svg-dev,
 libdtk6widget-dev,
 libdtk6core-dev

debian/control.1 (V20/Qt5):

code
Build-Depends:
 cmake,
 pkg-config,
 qtbase5-dev,
 qttools5-dev,
 libqt5svg5-dev,
 libdtkwidget-dev,
 libdtkcore-dev

Dependency Mapping

PurposeV25 (Qt6)V20 (Qt5)
Baseqt6-base-devqtbase5-dev
Toolsqt6-tools-devqttools5-dev
SVGqt6-svg-devlibqt5svg5-dev
DTK Widgetlibdtk6widget-devlibdtkwidget-dev
DTK Corelibdtk6core-devlibdtkcore-dev

Common Mistakes

MistakeWhy It's WrongFix
Hard-coded Qt5::Core / Qt6::CoreForces specific Qt versionUse Qt${QT_VERSION_MAJOR}::Core
Hard-coded Dtk::Core / Dtk6::CoreForces specific DTK versionUse Dtk${DTK_VERSION_MAJOR}::Core
Missing DTK_VERSION_MAJORDTK won't map to Qt versionAdd variable mapping from Qt detection
Only using control without control.1Won'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

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