File: QtLinkage.cmake

package info (click to toggle)
martchus-qtutilities 6.15.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 780 kB
  • sloc: cpp: 5,908; xml: 37; sh: 25; ansic: 12; makefile: 12
file content (221 lines) | stat: -rw-r--r-- 9,216 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
cmake_minimum_required(VERSION 3.17.0 FATAL_ERROR)

# defines helper to link against Qt dynamically or statically

# prevent multiple inclusion
if (DEFINED QT_LINKAGE_DETERMINED)
    return()
endif ()
set(QT_LINKAGE_DETERMINED ON)

# include validate_visibility from c++utilities' 3rdParty module
include(3rdParty)

# allow switching the Qt and KDE Frameworks version
set(QT_PACKAGE_PREFIX
    "Qt5"
    CACHE STRING "specifies the prefix for Qt packages")
set(KF_PACKAGE_PREFIX
    "KF5"
    CACHE STRING "specifies the prefix for KDE Frameworks packages")

# determine the minimum Qt version
if (NOT META_QT_VERSION)
    if (META_QT5_VERSION)
        # use deprecated META_QT5_VERSION variable (for compatibility)
        set(META_QT_VERSION "${META_QT5_VERSION}")
    else ()
        # require Qt 5.6 or higher by default
        set(META_QT_VERSION 5.6)
    endif ()
endif ()

# avoid "add_custom_target cannot create target "apk" because another target…" errors produced by Qt's Android support module
# (which can not cope with Qt CMake modules already pulled in by a dependency)
if (ANDROID AND NOT ${PROJECT_NAME}-MultiAbiBuild)
    set(${PROJECT_NAME}-MultiAbiBuild ON)
endif ()

