summaryrefslogtreecommitdiffstats
path: root/cmake/QtPublicCMakeHelpers.cmake
blob: ca091fcf9ac1eb4fe23e5ee36d696d8a026f0b00 (plain)
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
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause

# copy_if_different works incorrect in Windows if file size if bigger than 2GB.
# See https://gitlab.kitware.com/cmake/cmake/-/issues/23052 and QTBUG-99491 for details.
function(_qt_internal_copy_file_if_different_command out_var src_file dst_file)
    # The CMake version higher than 3.23 doesn't contain the issue
    if(CMAKE_HOST_WIN32 AND CMAKE_VERSION VERSION_LESS 3.23)
        set(${out_var} "${CMAKE_COMMAND}"
            "-DSRC_FILE_PATH=${src_file}"
            "-DDST_FILE_PATH=${dst_file}"
            -P "${_qt_6_config_cmake_dir}/QtCopyFileIfDifferent.cmake"
            PARENT_SCOPE
        )
    else()
        set(${out_var} "${CMAKE_COMMAND}"
            -E copy_if_different
            "${src_file}"
            "${dst_file}"
            PARENT_SCOPE
        )
    endif()
endfunction()

# The function checks if add_custom_command has the support of the DEPFILE argument.
function(_qt_internal_check_depfile_support out_var)
    if(CMAKE_GENERATOR MATCHES "Ninja" OR
        (CMAKE_VERSION VERSION_GREATER_EQUAL 3.20 AND CMAKE_GENERATOR MATCHES "Makefiles")
        OR (CMAKE_VERSION VERSION_GREATER_EQUAL 3.21
        AND (CMAKE_GENERATOR MATCHES "Xcode"
            OR (CMAKE_GENERATOR MATCHES "Visual Studio ([0-9]+)" AND CMAKE_MATCH_1 GREATER_EQUAL 12)
            )
        )
    )
        set(${out_var} TRUE)
    else()
        set(${out_var} FALSE)
    endif()
    set(${out_var} "${${out_var}}" PARENT_SCOPE)
endfunction()

# Checks if the path points to the cmake directory, like lib/cmake.
function(__qt_internal_check_path_points_to_cmake_dir result path)
    string(TOUPPER "${QT_CMAKE_EXPORT_NAMESPACE}" export_namespace_upper)
    if((INSTALL_LIBDIR AND path MATCHES "/${INSTALL_LIBDIR}/cmake$") OR
        (${export_namespace_upper}_INSTALL_LIBS AND
            path MATCHES "/${${export_namespace_upper}_INSTALL_LIBS}/cmake$") OR
        path MATCHES "/lib/cmake$"
    )
        set(${result} TRUE PARENT_SCOPE)
    else()
        set(${result} FALSE PARENT_SCOPE)
    endif()
endfunction()

# Creates a reverse path to prefix from possible cmake directories. Returns the unchanged path
# if it doesn't point to cmake directory.
function(__qt_internal_reverse_prefix_path_from_cmake_dir result cmake_path)
    string(TOUPPER "${QT_CMAKE_EXPORT_NAMESPACE}" export_namespace_upper)
    if(INSTALL_LIBDIR AND cmake_path MATCHES "(.+)/${INSTALL_LIBDIR}/cmake$")
        if(CMAKE_MATCH_1)
            set(${result} "${CMAKE_MATCH_1}" PARENT_SCOPE)
        endif()
    elseif(${export_namespace_upper}_INSTALL_LIBS AND
        cmake_path MATCHES "(.+)/${${export_namespace_upper}_INSTALL_LIBS}/cmake$")
        if(CMAKE_MATCH_1)
            set(${result} "${CMAKE_MATCH_1}" PARENT_SCOPE)
        endif()
    elseif(result MATCHES "(.+)/lib/cmake$")
        if(CMAKE_MATCH_1)
            set(${result} "${CMAKE_MATCH_1}" PARENT_SCOPE)
        endif()
    else()
        set(${result} "${cmake_path}" PARENT_SCOPE)
    endif()
endfunction()

# Returns the possible cmake directories based on prefix_path.
function(__qt_internal_get_possible_cmake_dirs out_paths prefix_path)
    set(${out_paths} "")

    if(EXISTS "${prefix_path}/lib/cmake")
        list(APPEND ${out_paths} "${prefix_path}/lib/cmake")
    endif()

    string(TOUPPER "${QT_CMAKE_EXPORT_NAMESPACE}" export_namespace_upper)
    set(next_path "${prefix_path}/${${export_namespace_upper}_INSTALL_LIBS}/cmake")
    if(${export_namespace_upper}_INSTALL_LIBS AND EXISTS "${next_path}")
        list(APPEND ${out_paths} "${next_path}")
    endif()

    set(next_path "${prefix_path}/${INSTALL_LIBDIR}/cmake")
    if(INSTALL_LIBDIR AND EXISTS "${next_path}")
        list(APPEND ${out_paths} "${next_path}")
    endif()

    list(REMOVE_DUPLICATES ${out_paths})
    set(${out_paths} "${${out_paths}}" PARENT_SCOPE)
