File: ECMQmlModule6.cmake

package info (click to toggle)
kf6-extra-cmake-modules 6.22.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,608 kB
  • sloc: python: 668; cpp: 330; ansic: 291; xml: 182; sh: 62; makefile: 8
file content (277 lines) | stat: -rw-r--r-- 10,917 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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#
# SPDX-FileCopyrightText: 2023 Arjen Hiemstra <ahiemstra@heimr.nl>
#
# SPDX-License-Identifier: BSD-3-Clause

# Qt 6 implementation of ECMQmlModule

cmake_policy(VERSION 3.16)

set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS ON)
find_package(Qt6 COMPONENTS Core Qml CONFIG)
unset(QT_NO_CREATE_VERSIONLESS_FUNCTIONS)

if (NOT TARGET Qt6::Qml)
    message(WARNING "Target Qt6::Qml was not found. ECMQmlModule requires the QML module when building with Qt 6")
    return()
endif()

# Match KDECMakeSettings' RUNTIME_OUTPUT_DIRECTORY so that we can load plugins from
# the build directory when running tests. But only if we don't yet have an output directory.
if (NOT QT_QML_OUTPUT_DIRECTORY)
    set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
endif()

# Stop warning about a changed import prefix.
qt6_policy(SET QTP0001 NEW)

option(ECM_QMLCACHE_UNITY_BUILD "Perform unity builds for source files produced by qmlcachegen." OFF)

# Internal, puts all qmlcachegen cpp source files into the same unity build group
function(_ecm_qml_module_setup_unity_group ARG_TARGET)
    get_target_property(_sources ${ARG_TARGET} SOURCES)
    foreach(_src ${_sources})
        string(REGEX MATCH "\\.rcc/qmlcache/" _is_qmlcache ${_src})
        if (_is_qmlcache)
            set_source_files_properties(${_src} PROPERTIES UNITY_GROUP "qmlcache")
        endif()
    endforeach()
endfunction()