# define function for using Qt and KDE Frameworks modules and static plugins
macro (use_qt_module)
    # parse arguments
    set(OPTIONAL_ARGS ONLY_PLUGINS PLUGINS_OPTIONAL)
    set(ONE_VALUE_ARGS PREFIX MODULE VISIBILITY LIBRARIES_VARIABLE)
    set(MULTI_VALUE_ARGS TARGETS PLUGINS)
    cmake_parse_arguments(ARGS "${OPTIONAL_ARGS}" "${ONE_VALUE_ARGS}" "${MULTI_VALUE_ARGS}" ${ARGN})

    # validate values
    if (NOT ARGS_PREFIX)
        message(FATAL_ERROR "use_qt_module called without PREFIX.")
    endif ()
    if (NOT ARGS_MODULE)
        message(FATAL_ERROR "use_qt_module called without MODULE.")
    endif ()
    if (ARGS_VISIBILITY)
        validate_visibility(${ARGS_VISIBILITY})
    else ()
        set(ARGS_VISIBILITY PRIVATE)
    endif ()
    if (NOT ARGS_LIBRARIES_VARIABLE)
        set(ARGS_LIBRARIES_VARIABLE "${ARGS_VISIBILITY}_LIBRARIES")
    endif ()
    if (NOT ARGS_TARGETS)
        if (${MODULE}_MODULE_TARGETS)
            set(ARGS_TARGETS "${${MODULE}_MODULE_TARGETS}")
        else ()
            set(ARGS_TARGETS "${ARGS_PREFIX}::${ARGS_MODULE}")
        endif ()
    endif ()
    if (ARGS_ONLY_PLUGINS AND NOT ARGS_PLUGINS)
        message(FATAL_ERROR "ONLY_PLUGINS specified but no plugins.")
    endif ()

    # find and use module
    if (NOT ONLY_PLUGINS)
        find_package("${ARGS_PREFIX}${ARGS_MODULE}" "${META_QT_VERSION}" REQUIRED)
        foreach (TARGET ${ARGS_TARGETS})
            if (NOT TARGET "${TARGET}")
                message(FATAL_ERROR "The CMake module ${ARGS_PREFIX}${ARGS_MODULE} does not provide the target ${TARGET}.")
            endif ()
            if ("${TARGET}" IN_LIST "${ARGS_LIBRARIES_VARIABLE}")
                continue()
            endif ()
            set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};${TARGET}")
            set("PKG_CONFIG_${ARGS_PREFIX}_${ARGS_MODULE}" "${ARGS_PREFIX}${ARGS_MODULE}")
            message(STATUS "Linking ${META_TARGET_NAME} against Qt module ${TARGET}.")

            # hack for "StaticQt5": re-assign INTERFACE_LINK_LIBRARIES_RELEASE to INTERFACE_LINK_LIBRARIES
            get_target_property("${ARGS_MODULE}_INTERFACE_LINK_LIBRARIES_RELEASE" "${TARGET}"
                                INTERFACE_LINK_LIBRARIES_RELEASE)
            if ("${ARGS_MODULE}_INTERFACE_LINK_LIBRARIES_RELEASE")
                set_target_properties("${TARGET}" PROPERTIES INTERFACE_LINK_LIBRARIES
                                                             "${${ARGS_MODULE}_INTERFACE_LINK_LIBRARIES_RELEASE}")
            endif ()
        endforeach ()
    endif ()

    # find and use plugins
    foreach (PLUGIN ${ARGS_PLUGINS})
        set(PLUGIN_TARGET "${ARGS_PREFIX}::Q${PLUGIN}Plugin")
        if (NOT TARGET "${PLUGIN_TARGET}")
            find_package("${ARGS_PREFIX}${ARGS_MODULE}" "${META_QT_VERSION}" REQUIRED)
        endif ()
        if (NOT TARGET "${PLUGIN_TARGET}"
            AND PLUGIN MATCHES "Svg.*"
            AND ARGS_MODULE STREQUAL "Svg")
            # look for Svg plugins within the Gui module's directory as well
            find_package("${ARGS_PREFIX}Gui" "${META_QT_VERSION}" REQUIRED)
            set(PLUGIN_CONFIG "${${ARGS_PREFIX}Gui_DIR}/${ARGS_PREFIX}Q${PLUGIN}PluginConfig.cmake")
            if (EXISTS "${PLUGIN_CONFIG}")
                include("${PLUGIN_CONFIG}")
            endif ()
        endif ()
        if (NOT TARGET "${PLUGIN_TARGET}")
            if (NOT PLUGINS_OPTIONAL)
                continue()
            endif ()
            message(
                FATAL_ERROR
                    "The ${ARGS_PREFIX}${ARGS_MODULE} package does not provide the target ${ARGS_PREFIX}::Q${PLUGIN}Plugin.")
        endif ()
        if ("${PLUGIN_TARGET}" IN_LIST "${ARGS_LIBRARIES_VARIABLE}")
            continue()
        endif ()
        set("${ARGS_LIBRARIES_VARIABLE}" "${${ARGS_LIBRARIES_VARIABLE}};${ARGS_PREFIX}::Q${PLUGIN}Plugin")
        message(STATUS "Linking ${META_TARGET_NAME} against Qt plugin ${ARGS_PREFIX}::Q${PLUGIN}Plugin.")
    endforeach ()

    # unset variables (can not simply use a function because Qt's variables need to be exported)
    foreach (ARGUMENT ${OPTIONAL_ARGS} ${ONE_VALUE_ARGS} ${MULTI_VALUE_ARGS})
        unset(ARGS_${ARGUMENT})
    endforeach ()
endmacro ()