endfunction()

# Collect additional package prefix paths to look for Qt packages, both from command line and the
# env variable ${prefixes_var}. The result is stored in ${out_var} and is a list of paths ending
# with "/lib/cmake".
function(__qt_internal_collect_additional_prefix_paths out_var prefixes_var)
    if(DEFINED "${out_var}")
        return()
    endif()

    set(additional_packages_prefix_paths "")

    set(additional_packages_prefixes "")
    if(${prefixes_var})
        list(APPEND additional_packages_prefixes ${${prefixes_var}})
    endif()
    if(DEFINED ENV{${prefixes_var}}
        AND NOT "$ENV{${prefixes_var}}" STREQUAL "")
        set(prefixes_from_env "$ENV{${prefixes_var}}")
        if(NOT CMAKE_HOST_WIN32)
            string(REPLACE ":" ";" prefixes_from_env "${prefixes_from_env}")
        endif()
        list(APPEND additional_packages_prefixes ${prefixes_from_env})
    endif()

    foreach(additional_path IN LISTS additional_packages_prefixes)
        file(TO_CMAKE_PATH "${additional_path}" additional_path)

        # The prefix paths need to end with lib/cmake to ensure the packages are found when
        # cross compiling. Search for REROOT_PATH_ISSUE_MARKER in the qt.toolchain.cmake file for
        # details.
        # We must pass the values via the PATHS options because the main find_package call uses
        # NO_DEFAULT_PATH, and thus CMAKE_PREFIX_PATH values are discarded.
        # CMAKE_FIND_ROOT_PATH values are not discarded and togegher with the PATHS option, it
        # ensures packages from additional prefixes are found.
        __qt_internal_check_path_points_to_cmake_dir(is_path_to_cmake "${additional_path}")
        if(is_path_to_cmake)
            list(APPEND additional_packages_prefix_paths "${additional_path}")
        else()
            __qt_internal_get_possible_cmake_dirs(additional_cmake_dirs "${additional_path}")
            list(APPEND additional_packages_prefix_paths ${additional_cmake_dirs})
        endif()
    endforeach()

    set("${out_var}" "${additional_packages_prefix_paths}" PARENT_SCOPE)
endfunction()

# Collects CMAKE_MODULE_PATH from QT_ADDITIONAL_PACKAGES_PREFIX_PATH
function(__qt_internal_collect_additional_module_paths)
    if(__qt_additional_module_paths_set)
        return()
    endif()
    foreach(prefix_path IN LISTS QT_ADDITIONAL_PACKAGES_PREFIX_PATH)
        __qt_internal_check_path_points_to_cmake_dir(is_path_to_cmake "${prefix_path}")
        if(is_path_to_cmake)
            list(APPEND CMAKE_MODULE_PATH "${prefix_path}/${QT_CMAKE_EXPORT_NAMESPACE}")
        else()
            __qt_internal_get_possible_cmake_dirs(additional_cmake_dirs "${additional_path}")
            list(TRANSFORM additional_cmake_dirs APPEND "/${QT_CMAKE_EXPORT_NAMESPACE}")
            list(APPEND CMAKE_MODULE_PATH ${additional_cmake_dirs})
        endif()
    endforeach()
    list(REMOVE_DUPLICATES CMAKE_MODULE_PATH)
    set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" PARENT_SCOPE)
    set(__qt_additional_module_paths_set TRUE PARENT_SCOPE)
endfunction()

# Take a list of prefix paths ending with "/lib/cmake", and return a list of absolute paths with
# "/lib/cmake" removed.
function(__qt_internal_prefix_paths_to_roots out_var prefix_paths)
    set(result "")
    foreach(path IN LISTS prefix_paths)
        __qt_internal_reverse_prefix_path_from_cmake_dir(path "${path}")
        list(APPEND result "${path}")
    endforeach()
    set("${out_var}" "${result}" PARENT_SCOPE)
endfunction()

