Agent Skills: qt-compatibility-build

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

UncategorizedID: re2zero/deepin-skills/qt-compatibility-build

Install this agent skill to your local

pnpm dlx add-skill https://github.com/re2zero/deepin-skills/tree/HEAD/qt-compatibility-build

Skill Files

Browse the full folder contents for qt-compatibility-build.

Download Skill

Loading file tree…

qt-compatibility-build/SKILL.md

Skill Metadata

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

| File | Deepin Version | Qt Version | |------|---------------|------------| | debian/control | V25 | Qt6 | | debian/control.1 | V20 | Qt5 |

Why: control (no suffix) = latest version (V25), control.1 (with suffix) = previous version (V20).

When to Use

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

| Task | Command/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.

Implementation

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

# 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):

find_package(Qt6 COMPONENTS Core Gui Widgets Network REQUIRED)
find_package(DtkWidget REQUIRED)

After (dynamic):

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):

target_link_libraries(mylib
    Dtk::Core
    Dtk::Gui
    Qt6::Network
)

After (dynamic):

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:

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:

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):

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

| Purpose | V25 (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 |

Common Mistakes

| Mistake | Why It's Wrong | Fix | |---------|----------------|-----| | Hard-coded Qt5::Core / Qt6::Core | Forces specific Qt version | Use Qt${QT_VERSION_MAJOR}::Core | | Hard-coded Dtk::Core / Dtk6::Core | Forces specific DTK version | Use Dtk${DTK_VERSION_MAJOR}::Core | | Missing DTK_VERSION_MAJOR | DTK won't map to Qt version | Add variable mapping from Qt detection | | Only using control without control.1 | Won't support V20 | Create both control files | | Using OR dependencies in single control | Should use separate files | Split into control and control.1 | | Only testing one Qt version | Both must work for dual support | Test V25 and V20 builds | | Not using find_package(QT NAMES Qt6 Qt5 ...) | Won't auto-detect both | Use 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