function(ecm_add_qml_module ARG_TARGET)
    cmake_parse_arguments(PARSE_ARGV 1 ARG "NO_PLUGIN;QT_NO_PLUGIN;GENERATE_PLUGIN_SOURCE" "URI;VERSION;CLASSNAME;OUTPUT_TARGETS" "")

    if ("${ARG_TARGET}" STREQUAL "")
        message(FATAL_ERROR "ecm_add_qml_module called without a valid target name.")
    endif()

    if ("${ARG_URI}" STREQUAL "")
        message(FATAL_ERROR "ecm_add_qml_module called without a valid module URI.")
    endif()

    string(FIND "${ARG_URI}" " " "_space")
    if (${_space} GREATER_EQUAL 0)
        message(FATAL_ERROR "ecm_add_qml_module called without a valid module URI.")
    endif()

    set(_arguments ${ARG_TARGET} URI ${ARG_URI})

    if (ARG_VERSION)
        list(APPEND _arguments VERSION ${ARG_VERSION})
    endif()

    if (ARG_CLASSNAME)
        message(AUTHOR_WARNING "The CLASSNAME argument to ecm_add_qml_module is deprecated for Qt 6; Use CLASS_NAME instead.")
        list(APPEND _arguments CLASS_NAME ${ARG_CLASSNAME})
    endif()

    if (ARG_NO_PLUGIN)
        message(AUTHOR_WARNING "The NO_PLUGIN argument to ecm_add_qml_module is deprecated for Qt 6; For Qt 6 QML modules always require a plugin library. Use GENERATE_PLUGIN_SOURCE instead. If you wish to use the NO_PLUGIN feature from qt_add_qml_module, use QT_NO_PLUGIN.")
        set(ARG_GENERATE_PLUGIN_SOURCE TRUE)
    endif()

    if (ARG_QT_NO_PLUGIN)
        list(APPEND _arguments NO_PLUGIN)
    endif()

    if (NOT ARG_GENERATE_PLUGIN_SOURCE)
        list(APPEND _arguments NO_GENERATE_PLUGIN_SOURCE NO_PLUGIN_OPTIONAL)
    endif()

    if (NOT TARGET ${ARG_TARGET})
        list(APPEND _arguments PLUGIN_TARGET ${ARG_TARGET})
        if (BUILD_SHARED_LIBS)
            list(APPEND _arguments SHARED)
        else()
            list(APPEND _arguments STATIC)
        endif()
    endif()

    # make qmlimportscanner also find QML modules installed
    # outside of the Qt prefix
    if(IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/${KDE_INSTALL_QMLDIR}")
        list(APPEND _import_paths "${CMAKE_INSTALL_PREFIX}/${KDE_INSTALL_QMLDIR}")
    endif()
    foreach(_prefix ${CMAKE_PREFIX_PATH})
        if(IS_DIRECTORY "${_prefix}/${KDE_INSTALL_QMLDIR}")
            list(APPEND _import_paths "${_prefix}/${KDE_INSTALL_QMLDIR}")
        endif()
    endforeach()
    list(APPEND _arguments IMPORT_PATH ${_import_paths})

    list(APPEND _arguments ${ARG_UNPARSED_ARGUMENTS})

    qt6_add_qml_module(${_arguments} OUTPUT_TARGETS _out_targets)
    if (ARG_OUTPUT_TARGETS)
        set(${ARG_OUTPUT_TARGETS} ${_out_targets} PARENT_SCOPE)
    endif()
    set_target_properties(${ARG_TARGET} PROPERTIES _ecm_output_targets "${_out_targets}")

    # KDECMakeSettings sets the prefix of MODULE targets to empty but Qt will
    # not load a QML plugin without prefix. So we need to force it here.
    qt6_query_qml_module(${ARG_TARGET} PLUGIN_TARGET _plugin_target)
    if (NOT WIN32 AND TARGET ${_plugin_target})
        set_target_properties(${_plugin_target} PROPERTIES PREFIX "lib")
    endif()

    option(VERBOSE_QML_COMPILER "Enable verbose output for qmlcachegen" OFF)

    if (VERBOSE_QML_COMPILER)
        set_target_properties(${ARG_TARGET} PROPERTIES
            QT_QMLCACHEGEN_ARGUMENTS "--verbose"
        )
    endif()

    _ecm_qml_module_setup_unity_group(${ARG_TARGET})
    set_target_properties(${ARG_TARGET} PROPERTIES UNITY_BUILD_MODE GROUP)
    set_target_properties(${ARG_TARGET} PROPERTIES UNITY_BUILD ${ECM_QMLCACHE_UNITY_BUILD})
endfunction()

function(ecm_add_qml_module_dependencies ARG_TARGET)
    message(AUTHOR_WARNING "ecm_add_qml_module_dependencies is deprecated for Qt 6; use the DEPENDENCIES argument to ecm_add_qml_module() instead.")
endfunction()

function(ecm_target_qml_sources ARG_TARGET)
    cmake_parse_arguments(PARSE_ARGV 1 ARG "PRIVATE" "VERSION;PATH;OUTPUT_TARGETS" "SOURCES")

    if ("${ARG_SOURCES}" STREQUAL "")
        message(FATAL_ERROR "ecm_target_qml_sources called without required argument SOURCES")
    endif()

    if (ARG_VERSION)
        set_source_files_properties(${ARG_SOURCES} PROPERTIES QT_QML_SOURCE_VERSIONS "${ARG_VERSION}")
    endif()

    if (ARG_PRIVATE)
        set_source_files_properties(${ARG_SOURCES} PROPERTIES QT_QML_INTERNAL_TYPE TRUE)
    endif()

    set(_QML_FILES)
    set(_RESOURCES)
    foreach(_path ${ARG_SOURCES})
        get_filename_component(_file "${_path}" NAME)
        get_filename_component(_ext "${_path}" EXT)
        set(_resource_alias "${_file}")
        if (ARG_PATH)
            set(_resource_alias "${ARG_PATH}/${_file}")
        endif()
        set_source_files_properties("${_path}" PROPERTIES QT_RESOURCE_ALIAS "${_resource_alias}")
        if ("${_ext}" MATCHES "(.qml|.js|.mjs)")
            list(APPEND _QML_FILES "${_path}")
        else()
            list(APPEND _RESOURCES "${_path}")
        endif()
    endforeach()

    if(_QML_FILES)
        qt6_target_qml_sources(${ARG_TARGET} QML_FILES ${_QML_FILES} OUTPUT_TARGETS _out_targets_qml ${ARG_UNPARSED_ARGUMENTS})
    endif()
    if(_RESOURCES)
        qt6_target_qml_sources(${ARG_TARGET} RESOURCES ${_RESOURCES} OUTPUT_TARGETS _out_targets_qrc ${ARG_UNPARSED_ARGUMENTS})
    endif()
    list(APPEND _out_targets "${_out_targets_qml}" "${_out_targets_qrc}")
    if (ARG_OUTPUT_TARGETS)
        set(${ARG_OUTPUT_TARGETS} ${_out_targets} PARENT_SCOPE)
    endif()
    get_target_property(_ecm_output_targets ${ARG_TARGET} _ecm_output_targets)
    list(APPEND _ecm_output_targets ${_out_targets})
    set_target_properties(${ARG_TARGET} PROPERTIES _ecm_output_targets "${_ecm_output_targets}")

    _ecm_qml_module_setup_unity_group(${ARG_TARGET})
endfunction()

function(ecm_finalize_qml_module ARG_TARGET)
    cmake_parse_arguments(PARSE_ARGV 1 ARG "" "DESTINATION;VERSION;EXPORT" "")

    if (NOT ARG_DESTINATION)
        set(ARG_DESTINATION "${KDE_INSTALL_QMLDIR}")
    endif()

    if ("${ARG_DESTINATION}" STREQUAL "")
        message(FATAL_ERROR "ecm_finalize_qml_module called without required argument DESTINATION and KDE_INSTALL_QMLDIR is not set")
    endif()

    if (NOT ARG_VERSION)
        set(ARG_VERSION "${PROJECT_VERSION}")
    endif()

    # This is effectively a workaround for missing upstream API, see QTBUG-100102

    qt6_query_qml_module(${ARG_TARGET}
        URI module_uri
        VERSION module_version
        PLUGIN_TARGET module_plugin_target
        TARGET_PATH module_target_path
        QMLDIR module_qmldir
        TYPEINFO module_typeinfo
        QML_FILES module_qml_files
        RESOURCES module_resources
    )

    set(module_dir "${ARG_DESTINATION}/${module_target_path}")

    if (NOT TARGET "${module_plugin_target}")
        return()
    endif()

    if (ARG_EXPORT AND NOT BUILD_SHARED_LIBS)
        set(_install_targets_args EXPORT "${ARG_EXPORT}")
    endif()
    install(TARGETS "${module_plugin_target}"
        ${_install_targets_args}
        LIBRARY DESTINATION "${module_dir}"
        RUNTIME DESTINATION "${module_dir}"
    )

    # Install dependent targets created for static builds
    get_target_property(_ecm_output_targets ${ARG_TARGET} _ecm_output_targets)
    if (_ecm_output_targets AND ARG_EXPORT)
        install(TARGETS ${_ecm_output_targets}
            EXPORT ${ARG_EXPORT}
            LIBRARY DESTINATION "${module_dir}"
            RUNTIME DESTINATION "${module_dir}"
            OBJECTS DESTINATION "${module_dir}"
        )
    endif()

    # Install the QML module meta information.
    install(FILES "${module_qmldir}"   DESTINATION "${module_dir}")
    install(FILES "${module_typeinfo}" DESTINATION "${module_dir}")

    # Install QML files, possibly renamed.
    # see Kirigami::StyleSelector::resolveFileX, on Android we never use QML files from disk
    # but rather always the ones from qrc
    if (NOT ANDROID)
        list(LENGTH module_qml_files num_files)
        if (NOT "${module_qml_files}" MATCHES "NOTFOUND" AND ${num_files} GREATER 0)
            qt6_query_qml_module(${ARG_TARGET} QML_FILES_DEPLOY_PATHS qml_files_deploy_paths)

            math(EXPR last_index "${num_files} - 1")
            foreach(i RANGE 0 ${last_index})
                list(GET module_qml_files       ${i} src_file)
                list(GET qml_files_deploy_paths ${i} deploy_path)
                get_filename_component(dst_name "${deploy_path}" NAME)
                get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
                install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}")
            endforeach()
        endif()
    endif()

    # Install resources, possibly renamed.
    list(LENGTH module_resources num_files)
    if (NOT "${module_resources}" MATCHES "NOTFOUND" AND ${num_files} GREATER 0)
        qt6_query_qml_module(${ARG_TARGET} RESOURCES_DEPLOY_PATHS resources_deploy_paths)

        math(EXPR last_index "${num_files} - 1")
        foreach(i RANGE 0 ${last_index})
            list(GET module_resources       ${i} src_file)
            list(GET resources_deploy_paths ${i} deploy_path)
            get_filename_component(dst_name "${deploy_path}" NAME)
            get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
            install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}")
        endforeach()
    endif()

    file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}-kde-qmlmodule.version" CONTENT "${ARG_VERSION}\n")
    install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}-kde-qmlmodule.version" DESTINATION "${module_dir}" RENAME "kde-qmlmodule.version")
endfunction()