# This function gets all targets below this directory
#
# Multi-value Arguments:
#     EXCLUDE list of target types that should be filtered from resulting list.
#
#     INCLUDE list of target types that should be filtered from resulting list.
#             EXCLUDE has higher priority than INCLUDE.
function(_qt_internal_collect_buildsystem_targets result dir)
    cmake_parse_arguments(arg "" "" "EXCLUDE;INCLUDE" ${ARGN})

    if(NOT _qt_internal_collect_buildsystem_targets_inner)
        set(${result} "")
        set(_qt_internal_collect_buildsystem_targets_inner TRUE)
    endif()

    set(forward_args "")
    if(arg_EXCLUDE)
        set(forward_args APPEND EXCLUDE ${arg_EXCLUDE})
    endif()

    if(arg_INCLUDE)
        set(forward_args APPEND INCLUDE ${arg_INCLUDE})
    endif()

    get_property(subdirs DIRECTORY "${dir}" PROPERTY SUBDIRECTORIES)

    # Make sure that we don't hit endless recursion when running qt-cmake-standalone-test on a
    # in-source test dir, where the currently processed directory lists itself in its SUBDIRECTORIES
    # property.
    # See https://bugreports.qt.io/browse/QTBUG-119998
    # and https://gitlab.kitware.com/cmake/cmake/-/issues/25489
    # Do it only when QT_INTERNAL_IS_STANDALONE_TEST is set, to avoid the possible slowdown when
    # processing many subdirectores when configuring all standalone tests rather than just one.
    if(QT_INTERNAL_IS_STANDALONE_TEST)
        list(REMOVE_ITEM subdirs "${dir}")
    endif()

    foreach(subdir IN LISTS subdirs)
        _qt_internal_collect_buildsystem_targets(${result} "${subdir}" ${forward_args})
    endforeach()
    get_property(sub_targets DIRECTORY "${dir}" PROPERTY BUILDSYSTEM_TARGETS)
    set(real_targets "")
    if(sub_targets)
        foreach(target IN LISTS sub_targets)
            get_target_property(target_type ${target} TYPE)
            if((NOT arg_INCLUDE OR target_type IN_LIST arg_INCLUDE) AND
                (NOT arg_EXCLUDE OR (NOT target_type IN_LIST arg_EXCLUDE)))
                list(APPEND real_targets ${target})
            endif()
        endforeach()
    endif()
    set(${result} ${${result}} ${real_targets} PARENT_SCOPE)
endfunction()

# Add a custom target ${target} that is *not* added to the default build target in a safe way.
# Dependencies must then be added with _qt_internal_add_phony_target_dependencies.
#
# What's "safe" in this context? For the Visual Studio generators, we cannot use add_dependencies,
# because this would enable the dependencies in the default build of the solution. See QTBUG-115166
# and upstream CMake issue #16668 for details. Instead, we record the dependencies (added with
# _qt_internal_add_phony_target_dependencies) and create the target at the end of the top-level
# directory scope.
#
# This only works if at least CMake 3.19 is used. Older CMake versions will trigger a warning that
# can be turned off with the variable ${WARNING_VARIABLE}.
#
# For other generators, this is just a call to add_custom_target, unless the target already exists,
# followed by add_dependencies.
#
# Use this function for targets that are not part of the default build, i.e. that should be
# triggered by the user.
#
# TARGET_CREATED_HOOK is the name of a function that is called after the target has been created.
# It takes the target's name as first and only argument.
#
# Example:
#     _qt_internal_add_phony_target(update_translations
#          WARNING_VARIABLE QT_NO_GLOBAL_LUPDATE_TARGET_CREATED_WARNING
#     )
#     _qt_internal_add_phony_target_dependencies(update_translations
#          narf_lupdate_zort_lupdate
#     )
#
function(_qt_internal_add_phony_target target)
    set(no_value_options "")
    set(single_value_options
        TARGET_CREATED_HOOK
        WARNING_VARIABLE
    )
    set(multi_value_options "")
    cmake_parse_arguments(PARSE_ARGV 0 arg
        "${no_value_options}" "${single_value_options}" "${multi_value_options}"
    )
    if("${arg_WARNING_VARIABLE}" STREQUAL "")
        message(FATAL_ERROR "WARNING_VARIABLE must be provided.")
    endif()
    if(CMAKE_GENERATOR MATCHES "^Visual Studio ")
        if(${CMAKE_VERSION} VERSION_LESS "3.19.0")
            if(NOT ${${arg_WARNING_VARIABLE}})
                message(WARNING
                    "Cannot create target ${target} with this CMake version. "
                    "Please upgrade to CMake 3.19.0 or newer. "
                    "Set ${WARNING_VARIABLE} to ON to disable this warning."
                )
            endif()
            return()
        endif()

        get_property(already_deferred GLOBAL PROPERTY _qt_target_${target}_creation_deferred)
        if(NOT already_deferred)
            cmake_language(EVAL CODE
                "cmake_language(DEFER DIRECTORY \"${CMAKE_SOURCE_DIR}\" CALL _qt_internal_add_phony_target_deferred \"${target}\")"
            )
            if(DEFINED arg_TARGET_CREATED_HOOK)
                set_property(GLOBAL
                    PROPERTY _qt_target_${target}_creation_hook ${arg_TARGET_CREATED_HOOK}
                )
            endif()
        endif()
        set_property(GLOBAL APPEND PROPERTY _qt_target_${target}_creation_deferred ON)
    else()
        if(NOT TARGET ${target})
            add_custom_target(${target})
            if(DEFINED arg_TARGET_CREATED_HOOK)
                if(CMAKE_VERSION VERSION_LESS "3.19")
                    set(incfile
                        "${CMAKE_CURRENT_BINARY_DIR}/.qt_internal_add_phony_target.cmake"
                    )
                    file(WRITE "${incfile}" "${arg_TARGET_CREATED_HOOK}(${target})")
                    include("${incfile}")
                    file(REMOVE "${incfile}")
                else()
                    cmake_language(CALL "${arg_TARGET_CREATED_HOOK}" "${target}")
                endif()
            endif()
        endif()
    endif()