# define function to make Qt variable available; queries qmake or uses variables provided by Qt 6
function (query_qmake_variable QMAKE_VARIABLE)
    # prevent queries for variables already known
    if (NOT "${${QMAKE_VARIABLE}}" STREQUAL "")
        return()
    endif ()

    # check configuration variables provided by Qt 6
    if (QMAKE_VARIABLE MATCHES "QT_(.*)")
        set(VARIABLE_NAME "${CMAKE_MATCH_1}")
        if (QT6_${VARIABLE_NAME})
            set(VARIABLE_NAME QT6_${VARIABLE_NAME})
        endif ()
        if (NOT "${${VARIABLE_NAME}}" STREQUAL "")
            set("${QMAKE_VARIABLE}"
                "${${VARIABLE_NAME}}"
                PARENT_SCOPE)
            message(STATUS "Qt variable ${QMAKE_VARIABLE} taken from ${VARIABLE_NAME}: ${${VARIABLE_NAME}}")
            return()
        endif ()
    endif ()

    # execute qmake
    get_target_property(QMAKE_BIN "${QT_QMAKE_TARGET}" IMPORTED_LOCATION)
    execute_process(
        COMMAND "${QMAKE_BIN}" -query "${QMAKE_VARIABLE}"
        RESULT_VARIABLE "${QMAKE_VARIABLE}_RESULT"
        OUTPUT_VARIABLE "${QMAKE_VARIABLE}")
    if (NOT "${${QMAKE_VARIABLE}_RESULT}" STREQUAL 0 OR "${${QMAKE_VARIABLE}}" STREQUAL "")
        message(
            FATAL_ERROR
                "Unable to read qmake variable ${QMAKE_VARIABLE} via \"${QMAKE_BIN} -query ${QMAKE_VARIABLE}\"; output was \"${${QMAKE_VARIABLE}}\"."
        )
    endif ()

    # remove new-line character at the end
    string(REGEX REPLACE "\n$" "" "${QMAKE_VARIABLE}" "${${QMAKE_VARIABLE}}")

    # export variable to parent scope
    set("${QMAKE_VARIABLE}"
        "${${QMAKE_VARIABLE}}"
        PARENT_SCOPE)
    message(STATUS "Qt variable ${QMAKE_VARIABLE} queried from qmake: ${${QMAKE_VARIABLE}}")
endfunction ()

# define function to make Qt variable available, resolving relative paths via CMAKE_FIND_ROOT_PATH
function (query_qmake_variable_path QMAKE_VARIABLE)
    # query the variable itself
    query_qmake_variable("${QMAKE_VARIABLE}")
    set(VARIABLE_VALUE "${${QMAKE_VARIABLE}}")
    if (NOT VARIABLE_VALUE)
        message(WARNING "Unable to resolve Qt variable ${QMAKE_VARIABLE}: it is empty")
        return()
    endif ()

    # pass the variable as-is if it points to an existing dir/file
    if (EXISTS "${VARIABLE_VALUE}")
        get_filename_component(VARIABLE_VALUE "${VARIABLE_VALUE}" REALPATH)
        message(STATUS "Qt variable ${QMAKE_VARIABLE} resolved to path: ${VARIABLE_VALUE}")
        set("${QMAKE_VARIABLE}"
            "${VARIABLE_VALUE}"
            PARENT_SCOPE)
        return()
    endif ()

    # assume VARIABLE_VALUE is relative within CMAKE_FIND_ROOT_PATH, e.g. QT_INSTALL_TRANSLATIONS might be set to
    # "share/qt6/translations"
    if ("${CMAKE_VERSION}" VERSION_LESS "3.12.0")
        message(WARNING "Unable to resolve Qt variable ${QMAKE_VARIABLE} to an existing path, try using CMake 3.12 or newer")
        return() # skip if CMake version too old like on Leap 15.1
    endif ()
    foreach (ROOT_PATH ${CMAKE_FIND_ROOT_PATH} "")
        foreach (PREFIX_PATH ${CMAKE_INSTALL_PREFIX} ${CMAKE_PREFIX_PATH} ${CMAKE_SYSTEM_PREFIX_PATH} "")
            string(JOIN "/" FULL_PATH ${ROOT_PATH} ${PREFIX_PATH} ${VARIABLE_VALUE})
            if (EXISTS "${FULL_PATH}")
                set("${QMAKE_VARIABLE}"
                    "${FULL_PATH}"
                    PARENT_SCOPE)
                message(STATUS "Qt variable ${QMAKE_VARIABLE} resolved to path: ${FULL_PATH}")
                return()
            else ()
                list(APPEND CHECKED_PATHS "${FULL_PATH}")
            endif ()
        endforeach ()
    endforeach ()
    message(
        WARNING "Unable to resolve Qt variable ${QMAKE_VARIABLE} to an existing path, was checking for: ${CHECKED_PATHS}")
endfunction ()