endfunction()

# Adds dependencies to a custom target that has been created with
# _qt_internal_add_phony_target. See the docstring at _qt_internal_add_phony_target for
# more details.
function(_qt_internal_add_phony_target_dependencies target)
    set(dependencies ${ARGN})
    if(CMAKE_GENERATOR MATCHES "^Visual Studio ")
        set_property(GLOBAL APPEND PROPERTY _qt_target_${target}_dependencies ${dependencies})

        # Exclude the dependencies from the solution's default build to avoid them being enabled
        # accidentally should the user add another dependency to them.
        set_target_properties(${dependencies} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD ON)
    else()
        add_dependencies(${target} ${dependencies})
    endif()
endfunction()

# Hack for the Visual Studio generator. Create the custom target named ${target} and work
# around the lack of a working add_dependencies by calling 'cmake --build' for every dependency.
function(_qt_internal_add_phony_target_deferred target)
    get_property(target_dependencies GLOBAL PROPERTY _qt_target_${target}_dependencies)
    set(target_commands "")
    foreach(dependency IN LISTS target_dependencies)
        list(APPEND target_commands
            COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" -t ${dependency}
        )
    endforeach()
    add_custom_target(${target} ${target_commands})
    get_property(creation_hook GLOBAL PROPERTY _qt_target_${target}_creation_hook)
    if(creation_hook)
        cmake_language(CALL ${creation_hook} ${target})
    endif()
endfunction()

# The helper function that checks if module was included multiple times, and has the inconsistent
# set of targets that belong to the module. It's expected that either all 'targets' or none of them
# will be written to the 'targets_not_defined' variable, if the module was not or was
# searched before accordingly.
function(_qt_internal_check_multiple_inclusion targets_not_defined targets)
    set(targets_defined "")
    set(${targets_not_defined} "")
    set(expected_targets "")
    foreach(expected_target ${targets})
        list(APPEND expected_targets ${expected_target})
        if(NOT TARGET Qt::${expected_target})
            list(APPEND ${targets_not_defined} ${expected_target})
        endif()
        if(TARGET Qt::${expected_target})
            list(APPEND targets_defined ${expected_target})
        endif()
    endforeach()
    if("${targets_defined}" STREQUAL "${expected_targets}")
        set(${targets_not_defined} "" PARENT_SCOPE)
        return()
    endif()
    if(NOT "${targets_defined}" STREQUAL "")
        message(FATAL_ERROR "Some (but not all) targets in this export set were already defined."
            "\nTargets Defined: ${targets_defined}\nTargets not yet defined: "
            "${${targets_not_defined}}\n"
        )
    endif()
    set(${targets_not_defined} "${${targets_not_defined}}" PARENT_SCOPE)
endfunction()

# The function is used when creating version less targets using ALIASes.
function(_qt_internal_create_versionless_alias_targets targets install_namespace)
    foreach(target IN LISTS targets)
        add_library(Qt::${target} ALIAS ${install_namespace}::${target})
    endforeach()
endfunction()

# The function is used when creating version less targets from scratch but not using ALIASes.
# It assigns the known properties from the versioned targets to the versionless created in this
# function. This allows versionless targets mimic the versioned.
function(_qt_internal_create_versionless_targets targets install_namespace)
    set(known_interface_properties
        QT_MAJOR_VERSION
        AUTOMOC_MACRO_NAMES
        AUTOUIC_OPTIONS
        COMPILE_DEFINITIONS
        COMPILE_FEATURES
        COMPILE_OPTIONS
        CXX_MODULE_SETS
        HEADER_SETS
        HEADER_SETS_TO_VERIFY
        INCLUDE_DIRECTORIES
        LINK_DEPENDS
        LINK_DIRECTORIES
        LINK_LIBRARIES
        LINK_LIBRARIES_DIRECT
        LINK_LIBRARIES_DIRECT_EXCLUDE
        LINK_OPTIONS
        POSITION_INDEPENDENT_CODE
        PRECOMPILE_HEADERS
        SOURCES
        SYSTEM_INCLUDE_DIRECTORIES
    )

    set(known_qt_exported_properties
        MODULE_PLUGIN_TYPES
        QT_DISABLED_PRIVATE_FEATURES
        QT_DISABLED_PUBLIC_FEATURES
        QT_ENABLED_PRIVATE_FEATURES
        QT_ENABLED_PUBLIC_FEATURES
        QT_QMAKE_PRIVATE_CONFIG
        QT_QMAKE_PUBLIC_CONFIG
        QT_QMAKE_PUBLIC_QT_CONFIG
    )

    set(known_qt_exported_properties_interface_allowed
        _qt_config_module_name
        _qt_is_public_module
        _qt_module_has_headers
        _qt_module_has_private_headers
        _qt_module_has_public_headers
        _qt_module_has_qpa_headers
        _qt_module_has_rhi_headers
        _qt_module_include_name
        _qt_module_interface_name
        _qt_package_name
        _qt_package_version
        _qt_private_module_target_name
    )

    set(supported_target_types STATIC_LIBRARY MODULE_LIBRARY SHARED_LIBRARY OBJECT_LIBRARY
        INTERFACE_LIBRARY)

    foreach(target IN LISTS targets)
        if(NOT TARGET ${install_namespace}::${target})
            message(FATAL_ERROR "${install_namespace}::${target} is not a target, can not extend"
                " an alias target")
        endif()

        get_target_property(type ${install_namespace}::${target} TYPE)
        if(NOT type)
            message(FATAL_ERROR "Cannot get the ${install_namespace}::${target} target type.")
        endif()

        if(NOT "${type}" IN_LIST supported_target_types)
            message(AUTHOR_WARNING "${install_namespace}::${target} requires the versionless"
                " target creation, but it has incompatible type ${type}.")
            continue()
        endif()

        string(REPLACE "_LIBRARY" "" creation_type "${type}")
        add_library(Qt::${target} ${creation_type} IMPORTED)

        if(NOT "${type}" STREQUAL "INTERFACE_LIBRARY")
            foreach(config "" _RELEASE _DEBUG _RELWITHDEBINFO _MINSIZEREL)
                get_target_property(target_imported_location
                        ${install_namespace}::${target} IMPORTED_LOCATION${config})
                if(NOT target_imported_location)
                    if("${config}" STREQUAL "")
                        message(FATAL_ERROR "Cannot create versionless target for"
                            " ${install_namespace}::${target}. IMPORTED_LOCATION property is "
                            "missing."
                        )
                    else()
                        continue()
                    endif()
                endif()
                set_property(TARGET Qt::${target} PROPERTY
                    IMPORTED_LOCATION${config} "${target_imported_location}")
            endforeach()

            foreach(property IN LISTS known_qt_exported_properties)
                get_target_property(exported_property_value
                    ${install_namespace}::${target} ${property})
                if(exported_property_value)
                    set_property(TARGET Qt::${target} APPEND PROPERTY
                        ${property} "${exported_property_value}")
                endif()
            endforeach()
        endif()

        foreach(property IN LISTS known_interface_properties)
            get_target_property(interface_property_value
                ${install_namespace}::${target} INTERFACE_${property})
            if(interface_property_value)
                set_property(TARGET Qt::${target} APPEND PROPERTY
                    INTERFACE_${property} "${interface_property_value}")
            endif()
        endforeach()

        foreach(property IN LISTS known_qt_exported_properties_interface_allowed)
            get_target_property(exported_property_value
                ${install_namespace}::${target} ${property})
            if(exported_property_value)
                set_property(TARGET Qt::${target} APPEND PROPERTY
                    ${property} "${exported_property_value}")
            endif()
        endforeach()

        set_property(TARGET Qt::${target} PROPERTY _qt_is_versionless_target TRUE)
    endforeach()
endfunction()