summaryrefslogtreecommitdiffstats
path: root/src/corelib/Qt6CoreMacros.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/Qt6CoreMacros.cmake')
-rw-r--r--src/corelib/Qt6CoreMacros.cmake3021
1 files changed, 2652 insertions, 369 deletions
diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake
index fc8ae6a74f..f55e32a7cf 100644
--- a/src/corelib/Qt6CoreMacros.cmake
+++ b/src/corelib/Qt6CoreMacros.cmake
@@ -1,34 +1,6 @@
-#=============================================================================
# Copyright 2005-2011 Kitware, Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# * Neither the name of Kitware, Inc. nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#=============================================================================
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
######################################
#
@@ -36,8 +8,6 @@
#
######################################
-include(CMakeParseArguments)
-
set(__qt_core_macros_module_base_dir "${CMAKE_CURRENT_LIST_DIR}")
# macro used to create the names of output files preserving relative dirs
@@ -104,7 +74,8 @@ macro(_qt_internal_get_moc_flags _moc_flags)
endmacro()
# helper macro to set up a moc rule
-function(_qt_internal_create_moc_command infile outfile moc_flags moc_options moc_target moc_depends)
+function(_qt_internal_create_moc_command infile outfile moc_flags moc_options
+ moc_target moc_depends out_json_file)
# Pass the parameters in a file. Set the working directory to
# be that containing the parameters file and reference it by
# just the file name. This is necessary because the moc tool on
@@ -117,36 +88,64 @@ function(_qt_internal_create_moc_command infile outfile moc_flags moc_options mo
endif()
set (_moc_parameters_file ${outfile}_parameters)
set (_moc_parameters ${moc_flags} ${moc_options} -o "${outfile}" "${infile}")
- string (REPLACE ";" "\n" _moc_parameters "${_moc_parameters}")
+ if(out_json_file)
+ list(APPEND _moc_parameters --output-json)
+ set(extra_output_files "${outfile}.json")
+ set(${out_json_file} "${extra_output_files}" PARENT_SCOPE)
+ endif()
if(moc_target)
- set(_moc_parameters_file ${_moc_parameters_file}$<$<BOOL:$<CONFIGURATION>>:_$<CONFIGURATION>>)
+ set(_moc_parameters_file ${_moc_parameters_file}$<$<BOOL:$<CONFIG>>:_$<CONFIG>>)
set(targetincludes "$<TARGET_PROPERTY:${moc_target},INCLUDE_DIRECTORIES>")
set(targetdefines "$<TARGET_PROPERTY:${moc_target},COMPILE_DEFINITIONS>")
- set(targetincludes "$<$<BOOL:${targetincludes}>:-I$<JOIN:${targetincludes},\n-I>\n>")
- set(targetdefines "$<$<BOOL:${targetdefines}>:-D$<JOIN:${targetdefines},\n-D>\n>")
+ set(targetincludes "$<$<BOOL:${targetincludes}>:-I$<JOIN:${targetincludes},;-I>>")
+ set(targetdefines "$<$<BOOL:${targetdefines}>:-D$<JOIN:${targetdefines},;-D>>")
+ set(_moc_parameters_list_without_genex)
+ set(_moc_parameters_list_with_genex)
+ foreach(_moc_parameter ${_moc_parameters})
+ if(_moc_parameter MATCHES "\\\$<")
+ list(APPEND _moc_parameters_list_with_genex ${_moc_parameter})
+ else()
+ list(APPEND _moc_parameters_list_without_genex ${_moc_parameter})
+ endif()
+ endforeach()
+
+ string(REPLACE ">" "$<ANGLE-R>" _moc_escaped_parameters "${_moc_parameters_list_without_genex}")
+ string(REPLACE "," "$<COMMA>" _moc_escaped_parameters "${_moc_escaped_parameters}")
+ string(REPLACE ";" "$<SEMICOLON>" _moc_escaped_parameters "${_moc_escaped_parameters}")
+ set(concatenated "$<$<BOOL:${targetincludes}>:${targetincludes};>$<$<BOOL:${targetdefines}>:${targetdefines};>$<$<BOOL:${_moc_escaped_parameters}>:${_moc_escaped_parameters};>")
+
+ list(APPEND concatenated ${_moc_parameters_list_with_genex})
+ set(concatenated "$<FILTER:$<REMOVE_DUPLICATES:${concatenated}>,EXCLUDE,^-[DI]$>")
+ set(concatenated "$<JOIN:${concatenated},\n>")
file (GENERATE
OUTPUT ${_moc_parameters_file}
- CONTENT "${targetdefines}${targetincludes}${_moc_parameters}\n"
+ CONTENT "${concatenated}"
)
+ set(concatenated)
set(targetincludes)
set(targetdefines)
else()
+ string (REPLACE ";" "\n" _moc_parameters "${_moc_parameters}")
file(WRITE ${_moc_parameters_file} "${_moc_parameters}\n")
endif()
set(_moc_extra_parameters_file @${_moc_parameters_file})
- add_custom_command(OUTPUT ${outfile}
+ add_custom_command(OUTPUT ${outfile} ${extra_output_files}
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc ${_moc_extra_parameters_file}
DEPENDS ${infile} ${moc_depends}
${_moc_working_dir}
VERBATIM)
set_source_files_properties(${infile} PROPERTIES SKIP_AUTOMOC ON)
- set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOMOC ON)
- set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOUIC ON)
+ set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOMOC ON
+ SKIP_AUTOUIC ON
+ )
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.27")
+ set_source_files_properties(${outfile} PROPERTIES SKIP_LINTING ON)
+ endif()
endfunction()
function(qt6_generate_moc infile outfile )
@@ -160,7 +159,10 @@ function(qt6_generate_moc infile outfile )
if ("x${ARGV2}" STREQUAL "xTARGET")
set(moc_target ${ARGV3})
endif()
- _qt_internal_create_moc_command(${abs_infile} ${_outfile} "${moc_flags}" "" "${moc_target}" "")
+ _qt_internal_create_moc_command(${abs_infile} ${_outfile} "${moc_flags}" "" "${moc_target}"
+ "" # moc_depends
+ "" # out_json_file
+ )
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
@@ -181,7 +183,10 @@ function(qt6_wrap_cpp outfiles )
_qt_internal_get_moc_flags(moc_flags)
set(options)
- set(oneValueArgs TARGET)
+ set(oneValueArgs
+ TARGET
+ __QT_INTERNAL_OUTPUT_MOC_JSON_FILES
+ )
set(multiValueArgs OPTIONS DEPENDS)
cmake_parse_arguments(_WRAP_CPP "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
@@ -191,14 +196,76 @@ function(qt6_wrap_cpp outfiles )
set(moc_target ${_WRAP_CPP_TARGET})
set(moc_depends ${_WRAP_CPP_DEPENDS})
+ set(metatypes_json_list "")
+
foreach(it ${moc_files})
get_filename_component(it ${it} ABSOLUTE)
- _qt_internal_make_output_file(${it} moc_ cpp outfile)
+ get_filename_component(it_ext ${it} EXT)
+ # remove the dot
+ string(SUBSTRING ${it_ext} 1 -1 it_ext)
+ set(HEADER_REGEX "(h|hh|h\\+\\+|hm|hpp|hxx|in|txx|inl)$")
+
+ if(it_ext MATCHES "${HEADER_REGEX}")
+ _qt_internal_make_output_file("${it}" moc_ cpp outfile)
+ set(is_header_file TRUE)
+ else()
+ set(found_source_extension FALSE)
+ foreach(LANG C CXX OBJC OBJCXX CUDA)
+ list(FIND CMAKE_${LANG}_SOURCE_FILE_EXTENSIONS "${it_ext}"
+ index)
+ if(${index} GREATER -1)
+ set(found_extension TRUE)
+ break()
+ endif()
+ endforeach()
+ if(found_extension)
+ if(TARGET ${moc_target})
+ _qt_internal_make_output_file(${it} "" moc outfile)
+ target_sources(${moc_target} PRIVATE "${outfile}")
+ target_include_directories("${moc_target}" PRIVATE
+ "${CMAKE_CURRENT_BINARY_DIR}")
+ else()
+ if("${moc_target}" STREQUAL "")
+ string(JOIN "" err_msg
+ "qt6_wrap_cpp: TARGET parameter is empty. "
+ "Since the file ${it} is a source file, "
+ "the TARGET option must be specified.")
+ else()
+ string(JOIN "" err_msg
+ "qt6_wrap_cpp: TARGET \"${moc_target}\" "
+ "not found.")
+ endif()
+ message(FATAL_ERROR "${err_msg}")
+ endif()
+ else()
+ string(JOIN "" err_msg "qt6_wrap_cpp: Unknown file extension: "
+ "\"\.${it_ext}\".")
+ message(FATAL_ERROR "${err_msg}")
+ endif()
+ endif()
+
+ set(out_json_file_var "")
+ if(_WRAP_CPP___QT_INTERNAL_OUTPUT_MOC_JSON_FILES)
+ set(out_json_file_var "out_json_file")
+ endif()
+
_qt_internal_create_moc_command(
- ${it} ${outfile} "${moc_flags}" "${moc_options}" "${moc_target}" "${moc_depends}")
+ ${it} ${outfile} "${moc_flags}" "${moc_options}" "${moc_target}" "${moc_depends}"
+ "${out_json_file_var}")
list(APPEND ${outfiles} ${outfile})
+ if(_WRAP_CPP___QT_INTERNAL_OUTPUT_MOC_JSON_FILES)
+ list(APPEND metatypes_json_list "${${out_json_file_var}}")
+ endif()
endforeach()
- set(${outfiles} ${${outfiles}} PARENT_SCOPE)
+
+ if(is_header_file)
+ set(${outfiles} "${${outfiles}}" PARENT_SCOPE)
+ endif()
+
+ if(metatypes_json_list)
+ set(${_WRAP_CPP___QT_INTERNAL_OUTPUT_MOC_JSON_FILES}
+ "${metatypes_json_list}" PARENT_SCOPE)
+ endif()
endfunction()
# This will override the CMake upstream command, because that one is for Qt 3.
@@ -262,6 +329,10 @@ function(qt6_add_binary_resources target )
set(rcc_options ${_RCC_OPTIONS})
set(rcc_destination ${_RCC_DESTINATION})
+ if(NOT QT_FEATURE_zstd)
+ list(APPEND rcc_options "--no-zstd")
+ endif()
+
if(NOT rcc_destination)
set(rcc_destination ${CMAKE_CURRENT_BINARY_DIR}/${target}.rcc)
endif()
@@ -326,6 +397,10 @@ function(qt6_add_resources outfiles )
message(WARNING "Use qt6_add_binary_resources for binary option")
endif()
+ if(NOT QT_FEATURE_zstd)
+ list(APPEND rcc_options "--no-zstd")
+ endif()
+
foreach(it ${rcc_files})
get_filename_component(outfilename ${it} NAME_WE)
get_filename_component(infile ${it} ABSOLUTE)
@@ -340,8 +415,11 @@ function(qt6_add_resources outfiles )
MAIN_DEPENDENCY ${infile}
DEPENDS ${_rc_depends} "${_out_depends}" ${QT_CMAKE_EXPORT_NAMESPACE}::rcc
VERBATIM)
- set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOMOC ON)
- set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOUIC ON)
+ set_source_files_properties(${outfile} PROPERTIES SKIP_AUTOMOC ON
+ SKIP_AUTOUIC ON
+ SKIP_UNITY_BUILD_INCLUSION ON
+ SKIP_PRECOMPILE_HEADERS ON
+ )
list(APPEND ${outfiles} ${outfile})
endforeach()
set(${outfiles} ${${outfiles}} PARENT_SCOPE)
@@ -355,7 +433,12 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
qt6_add_resources("${outfiles}" ${ARGN})
endif()
- if(NOT TARGET ${outfiles})
+ if(TARGET ${outfiles})
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "OUTPUT_TARGETS" "")
+ if (arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} ${${arg_OUTPUT_TARGETS}} PARENT_SCOPE)
+ endif()
+ else()
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endif()
endfunction()
@@ -365,6 +448,18 @@ endif()
# qt6_add_big_resources(outfiles inputfile ... )
function(qt6_add_big_resources outfiles )
+ if(CMAKE_GENERATOR STREQUAL "Xcode" AND IOS)
+ message(WARNING
+ "Due to CMake limitations, qt6_add_big_resources can't be used when building for iOS. "
+ "See https://bugreports.qt.io/browse/QTBUG-103497 for details. "
+ "Falling back to using qt6_add_resources. "
+ "Consider using qt6_add_resources directly to silence this warning."
+ )
+ qt6_add_resources(${ARGV})
+ set(${outfiles} ${${outfiles}} PARENT_SCOPE)
+ return()
+ endif()
+
if (CMAKE_VERSION VERSION_LESS 3.9)
message(FATAL_ERROR, "qt6_add_big_resources requires CMake 3.9 or newer")
endif()
@@ -382,36 +477,89 @@ function(qt6_add_big_resources outfiles )
message(WARNING "Use qt6_add_binary_resources for binary option")
endif()
+ if(NOT QT_FEATURE_zstd)
+ list(APPEND rcc_options "--no-zstd")
+ endif()
+
foreach(it ${rcc_files})
get_filename_component(outfilename ${it} NAME_WE)
+
+ # Provide unique targets and output file names
+ # in case we add multiple .qrc files with the same base name.
+ string(MAKE_C_IDENTIFIER "_qt_big_resource_count_${outfilename}" prop)
+ get_property(count GLOBAL PROPERTY ${prop})
+ if(count)
+ string(APPEND outfilename "_${count}")
+ else()
+ set(count 0)
+ endif()
+ math(EXPR count "${count} + 1")
+ set_property(GLOBAL PROPERTY ${prop} ${count})
+
get_filename_component(infile ${it} ABSOLUTE)
set(tmpoutfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${outfilename}tmp.cpp)
set(outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${outfilename}.o)
_qt6_parse_qrc_file(${infile} _out_depends _rc_depends)
- set_source_files_properties(${infile} PROPERTIES SKIP_AUTORCC ON)
+ set_source_files_properties(${infile} PROPERTIES SKIP_AUTOGEN ON)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.27")
+ set_source_files_properties(${tmpoutfile} PROPERTIES SKIP_LINTING ON)
+ endif()
add_custom_command(OUTPUT ${tmpoutfile}
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::rcc ${rcc_options} --name ${outfilename} --pass 1 --output ${tmpoutfile} ${infile}
DEPENDS ${infile} ${_rc_depends} "${out_depends}" ${QT_CMAKE_EXPORT_NAMESPACE}::rcc
+ COMMENT "Running rcc pass 1 for resource ${outfilename}"
VERBATIM)
add_custom_target(big_resources_${outfilename} ALL DEPENDS ${tmpoutfile})
- add_library(rcc_object_${outfilename} OBJECT ${tmpoutfile})
- target_compile_definitions(rcc_object_${outfilename} PUBLIC "$<TARGET_PROPERTY:Qt6::Core,INTERFACE_COMPILE_DEFINITIONS>")
- set_target_properties(rcc_object_${outfilename} PROPERTIES AUTOMOC OFF)
- set_target_properties(rcc_object_${outfilename} PROPERTIES AUTOUIC OFF)
+ _qt_internal_add_rcc_pass2(
+ RESOURCE_NAME ${outfilename}
+ RCC_OPTIONS ${rcc_options}
+ OBJECT_LIB rcc_object_${outfilename}
+ QRC_FILE ${infile}
+ PASS1_OUTPUT_FILE ${tmpoutfile}
+ OUT_OBJECT_FILE ${outfile}
+ )
add_dependencies(rcc_object_${outfilename} big_resources_${outfilename})
- # The modification of TARGET_OBJECTS needs the following change in cmake
- # https://gitlab.kitware.com/cmake/cmake/commit/93c89bc75ceee599ba7c08b8fe1ac5104942054f
- add_custom_command(OUTPUT ${outfile}
- COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::rcc
- ARGS ${rcc_options} --name ${outfilename} --pass 2 --temp $<TARGET_OBJECTS:rcc_object_${outfilename}> --output ${outfile} ${infile}
- DEPENDS rcc_object_${outfilename} $<TARGET_OBJECTS:rcc_object_${outfilename}> ${QT_CMAKE_EXPORT_NAMESPACE}::rcc
- VERBATIM)
- list(APPEND ${outfiles} ${outfile})
+ list(APPEND ${outfiles} ${outfile})
endforeach()
set(${outfiles} ${${outfiles}} PARENT_SCOPE)
endfunction()
+function(_qt_internal_add_rcc_pass2)
+ set(options)
+ set(oneValueArgs
+ RESOURCE_NAME
+ OBJECT_LIB
+ QRC_FILE
+ PASS1_OUTPUT_FILE
+ OUT_OBJECT_FILE
+ )
+ set(multiValueArgs
+ RCC_OPTIONS
+ )
+ cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ add_library(${arg_OBJECT_LIB} OBJECT ${arg_PASS1_OUTPUT_FILE})
+ _qt_internal_set_up_static_runtime_library(${arg_OBJECT_LIB})
+ target_compile_definitions(${arg_OBJECT_LIB} PUBLIC
+ "$<TARGET_PROPERTY:Qt6::Core,INTERFACE_COMPILE_DEFINITIONS>")
+ set_target_properties(${arg_OBJECT_LIB} PROPERTIES
+ AUTOMOC OFF
+ AUTOUIC OFF)
+ # The modification of TARGET_OBJECTS needs the following change in cmake
+ # https://gitlab.kitware.com/cmake/cmake/commit/93c89bc75ceee599ba7c08b8fe1ac5104942054f
+ add_custom_command(
+ OUTPUT ${arg_OUT_OBJECT_FILE}
+ COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::rcc
+ ${arg_RCC_OPTIONS} --name ${arg_RESOURCE_NAME} --pass 2
+ --temp $<TARGET_OBJECTS:${arg_OBJECT_LIB}>
+ --output ${arg_OUT_OBJECT_FILE} ${arg_QRC_FILE}
+ DEPENDS ${arg_OBJECT_LIB} $<TARGET_OBJECTS:${arg_OBJECT_LIB}>
+ ${QT_CMAKE_EXPORT_NAMESPACE}::rcc
+ COMMENT "Running rcc pass 2 for resource ${arg_RESOURCE_NAME}"
+ VERBATIM)
+endfunction()
+
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_add_big_resources outfiles)
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
@@ -423,11 +571,45 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endfunction()
endif()
+function(_qt_internal_apply_win_prefix_and_suffix target)
+ if(WIN32)
+ # Table of prefix / suffixes for MSVC libraries as qmake expects them to be created.
+ # static - Qt6EdidSupport.lib (platform support libraries / or static QtCore, etc)
+ # shared - Qt6Core.dll
+ # shared import library - Qt6Core.lib
+ # module aka Qt plugin - qwindows.dll
+ # module import library - qwindows.lib
+ #
+ # The CMake defaults are fine for us.
+
+ # Table of prefix / suffixes for MinGW libraries as qmake expects them to be created.
+ # static - libQt6EdidSupport.a (platform support libraries / or static QtCore, etc)
+ # shared - Qt6Core.dll
+ # shared import library - libQt6Core.a
+ # module aka Qt plugin - qwindows.dll
+ # module import library - libqwindows.a
+ #
+ # CMake for Windows-GNU platforms defaults the prefix to "lib".
+ # CMake for Windows-GNU platforms defaults the import suffix to ".dll.a".
+ # These CMake defaults are not ok for us.
+
+ # This should cover both MINGW with GCC and CLANG.
+ if(NOT MSVC)
+ set_property(TARGET "${target}" PROPERTY IMPORT_SUFFIX ".a")
+
+ get_target_property(target_type ${target} TYPE)
+ if(target_type STREQUAL "STATIC_LIBRARY")
+ set_property(TARGET "${target}" PROPERTY PREFIX "lib")
+ else()
+ set_property(TARGET "${target}" PROPERTY PREFIX "")
+ set_property(TARGET "${target}" PROPERTY IMPORT_PREFIX "lib")
+ endif()
+ endif()
+ endif()
+endfunction()
+
set(_Qt6_COMPONENT_PATH "${CMAKE_CURRENT_LIST_DIR}/..")
-# This function is currently in Technical Preview.
-# It's signature and behavior might change.
-#
# Wrapper function that adds an executable with some Qt specific behavior.
# Some scenarios require steps to be deferred to the end of the current
# directory scope so that the caller has an opportunity to modify certain
@@ -435,10 +617,14 @@ set(_Qt6_COMPONENT_PATH "${CMAKE_CURRENT_LIST_DIR}/..")
function(qt6_add_executable target)
cmake_parse_arguments(PARSE_ARGV 1 arg "MANUAL_FINALIZATION" "" "")
+ _qt_internal_warn_about_example_add_subdirectory()
+
_qt_internal_create_executable("${target}" ${arg_UNPARSED_ARGUMENTS})
+ target_link_libraries("${target}" PRIVATE Qt6::Core)
+ set_property(TARGET ${target} PROPERTY _qt_expects_finalization TRUE)
if(arg_MANUAL_FINALIZATION)
- # Caller says they will call qt6_finalize_executable() themselves later
+ # Caller says they will call qt6_finalize_target() themselves later
return()
endif()
@@ -448,9 +634,25 @@ function(qt6_add_executable target)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19)
# Need to wrap in an EVAL CODE or else ${target} won't be evaluated
# due to special behavior of cmake_language() argument handling
- cmake_language(EVAL CODE "cmake_language(DEFER CALL qt6_finalize_executable ${target})")
+ cmake_language(EVAL CODE "cmake_language(DEFER CALL qt6_finalize_target ${target})")
else()
- qt6_finalize_executable("${target}")
+ set_target_properties("${target}" PROPERTIES _qt_is_immediately_finalized TRUE)
+ qt6_finalize_target("${target}")
+ endif()
+endfunction()
+
+# Just like for qt_add_resources, we should disable zstd compression when cross-compiling to a
+# target that doesn't support zstd decompression, even if the host tool supports it.
+# Allow an opt out via a QT_NO_AUTORCC_ZSTD variable.
+function(_qt_internal_disable_autorcc_zstd_when_not_supported target)
+ if(TARGET "${target}"
+ AND DEFINED QT_FEATURE_zstd
+ AND NOT QT_FEATURE_zstd
+ AND NOT QT_NO_AUTORCC_ZSTD)
+ get_target_property(target_type ${target} TYPE)
+ if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
+ set_property(TARGET "${target}" APPEND PROPERTY AUTORCC_OPTIONS "--no-zstd")
+ endif()
endif()
endfunction()
@@ -466,21 +668,24 @@ function(_qt_internal_create_executable target)
set_property(TARGET "${target}" PROPERTY CXX_VISIBILITY_PRESET default)
set_property(TARGET "${target}" PROPERTY OBJC_VISIBILITY_PRESET default)
set_property(TARGET "${target}" PROPERTY OBJCXX_VISIBILITY_PRESET default)
+ set_property(TARGET "${target}"
+ PROPERTY _qt_android_apply_arch_suffix_called_from_qt_impl TRUE)
qt6_android_apply_arch_suffix("${target}")
+ set_property(TARGET "${target}" PROPERTY _qt_is_android_executable TRUE)
else()
add_executable("${target}" ${ARGN})
endif()
- target_link_libraries("${target}" PRIVATE Qt6::Core)
+ _qt_internal_disable_autorcc_zstd_when_not_supported("${target}")
+ _qt_internal_set_up_static_runtime_library("${target}")
endfunction()
-# This function is currently in Technical Preview.
-# It's signature and behavior might change.
-function(qt6_finalize_executable target)
-
+function(_qt_internal_finalize_executable target)
# We can't evaluate generator expressions at configure time, so we can't
# ask for any transitive properties or even the full library dependency
- # chain. We can still look at the immediate dependencies though and query
+ # chain.
+ # We can still look at the immediate dependencies
+ # (and recursively their dependencies) and query
# any that are not expressed as generator expressions. For any we can
# identify as a CMake target known to the current scope, we can check if
# that target has a finalizer to be called. This is expected to cover the
@@ -489,12 +694,11 @@ function(qt6_finalize_executable target)
# responsible for calling any relevant functions themselves instead of
# relying on these automatic finalization calls.
set(finalizers)
- get_target_property(immediate_deps ${target} LINK_LIBRARIES)
- if(immediate_deps)
- foreach(dep IN LISTS immediate_deps)
- if(NOT TARGET ${dep})
- continue()
- endif()
+
+ __qt_internal_collect_all_target_dependencies("${target}" dep_targets)
+
+ if(dep_targets)
+ foreach(dep IN LISTS dep_targets)
get_target_property(dep_finalizers ${dep}
INTERFACE_QT_EXECUTABLE_FINALIZERS
)
@@ -504,13 +708,18 @@ function(qt6_finalize_executable target)
endforeach()
list(REMOVE_DUPLICATES finalizers)
endif()
+
if(finalizers)
if(CMAKE_VERSION VERSION_LESS 3.18)
- # cmake_language() not available
- message(WARNING
- "Skipping module-specific finalizers for target ${target} "
- "(requires CMake 3.18 or later)"
- )
+ # cmake_language() not available, fall back to the slower method of
+ # writing a file and including it
+ set(contents "")
+ foreach(finalizer_func IN LISTS finalizers)
+ string(APPEND contents "${finalizer_func}(${target})\n")
+ endforeach()
+ set(finalizer_file "${CMAKE_CURRENT_BINARY_DIR}/.qt/finalize_${target}.cmake")
+ file(WRITE ${finalizer_file} "${contents}")
+ include(${finalizer_file})
else()
foreach(finalizer_func IN LISTS finalizers)
cmake_language(CALL ${finalizer_func} ${target})
@@ -518,27 +727,204 @@ function(qt6_finalize_executable target)
endif()
endif()
- if(ANDROID)
- qt6_android_generate_deployment_settings("${target}")
- qt6_android_add_apk_target("${target}")
+ if(EMSCRIPTEN)
+ _qt_internal_wasm_add_target_helpers("${target}")
+ _qt_internal_add_wasm_extra_exported_methods("${target}")
+ _qt_internal_set_wasm_export_name("${target}")
+ endif()
+ if(IOS)
+ _qt_internal_finalize_ios_app("${target}")
+ elseif(APPLE)
+ _qt_internal_finalize_macos_app("${target}")
+ endif()
+
+ # For finalizer mode of plugin importing to work safely, we need to know the list of Qt
+ # dependencies the target has, but those might be added later than the qt_add_executable call.
+ # Most of our examples are like that. Only enable finalizer mode when we are sure that the user
+ # manually called qt_finalize_target at the end of their CMake project, or it was automatically
+ # done via a deferred call. This is also applicable to the resource object finalizer.
+ get_target_property(is_immediately_finalized "${target}" _qt_is_immediately_finalized)
+ if(NOT is_immediately_finalized)
+ __qt_internal_apply_plugin_imports_finalizer_mode("${target}")
+ __qt_internal_process_dependency_object_libraries("${target}")
endif()
endfunction()
+function(_cat IN_FILE OUT_FILE)
+ file(READ ${IN_FILE} CONTENTS)
+ file(APPEND ${OUT_FILE} "${CONTENTS}\n")
+endfunction()
+
+function(_qt_internal_finalize_batch name)
+ find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Core)
+
+ set(generated_blacklist_file "${CMAKE_CURRENT_BINARY_DIR}/BLACKLIST")
+ get_target_property(blacklist_files "${name}" _qt_blacklist_files)
+ file(WRITE "${generated_blacklist_file}" "")
+ foreach(blacklist_file ${blacklist_files})
+ _cat("${blacklist_file}" "${generated_blacklist_file}")
+ endforeach()
+ qt_internal_add_resource(${name} "batch_blacklist"
+ PREFIX "/"
+ FILES "${CMAKE_CURRENT_BINARY_DIR}/BLACKLIST"
+ BASE ${CMAKE_CURRENT_BINARY_DIR})
+endfunction()
+
+# If a task needs to run before any targets are finalized in the current directory
+# scope, call this function and pass the ID of that task as the argument.
+function(_qt_internal_delay_finalization_until_after defer_id)
+ set_property(DIRECTORY APPEND PROPERTY qt_internal_finalizers_wait_for_ids "${defer_id}")
+endfunction()
+
+function(qt6_finalize_target target)
+ set_property(TARGET ${target} PROPERTY _qt_expects_finalization FALSE)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
+ cmake_language(DEFER GET_CALL_IDS ids_queued)
+ get_directory_property(wait_for_ids qt_internal_finalizers_wait_for_ids)
+ while(wait_for_ids)
+ list(GET wait_for_ids 0 id_to_wait_for)
+ if(id_to_wait_for IN_LIST ids_queued)
+ # Something else needs to run before we finalize targets.
+ # Try again later by re-deferring ourselves, which effectively
+ # puts us at the end of the current list of deferred actions.
+ cmake_language(EVAL CODE "cmake_language(DEFER CALL ${CMAKE_CURRENT_FUNCTION} ${ARGV})")
+ set_directory_properties(PROPERTIES
+ qt_internal_finalizers_wait_for_ids "${wait_for_ids}"
+ )
+ return()
+ endif()
+ list(POP_FRONT wait_for_ids)
+ endwhile()
+ # No other deferred tasks to wait for
+ set_directory_properties(PROPERTIES qt_internal_finalizers_wait_for_ids "")
+ endif()
+
+ if(NOT TARGET "${target}")
+ message(FATAL_ERROR "No target '${target}' found in current scope.")
+ endif()
+
+ get_target_property(is_finalized "${target}" _qt_is_finalized)
+ if(is_finalized)
+ message(AUTHOR_WARNING
+ "Tried to call qt6_finalize_target twice on target '${target}'. "
+ "Did you forget to specify MANUAL_FINALIZATION to qt6_add_executable, "
+ "qt6_add_library or qt6_add_plugin?")
+ return()
+ endif()
+
+ _qt_internal_expose_deferred_files_to_ide(${target})
+ _qt_internal_finalize_source_groups(${target})
+ get_target_property(target_type ${target} TYPE)
+ get_target_property(is_android_executable "${target}" _qt_is_android_executable)
+
+ if(target_type STREQUAL "EXECUTABLE" OR is_android_executable)
+ _qt_internal_finalize_executable(${ARGV})
+ endif()
+
+ if(APPLE)
+ # Tell CMake to generate run-scheme for the executable when generating
+ # Xcode projects. This avoids Xcode auto-generating default schemes for
+ # all targets, which includes internal and build-only targets.
+ get_target_property(generate_scheme "${target}" XCODE_GENERATE_SCHEME)
+ if(generate_scheme MATCHES "-NOTFOUND" AND (
+ target_type STREQUAL "EXECUTABLE" OR
+ target_type STREQUAL "SHARED_LIBRARY" OR
+ target_type STREQUAL "STATIC_LIBRARY" OR
+ target_type STREQUAL "MODULE_LIBRARY"))
+ set_property(TARGET "${target}" PROPERTY XCODE_GENERATE_SCHEME TRUE)
+ endif()
+ endif()
+
+ set_target_properties(${target} PROPERTIES _qt_is_finalized TRUE)
+endfunction()
+
+function(_qt_internal_finalize_source_groups target)
+ if(NOT ("${CMAKE_GENERATOR}" STREQUAL "Xcode"
+ OR "${CMAKE_GENERATOR}" MATCHES "^Visual Studio"))
+ return()
+ endif()
+
+ get_target_property(sources ${target} SOURCES)
+ if(NOT sources)
+ return()
+ endif()
+
+ get_target_property(source_dir ${target} SOURCE_DIR)
+ get_target_property(binary_dir ${target} BINARY_DIR)
+
+ get_property(generated_source_group GLOBAL PROPERTY AUTOGEN_SOURCE_GROUP)
+ if(NOT generated_source_group)
+ set(generated_source_group "Source Files/Generated")
+ endif()
+
+ foreach(source IN LISTS sources)
+ string(GENEX_STRIP "${source}" source)
+
+ if(IS_ABSOLUTE ${source})
+ set(source_file_path "${source}")
+ else()
+ # Resolve absolute path. Can't use LOCATION, as that
+ # will error out if the file doesn't exist :(
+ get_filename_component(source_file_path "${source}"
+ ABSOLUTE BASE_DIR "${source_dir}")
+ if(NOT EXISTS ${source_file_path})
+ # Likely generated file, will end up in build dir
+ get_filename_component(source_file_path "${source}"
+ ABSOLUTE BASE_DIR "${binary_dir}")
+ endif()
+ endif()
+
+ # Include qml files in "Source Files". Can not be done via regex,
+ # due to https://gitlab.kitware.com/cmake/cmake/-/issues/25597
+ if(${source_file_path} MATCHES "\\.qml$")
+ source_group("Source Files" FILES ${source_file_path})
+ endif()
+
+ get_source_file_property(is_generated "${source_file_path}" GENERATED)
+ if(${is_generated})
+ source_group(${generated_source_group} FILES ${source_file_path})
+ endif()
+ endforeach()
+endfunction()
+
+function(_qt_internal_darwin_permission_finalizer target)
+ get_target_property(plist_file "${target}" MACOSX_BUNDLE_INFO_PLIST)
+ if(NOT plist_file)
+ return()
+ endif()
+ foreach(plugin_target IN LISTS QT_ALL_PLUGINS_FOUND_BY_FIND_PACKAGE_permissions)
+ set(versioned_plugin_target "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_target}")
+ get_target_property(usage_descriptions
+ ${versioned_plugin_target}
+ _qt_info_plist_usage_descriptions)
+ foreach(usage_description_key IN LISTS usage_descriptions)
+ execute_process(COMMAND "/usr/libexec/PlistBuddy"
+ -c "print ${usage_description_key}" "${plist_file}"
+ OUTPUT_VARIABLE usage_description
+ ERROR_VARIABLE plist_error)
+ if(usage_description AND NOT plist_error)
+ set_target_properties("${target}"
+ PROPERTIES "_qt_has_${plugin_target}_usage_description" TRUE)
+ qt6_import_plugins(${target} INCLUDE ${versioned_plugin_target})
+ endif()
+ endforeach()
+ endforeach()
+endfunction()
+
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_add_executable)
qt6_add_executable(${ARGV})
endfunction()
+ function(qt_finalize_target)
+ qt6_finalize_target(${ARGV})
+ endfunction()
+
+ # Kept for compatibility with Qt Creator 4.15 wizards
function(qt_finalize_executable)
- qt6_finalize_executable(${ARGV})
+ qt6_finalize_target(${ARGV})
endfunction()
endif()
-# Temporarily keep compatibility, until all repositories are migrated.
-function(add_qt_gui_executable)
- message(AUTHOR_WARNING "Please replace add_qt_gui_executable with qt_add_executable instead. The former will be removed shortly.")
- qt6_add_executable(${ARGV})
-endfunction()
-
function(_qt_get_plugin_name_with_version target out_var)
string(REGEX REPLACE "^Qt::(.+)" "Qt${QT_DEFAULT_MAJOR_VERSION}::\\1"
qt_plugin_with_version "${target}")
@@ -573,25 +959,6 @@ function(_qt_internal_disable_static_default_plugins target)
set_target_properties(${target} PROPERTIES QT_DEFAULT_PLUGINS 0)
endfunction()
-# This function is used to indicate which plug-ins are going to be
-# used by a given target.
-# This allows static linking to a correct set of plugins.
-# Options :
-# NO_DEFAULT: disable linking against any plug-in by default for that target, e.g. no platform plug-in.
-# INCLUDE <list of additional plug-ins to be linked against>
-# EXCLUDE <list of plug-ins to be removed from the default set>
-# INCLUDE_BY_TYPE <type> <included plugins>
-# EXCLUDE_BY_TYPE <type to be excluded>
-#
-# Example :
-# qt_import_plugins(myapp
-# INCLUDE Qt::QCocoaIntegrationPlugin
-# EXCLUDE Qt::QMinimalIntegrationPlugin
-# INCLUDE_BY_TYPE imageformats Qt::QGifPlugin Qt::QJpegPlugin
-# EXCLUDE_BY_TYPE sqldrivers
-# )
-
-# TODO : support qml plug-ins.
function(qt6_import_plugins target)
cmake_parse_arguments(arg "NO_DEFAULT" "" "INCLUDE;EXCLUDE;INCLUDE_BY_TYPE;EXCLUDE_BY_TYPE" ${ARGN})
@@ -625,10 +992,14 @@ function(qt6_import_plugins target)
# Check if passed plugin target name is a version-less one, and make a version-full
# one.
+ set_property(TARGET "${target}" APPEND PROPERTY "QT_PLUGINS_${_current_type}" "${_arg}")
+ set_property(TARGET "${target}" APPEND PROPERTY "_qt_plugins_by_type" "${_arg}")
_qt_get_plugin_name_with_version("${_arg}" qt_plugin_with_version)
- if(TARGET "${_arg}" OR TARGET "${qt_plugin_with_version}")
- set_property(TARGET "${target}" APPEND PROPERTY "QT_PLUGINS_${_current_type}" "${_arg}")
- else()
+
+ # TODO: Do we really need this check? We didn't have it in Qt5, and plugin targets
+ # wrapped in genexes end up causing warnings, but we explicitly use GENEX_EVAL to
+ # support them.
+ if(NOT TARGET "${_arg}" AND NOT TARGET "${qt_plugin_with_version}")
message("Warning: plug-in ${_arg} is not known to the current Qt installation.")
endif()
endif()
@@ -651,19 +1022,196 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endfunction()
endif()
+# This function is currently in Technical Preview. It's signature may change or be removed entirely.
+function(qt6_set_finalizer_mode target)
+ cmake_parse_arguments(arg "ENABLE;DISABLE" "" "MODES" ${ARGN})
+ if(NOT arg_ENABLE AND NOT arg_DISABLE)
+ message(FATAL_ERROR "No option was specified whether to enable or disable the modes.")
+ elseif(arg_ENABLE AND arg_DISABLE)
+ message(FATAL_ERROR "Both ENABLE and DISABLE options were specified.")
+ endif()
+ if(NOT arg_MODES)
+ message(FATAL_ERROR "No modes were specified in qt6_set_finalizer_mode() call.")
+ endif()
+
+ if(arg_ENABLE)
+ set(value "TRUE")
+ elseif(arg_DISABLE)
+ set(value "FALSE")
+ endif()
+
+ foreach(mode ${arg_MODES})
+ __qt_internal_enable_finalizer_mode("${target}" "${mode}" "${value}")
+ endforeach()
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_set_finalizer_mode)
+ qt6_set_finalizer_mode(${ARGV})
+ endfunction()
+endif()
+
+function(_qt_internal_assign_to_internal_targets_folder target)
+ get_property(folder_name GLOBAL PROPERTY QT_TARGETS_FOLDER)
+ if(NOT "${folder_name}" STREQUAL "")
+ set_property(TARGET ${target} PROPERTY FOLDER "${folder_name}")
+ endif()
+endfunction()
+
+function(_qt_internal_get_target_autogen_build_dir target out_var)
+ get_property(target_autogen_build_dir TARGET ${target} PROPERTY AUTOGEN_BUILD_DIR)
+ if(target_autogen_build_dir)
+ set(${out_var} "${target_autogen_build_dir}" PARENT_SCOPE)
+ else()
+ get_property(target_binary_dir TARGET ${target} PROPERTY BINARY_DIR)
+ set(${out_var} "${target_binary_dir}/${target}_autogen" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function(_qt_internal_should_install_metatypes target)
+ set(args_option
+ INTERNAL_INSTALL
+ )
+ set(args_single
+ OUT_VAR
+ )
+ set(args_multi
+ )
+
+ cmake_parse_arguments(arg
+ "${args_option}"
+ "${args_single}"
+ "${args_multi}" ${ARGN})
+
+ # Check whether the generated json file needs to be installed.
+ # Executable metatypes.json files should not be installed. Qt non-prefix builds should also
+ # not install the files.
+ set(should_install FALSE)
+
+ get_target_property(target_type ${target} TYPE)
+ if(NOT target_type STREQUAL "EXECUTABLE" AND arg_INTERNAL_INSTALL)
+ set(should_install TRUE)
+ endif()
+ set(${arg_OUT_VAR} "${should_install}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_get_metatypes_install_dir internal_install_dir arch_data_dir out_var)
+ # Automatically fill default install args when not specified.
+ if(NOT internal_install_dir)
+ # INSTALL_ARCHDATADIR is not set when QtBuildInternals is not loaded
+ # (when not doing a Qt build). Default to a hardcoded location for user
+ # projects (will likely be wrong).
+ if(arch_data_dir)
+ set(install_dir "${arch_data_dir}/metatypes")
+ else()
+ set(install_dir "lib/metatypes")
+ endif()
+ else()
+ set(install_dir "${internal_install_dir}")
+ endif()
+ set(${out_var} "${install_dir}" PARENT_SCOPE)
+endfunction()
+
+# Propagates the build time metatypes file via INTERFACE_SOURCES (using $<BUILD_INTERFACE>)
+# and saves the path and file name in properties, so that they can be queryied in the qml api
+# implementation for the purpose of duplicating a qml module backing library's metatypes in its
+# associated plugin. This is required for qmltyperegistrar to get the full set of foreign types
+# when projects link to the plugin and not the backing library.
+function(_qt_internal_assign_build_metatypes_files_and_properties target)
+ get_target_property(existing_meta_types_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE)
+ if (existing_meta_types_file)
+ return()
+ endif()
+
+ set(args_option
+ )
+ set(args_single
+ METATYPES_FILE_NAME
+ METATYPES_FILE_PATH
+ )
+ set(args_multi
+ )
+
+ cmake_parse_arguments(arg
+ "${args_option}"
+ "${args_single}"
+ "${args_multi}" ${ARGN})
+
+ if(NOT arg_METATYPES_FILE_NAME)
+ message(FATAL_ERROR "METATYPES_FILE_NAME must be specified")
+ endif()
+
+ if(NOT arg_METATYPES_FILE_PATH)
+ message(FATAL_ERROR "METATYPES_FILE_PATH must be specified")
+ endif()
+
+ set(metatypes_file_name "${arg_METATYPES_FILE_NAME}")
+ set(metatypes_file_path "${arg_METATYPES_FILE_PATH}")
+
+ # Set up consumption of files via INTERFACE_SOURCES.
+ set(consumes_metatypes "$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>")
+ set(metatypes_file_genex_build
+ "$<BUILD_INTERFACE:$<${consumes_metatypes}:${metatypes_file_path}>>"
+ )
+ target_sources(${target} INTERFACE ${metatypes_file_genex_build})
+
+ set_target_properties(${target} PROPERTIES
+ INTERFACE_QT_MODULE_HAS_META_TYPES YES
+ # The property name is a bit misleading, it's not wrapped in a genex.
+ INTERFACE_QT_META_TYPES_BUILD_FILE "${metatypes_file_path}"
+ INTERFACE_QT_META_TYPES_FILE_NAME "${metatypes_file_name}"
+ )
+endfunction()
+
+# Same as above, but with $<INSTALL_INTERFACE>.
+function(_qt_internal_assign_install_metatypes_files_and_properties target)
+ get_target_property(existing_meta_types_file ${target} INTERFACE_QT_META_TYPES_INSTALL_FILE)
+ if (existing_meta_types_file)
+ return()
+ endif()
+
+ set(args_option
+ )
+ set(args_single
+ INSTALL_DIR
+ )
+ set(args_multi
+ )
+
+ cmake_parse_arguments(arg
+ "${args_option}"
+ "${args_single}"
+ "${args_multi}" ${ARGN})
+
+
+ get_target_property(metatypes_file_name "${target}" INTERFACE_QT_META_TYPES_FILE_NAME)
+
+ if(NOT metatypes_file_name)
+ message(FATAL_ERROR "INTERFACE_QT_META_TYPES_FILE_NAME of target ${target} is empty")
+ endif()
+
+ if(NOT arg_INSTALL_DIR)
+ message(FATAL_ERROR "INSTALL_DIR must be specified")
+ endif()
+
+ # Set up consumption of files via INTERFACE_SOURCES.
+ set(consumes_metatypes "$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>")
+
+ set(install_dir "${arg_INSTALL_DIR}")
+
+ set(metatypes_file_install_path "${install_dir}/${metatypes_file_name}")
+ set(metatypes_file_install_path_genex "$<INSTALL_PREFIX>/${metatypes_file_install_path}")
+ set(metatypes_file_genex_install
+ "$<INSTALL_INTERFACE:$<${consumes_metatypes}:${metatypes_file_install_path_genex}>>"
+ )
+ target_sources(${target} INTERFACE ${metatypes_file_genex_install})
+
+ set_target_properties(${target} PROPERTIES
+ INTERFACE_QT_META_TYPES_INSTALL_FILE "${metatypes_file_install_path}"
+ )
+endfunction()
+
-# Extracts metatypes from a Qt target and generates a metatypes.json for it.
-# By default we check whether AUTOMOC has been enabled and we extract the information from the
-# target's AUTOMOC supporting files.
-# Should you not wish to use automoc you need to pass in all the generated json files via the
-# MANUAL_MOC_JSON_FILES parameter. The latter can be obtained by running moc with
-# the --output-json parameter.
-# Params:
-# INSTALL_DIR: Location where to install the metatypes file. For public consumption,
-# defaults to a ${CMAKE_INSTALL_PREFIX}/${INSTALL_LIBDIR}/metatypes directory.
-# Executable metatypes files are never installed.
-# COPY_OVER_INSTALL: (Qt Internal) When present will install the file via a post build step
-# copy rather than using install.
function(qt6_extract_metatypes target)
get_target_property(existing_meta_types_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE)
@@ -671,7 +1219,30 @@ function(qt6_extract_metatypes target)
return()
endif()
- cmake_parse_arguments(arg "COPY_OVER_INSTALL" "INSTALL_DIR" "MANUAL_MOC_JSON_FILES" ${ARGN})
+ set(args_option
+ # TODO: Move this into a separate internal function, so it doesn't pollute the public one.
+ # When given, metatypes files will be installed into the default Qt
+ # metatypes folder. Only to be used by the Qt build.
+ __QT_INTERNAL_INSTALL
+ )
+ set(args_single
+ # TODO: Move this into a separate internal function, so it doesn't pollute the public one.
+ # Location where to install the metatypes file. Only used if
+ # __QT_INTERNAL_INSTALL is given. It defaults to the
+ # ${CMAKE_INSTALL_PREFIX}/${INSTALL_ARCHDATADIR}/metatypes directory.
+ # Executable metatypes files are never installed.
+ __QT_INTERNAL_INSTALL_DIR
+
+ OUTPUT_FILES
+ )
+ set(args_multi
+ MANUAL_MOC_JSON_FILES
+ )
+
+ cmake_parse_arguments(arg
+ "${args_option}"
+ "${args_single}"
+ "${args_multi}" ${ARGN})
get_target_property(target_type ${target} TYPE)
if (target_type STREQUAL "INTERFACE_LIBRARY")
@@ -684,28 +1255,13 @@ function(qt6_extract_metatypes target)
return()
endif()
- # Whether the generated json file needs to be installed for prefix-builds, or copied for
- # non-prefix builds. Regardless of the type of build, executable metatypes.json files should
- # not be installed. Only library .json files should be installed.
- set(should_install "TRUE")
- if (target_type STREQUAL "EXECUTABLE")
- set(should_install "FALSE")
- endif()
-
- # Automatically fill default install args when not specified.
- if (NOT arg_INSTALL_DIR)
- # INSTALL_LIBDIR is not set when QtBuildInternals is not loaded (when not doing a Qt build).
- if(INSTALL_LIBDIR)
- set(arg_INSTALL_DIR "${INSTALL_LIBDIR}/metatypes")
- else()
- set(arg_INSTALL_DIR "lib/metatypes")
- endif()
- endif()
-
get_target_property(target_binary_dir ${target} BINARY_DIR)
set(type_list_file "${target_binary_dir}/meta_types/${target}_json_file_list.txt")
set(type_list_file_manual "${target_binary_dir}/meta_types/${target}_json_file_list_manual.txt")
+ set(target_autogen_build_dir "")
+ _qt_internal_get_target_autogen_build_dir(${target} target_autogen_build_dir)
+
get_target_property(uses_automoc ${target} AUTOMOC)
set(automoc_args)
set(automoc_dependencies)
@@ -716,17 +1272,18 @@ function(qt6_extract_metatypes target)
AUTOMOC_MOC_OPTIONS "--output-json"
)
- if(NOT CMAKE_CONFIGURATION_TYPES)
+ get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(NOT is_multi_config)
set(cmake_autogen_cache_file
"${target_binary_dir}/CMakeFiles/${target}_autogen.dir/ParseCache.txt")
- set(mutli_config_args
- --cmake-autogen-include-dir-path "${target_binary_dir}/${target}_autogen/include"
+ set(multi_config_args
+ --cmake-autogen-include-dir-path "${target_autogen_build_dir}/include"
)
else()
set(cmake_autogen_cache_file
"${target_binary_dir}/CMakeFiles/${target}_autogen.dir/ParseCache_$<CONFIG>.txt")
- set(mutli_config_args
- --cmake-autogen-include-dir-path "${target_binary_dir}/${target}_autogen/include_$<CONFIG>"
+ set(multi_config_args
+ --cmake-autogen-include-dir-path "${target_autogen_build_dir}/include_$<CONFIG>"
"--cmake-multi-config")
endif()
@@ -735,41 +1292,92 @@ function(qt6_extract_metatypes target)
set (use_dep_files FALSE)
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.17") # Requires automoc changes present only in 3.17
- if(CMAKE_GENERATOR STREQUAL "Ninja" OR CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
- set(use_dep_files TRUE)
+ if(CMAKE_GENERATOR STREQUAL "Ninja" OR
+ CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" OR
+ (CMAKE_GENERATOR MATCHES "Makefiles" AND
+ CMAKE_VERSION VERSION_GREATER_EQUAL "3.28"))
+ if(DEFINED QT_USE_CMAKE_DEPFILES)
+ set(use_dep_files ${QT_USE_CMAKE_DEPFILES})
+ else()
+ set(use_dep_files TRUE)
+ endif()
endif()
endif()
+ set(cmake_automoc_parser_timestamp "${type_list_file}.timestamp")
+
if (NOT use_dep_files)
+ # When a project is configured with a Visual Studio generator, CMake's
+ # cmQtAutoGenInitializer::InitAutogenTarget() can take one of two code paths on how to
+ # handle AUTOMOC rules.
+ # It either creates a ${target}_autogen custom target or uses PRE_BUILD build events.
+ #
+ # The latter in considered an optimization and is used by CMake when possible.
+ # Unfortunately that breaks our add_dependency call because we expect on _autogen target
+ # to always exist.
+ #
+ # Ensure the PRE_BUILD path is not taken by generating a dummy header file and adding it
+ # as a source file to the target. This causes the file to be added to
+ # cmQtAutoGenInitializer::AutogenTarget.DependFiles, which disables the PRE_BUILD path.
+ if(CMAKE_GENERATOR MATCHES "Visual Studio")
+ # The file name should be target specific, but still short, so we don't hit path
+ # length issues.
+ string(MAKE_C_IDENTIFIER "ddf_${target}" dummy_dependency_file)
+ set(dummy_out_file "${CMAKE_CURRENT_BINARY_DIR}/${dummy_dependency_file}.h")
+
+ # The content shouldn't be empty so we don't trigger AUTOMOC warnings about it.
+ file(GENERATE OUTPUT "${dummy_out_file}" CONTENT "//")
+ set_source_files_properties("${dummy_out_file}" PROPERTIES
+ GENERATED TRUE
+ SKIP_AUTOGEN OFF)
+ target_sources("${target}" PRIVATE "${dummy_out_file}")
+ endif()
+
add_custom_target(${target}_automoc_json_extraction
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::cmake_automoc_parser
- BYPRODUCTS ${type_list_file}
+ BYPRODUCTS
+ ${type_list_file}
+ "${cmake_automoc_parser_timestamp}"
COMMAND
${QT_CMAKE_EXPORT_NAMESPACE}::cmake_automoc_parser
--cmake-autogen-cache-file "${cmake_autogen_cache_file}"
--cmake-autogen-info-file "${cmake_autogen_info_file}"
--output-file-path "${type_list_file}"
- ${mutli_config_args}
- COMMENT "Running Automoc file extraction"
+ --timestamp-file-path "${cmake_automoc_parser_timestamp}"
+ ${multi_config_args}
+ COMMENT "Running AUTOMOC file extraction for target ${target}"
COMMAND_EXPAND_LISTS
)
add_dependencies(${target}_automoc_json_extraction ${target}_autogen)
+ _qt_internal_assign_to_internal_targets_folder(${target}_automoc_json_extraction)
else()
- set(cmake_autogen_timestamp_file
- "${target_binary_dir}/${target}_autogen/timestamp"
- )
+ set(timestamp_file "${target_autogen_build_dir}/timestamp")
+ set(timestamp_file_with_config "${timestamp_file}_$<CONFIG>")
+ if (is_multi_config AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.29"
+ AND NOT QT_INTERNAL_USE_OLD_AUTOGEN_GRAPH_MULTI_CONFIG_METATYPES)
+ string(JOIN "" timestamp_genex
+ "$<IF:$<BOOL:$<TARGET_PROPERTY:${target},"
+ "AUTOGEN_BETTER_GRAPH_MULTI_CONFIG>>,"
+ "${timestamp_file_with_config},${timestamp_file}>")
+ set(cmake_autogen_timestamp_file "${timestamp_genex}")
+ else()
+ set(cmake_autogen_timestamp_file ${timestamp_file})
+ endif()
add_custom_command(OUTPUT ${type_list_file}
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::cmake_automoc_parser
${cmake_autogen_timestamp_file}
+ BYPRODUCTS "${cmake_automoc_parser_timestamp}"
COMMAND
${QT_CMAKE_EXPORT_NAMESPACE}::cmake_automoc_parser
--cmake-autogen-cache-file "${cmake_autogen_cache_file}"
--cmake-autogen-info-file "${cmake_autogen_info_file}"
--output-file-path "${type_list_file}"
- ${mutli_config_args}
- COMMENT "Running Automoc file extraction"
+ --timestamp-file-path "${cmake_automoc_parser_timestamp}"
+ ${multi_config_args}
+ COMMENT "Running AUTOMOC file extraction for target ${target}"
COMMAND_EXPAND_LISTS
+ VERBATIM
)
endif()
@@ -793,7 +1401,7 @@ function(qt6_extract_metatypes target)
message(FATAL_ERROR "Metatype generation requires either the use of AUTOMOC or a manual list of generated json files")
endif()
- if (CMAKE_BUILD_TYPE)
+ if (CMAKE_BUILD_TYPE AND NOT is_multi_config)
string(TOLOWER ${target}_${CMAKE_BUILD_TYPE} target_lowercase)
else()
string(TOLOWER ${target} target_lowercase)
@@ -819,18 +1427,11 @@ function(qt6_extract_metatypes target)
file(TOUCH ${metatypes_file})
endif()
- # Need to make the path absolute during a Qt non-prefix build, otherwise files are written
- # to the source dir because the paths are relative to the source dir when using file(TOUCH).
- if(arg_COPY_OVER_INSTALL AND NOT IS_ABSOLUTE "${arg_INSTALL_DIR}/${metatypes_file_name}")
- set(arg_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${arg_INSTALL_DIR}")
- endif()
-
- if (should_install AND arg_COPY_OVER_INSTALL
- AND NOT EXISTS ${arg_INSTALL_DIR}/${metatypes_file_name})
- file(MAKE_DIRECTORY "${arg_INSTALL_DIR}")
- file(TOUCH "${arg_INSTALL_DIR}/${metatypes_file_name}")
- endif()
- add_custom_command(OUTPUT ${metatypes_file_gen} ${metatypes_file}
+ add_custom_command(
+ OUTPUT
+ ${metatypes_file_gen}
+ BYPRODUCTS
+ ${metatypes_file}
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::moc ${automoc_dependencies} ${manual_dependencies}
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc
-o ${metatypes_file_gen}
@@ -838,85 +1439,87 @@ function(qt6_extract_metatypes target)
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${metatypes_file_gen}
${metatypes_file}
- COMMENT "Running automoc with --collect-json"
+ COMMENT "Running moc --collect-json for target ${target}"
+ VERBATIM
)
- # We still need to add this file as a source of Core, otherwise the file
+ if(CMAKE_GENERATOR MATCHES " Makefiles" OR CMAKE_GENERATOR MATCHES "^Visual Studio")
+ # Work around https://gitlab.kitware.com/cmake/cmake/-/issues/19005 to trigger the command
+ # that generates ${metatypes_file}.
+ add_custom_command(
+ OUTPUT ${metatypes_file}
+ DEPENDS ${metatypes_file_gen}
+ COMMAND ${CMAKE_COMMAND} -E true
+ VERBATIM
+ )
+ endif()
+
+ # We can't rely on policy CMP0118 since user project controls it
+ set(scope_args)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${target})
+ endif()
+ set_source_files_properties(${metatypes_file_gen} ${metatypes_file} ${scope_args}
+ PROPERTIES GENERATED TRUE
+ )
+
+ # We still need to add this file as a source of the target, otherwise the file
# rule above is not triggered. INTERFACE_SOURCES do not properly register
# as dependencies to build the current target.
+ # TODO: Can we pass ${metatypes_file} instead of ${metatypes_file_gen} as a source?
+ # TODO: Do we still need the _gen variant at all?
target_sources(${target} PRIVATE ${metatypes_file_gen})
- set(metatypes_file_genex_build)
- set(metatypes_file_genex_install)
- if (arg_COPY_OVER_INSTALL)
- if(should_install)
- set(metatypes_file_genex_build
- "$<BUILD_INTERFACE:$<$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>:${arg_INSTALL_DIR}/${metatypes_file_name}>>"
- )
- endif()
+ set_source_files_properties(${metatypes_file} ${scope_args}
+ PROPERTIES HEADER_FILE_ONLY TRUE
+ )
+
+ if(arg_OUTPUT_FILES)
+ set(${arg_OUTPUT_FILES} "${metatypes_file}" PARENT_SCOPE)
+ endif()
+
+ # Propagate the build time metatypes file.
+ _qt_internal_assign_build_metatypes_files_and_properties(
+ "${target}"
+ METATYPES_FILE_NAME "${metatypes_file_name}"
+ METATYPES_FILE_PATH "${metatypes_file}"
+ )
+
+ if(arg___QT_INTERNAL_INSTALL)
+ set(internal_install_option "INTERNAL_INSTALL")
else()
- set(metatypes_file_genex_build
- "$<BUILD_INTERFACE:$<$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>:${metatypes_file}>>"
- )
- if(should_install)
- set(metatypes_file_genex_install
- "$<INSTALL_INTERFACE:$<$<BOOL:$<TARGET_PROPERTY:QT_CONSUMES_METATYPES>>:$<INSTALL_PREFIX>/${arg_INSTALL_DIR}/${metatypes_file_name}>>"
- )
- endif()
+ set(internal_install_option "")
endif()
- set_source_files_properties(${metatypes_file} PROPERTIES HEADER_FILE_ONLY TRUE)
- set_target_properties(${target} PROPERTIES
- INTERFACE_QT_MODULE_HAS_META_TYPES YES
- INTERFACE_QT_MODULE_META_TYPES_FROM_BUILD YES
- INTERFACE_QT_META_TYPES_BUILD_FILE "${metatypes_file}"
- QT_MODULE_META_TYPES_FILE_GENEX_BUILD "${metatypes_file_genex_build}"
- QT_MODULE_META_TYPES_FILE_GENEX_INSTALL "${metatypes_file_genex_install}"
+ # TODO: Clean up Qt-specific installation not to happen in the public api.
+ # Check whether the metatype files should be installed.
+ _qt_internal_should_install_metatypes("${target}"
+ ${internal_install_option}
+ OUT_VAR should_install
)
- target_sources(${target} INTERFACE ${metatypes_file_genex_build} ${metatypes_file_genex_install})
-
- # Installation is complicated, because there are multiple combinations.
- # In non-prefix builds (signaled by arg_COPY_OVER_INSTALL == TRUE), Qt modules are /copied/
- # into the qt_prefix/lib/metatypes.
- # In prefix builds (signaled by arg_COPY_OVER_INSTALL == FALSE), Qt modules are /installed/
- # into the qt_prefix/lib/metatypes.
- # Currently only the internal qt_add_module sets arg_COPY_OVER_INSTALL.
- #
- # Tests and examples are executables, and thus will not have their meta types installed, but
- # they will have them generated (if this function is called).
- #
- # Regular libraries and plugins (which are not part of the Qt build), will be /installed/
- # into a lib/metatypes directory relative to their prefix, rather than the Qt prefix (only
- # outside of a Qt build).
- # We don't support non-prefix builds for libraries or plugins which are not part of the official
- # Qt build. Aka everything non-prefix / COPY_OVER_INSTALL related are implementation details
- # that users shouldn't use.
+
if(should_install)
- if (arg_COPY_OVER_INSTALL)
- set(command_args
- COMMAND ${CMAKE_COMMAND} -E copy_if_different
- "${metatypes_file}"
- "${arg_INSTALL_DIR}/${metatypes_file_name}"
- )
- if (target_type STREQUAL "OBJECT_LIBRARY")
- add_custom_target(${target}_metatypes_copy
- DEPENDS "${metatypes_file}"
- ${command_args}
- )
- add_dependencies(${target} ${target}_metatypes_copy)
- else()
- add_custom_command(TARGET ${target} POST_BUILD
- ${command_args}
- )
- endif()
- else()
- install(FILES "${metatypes_file}" DESTINATION "${arg_INSTALL_DIR}")
- endif()
+ _qt_internal_get_metatypes_install_dir(
+ "${arg___QT_INTERNAL_INSTALL_DIR}"
+ "${INSTALL_ARCHDATADIR}"
+ install_dir
+ )
+
+ # Propagate the install time metatypes file.
+ _qt_internal_assign_install_metatypes_files_and_properties(
+ "${target}"
+ INSTALL_DIR "${install_dir}"
+ )
+ install(FILES "${metatypes_file}" DESTINATION "${install_dir}")
endif()
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_extract_metatypes)
qt6_extract_metatypes(${ARGV})
+ cmake_parse_arguments(PARSE_ARGV 0 arg "" "OUTPUT_FILES" "")
+ if(arg_OUTPUT_FILES)
+ set(${arg_OUTPUT_FILES} "${${arg_OUTPUT_FILES}}" PARENT_SCOPE)
+ endif()
endfunction()
endif()
@@ -953,9 +1556,16 @@ function(_qt_internal_generate_win32_rc_file target)
return()
endif()
+ if(MSVC)
+ set(extra_rc_flags "-c65001 -DWIN32 -nologo")
+ else()
+ set(extra_rc_flags)
+ endif()
+
if (target_rc_file)
# Use the provided RC file
target_sources(${target} PRIVATE "${target_rc_file}")
+ set_property(SOURCE ${target_rc_file} PROPERTY COMPILE_FLAGS "${extra_rc_flags}")
else()
# Generate RC File
set(rc_file_output "${target_binary_dir}/")
@@ -1111,10 +1721,29 @@ END
# We would like to do the following:
# target_sources(${target} PRIVATE "$<$<CONFIG:${cfg}>:${output}>")
- # However, https://gitlab.kitware.com/cmake/cmake/-/issues/20682 doesn't let us.
- # Work-around by compiling the resources in an object lib and linking that.
- add_library(${target}_rc OBJECT "${output}")
- target_link_libraries(${target} PRIVATE $<TARGET_OBJECTS:${target}_rc>)
+ #
+ # However, https://gitlab.kitware.com/cmake/cmake/-/issues/20682 doesn't let us do that
+ # in CMake 3.19 and earlier.
+ # We can do it in CMake 3.20 and later.
+ # And we have to do it with CMake 3.21.0 to avoid a different issue
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/22436
+ #
+ # So use the object lib work around for <= 3.19 and target_sources directly for later
+ # versions.
+ set(use_obj_lib FALSE)
+ set(end_target "${target}")
+ if(CMAKE_VERSION VERSION_LESS 3.20)
+ set(use_obj_lib TRUE)
+ set(end_target "${target}_rc")
+ add_library(${target}_rc OBJECT "${output}")
+ target_link_libraries(${target} PRIVATE $<TARGET_OBJECTS:${target}_rc>)
+ endif()
+
+ set(scope_args)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${end_target})
+ endif()
+
while(outputs)
list(POP_FRONT cfgs cfg)
list(POP_FRONT outputs output)
@@ -1122,20 +1751,245 @@ END
add_custom_command(OUTPUT "${output}"
DEPENDS "${input}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${input}" "${output}"
+ VERBATIM
+ )
+ # We can't rely on policy CMP0118 since user project controls it
+ set_source_files_properties(${output} ${scope_args} PROPERTIES
+ GENERATED TRUE
+ COMPILE_FLAGS "${extra_rc_flags}"
)
- target_sources(${target}_rc PRIVATE "$<$<CONFIG:${cfg}>:${output}>")
+ target_sources(${end_target} PRIVATE "$<$<CONFIG:${cfg}>:${output}>")
endwhile()
endif()
endfunction()
+# Generate Win32 longPathAware RC and Manifest files for a target.
+# MSVC needs the manifest file as part of target_sources. MinGW the RC file.
+#
+function(_qt_internal_generate_longpath_win32_rc_file_and_manifest target)
+ set(prohibited_target_types INTERFACE_LIBRARY STATIC_LIBRARY OBJECT_LIBRARY)
+ get_target_property(target_type ${target} TYPE)
+ if(target_type IN_LIST prohibited_target_types)
+ return()
+ endif()
+
+ get_target_property(target_binary_dir ${target} BINARY_DIR)
+
+ # Generate manifest
+ set(target_mn_filename "${target}_longpath.manifest")
+ set(mn_file_output "${target_binary_dir}/${target_mn_filename}")
+
+ set(mn_contents [=[<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<application xmlns="urn:schemas-microsoft-com:asm.v3">
+ <windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+ <ws2:longPathAware>true</ws2:longPathAware>
+ </windowsSettings>
+</application>
+</assembly>]=])
+ file(GENERATE OUTPUT "${mn_file_output}" CONTENT "${mn_contents}")
+
+ # Generate RC File
+ set(rc_file_output "${target_binary_dir}/${target}_longpath.rc")
+ set(rc_contents "1 /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 24 /* RT_MANIFEST */ ${target_mn_filename}")
+ file(GENERATE OUTPUT "${rc_file_output}" CONTENT "${rc_contents}")
+
+ if (MINGW)
+ set(outputs "${rc_file_output}")
+ endif()
+ list(APPEND outputs "${mn_file_output}")
+
+ foreach(output IN LISTS outputs)
+ # Needed for CMake versions < 3.19
+ set_source_files_properties(${output} PROPERTIES GENERATED TRUE)
+ target_sources(${target} PRIVATE "${output}")
+ endforeach()
+endfunction()
+
function(__qt_get_relative_resource_path_for_file output_alias file)
get_property(alias SOURCE ${file} PROPERTY QT_RESOURCE_ALIAS)
if (NOT alias)
set(alias "${file}")
+ if(IS_ABSOLUTE "${file}")
+ message(FATAL_ERROR
+ "The source file '${file}' was specified with an absolute path and is used in a Qt "
+ "resource. Please set the QT_RESOURCE_ALIAS property on that source file to a "
+ "relative path to make the file properly accessible via the resource system."
+ )
+ endif()
endif()
set(${output_alias} ${alias} PARENT_SCOPE)
endfunction()
+# Performs linking and propagation of the specified objects via the target's usage requirements.
+# The objects may be given as generator expression.
+#
+# Arguments:
+# EXTRA_CONDITIONS
+# Conditions to be checked before linking the object files to the end-point executable.
+# EXTRA_TARGET_LINK_LIBRARIES_CONDITIONS
+# Conditions for the target_link_libraries call.
+# EXTRA_TARGET_SOURCES_CONDITIONS
+# Conditions for the target_sources call.
+function(__qt_internal_propagate_object_files target objects)
+ set(options "")
+ set(single_args "")
+ set(extra_conditions_args
+ EXTRA_CONDITIONS
+ EXTRA_TARGET_LINK_LIBRARIES_CONDITIONS
+ EXTRA_TARGET_SOURCES_CONDITIONS
+ )
+ set(multi_args ${extra_conditions_args})
+ cmake_parse_arguments(arg "${options}" "${single_args}" "${multi_args}" ${ARGN})
+
+ # Collect additional conditions.
+ foreach(arg IN LISTS extra_conditions_args)
+ string(TOLOWER "${arg}" lcvar)
+ if(arg_${arg})
+ list(JOIN arg_${arg} "," ${lcvar})
+ else()
+ set(${lcvar} "$<BOOL:TRUE>")
+ endif()
+ endforeach()
+
+ # Do not litter the static libraries
+ set(not_static_condition
+ "$<NOT:$<STREQUAL:$<TARGET_PROPERTY:TYPE>,STATIC_LIBRARY>>"
+ )
+
+ # Check if link order matters for the Platform.
+ set(platform_link_order_property
+ "$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Platform,_qt_link_order_matters>"
+ )
+ set(platform_link_order_condition
+ "$<BOOL:${platform_link_order_property}>"
+ )
+
+ # Check if link options are propagated according to CMP0099
+ # In user builds the _qt_cmp0099_policy_check is set to FALSE or $<TARGET_POLICY:CMP0099>
+ # depending on the used CMake version.
+ # See __qt_internal_check_cmp0099_available for details.
+ set(cmp0099_policy_check_property
+ "$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Platform,_qt_cmp0099_policy_check>"
+ )
+ set(link_objects_using_link_options_condition
+ "$<BOOL:$<GENEX_EVAL:${cmp0099_policy_check_property}>>"
+ )
+
+ # Collect link conditions for the target_sources call.
+ string(JOIN "" target_sources_genex
+ "$<"
+ "$<AND:"
+ "${not_static_condition},"
+ "${platform_link_order_condition},"
+ "$<NOT:${link_objects_using_link_options_condition}>,"
+ "${extra_target_sources_conditions},"
+ "${extra_conditions}"
+ ">"
+ ":${objects}>"
+ )
+ target_sources(${target} INTERFACE
+ "${target_sources_genex}"
+ )
+
+ # Collect link conditions for the target_link_options call.
+ string(JOIN "" target_link_options_genex
+ "$<"
+ "$<AND:"
+ "${not_static_condition},"
+ "${platform_link_order_condition},"
+ "${link_objects_using_link_options_condition},"
+ "${extra_conditions}"
+ ">"
+ ":${objects}>"
+ )
+ # target_link_options works well since CMake 3.17 which has policy CMP0099 set to NEW for the
+ # minimum required CMake version greater than or equal to 3.17. The default is OLD. See
+ # https://cmake.org/cmake/help/git-master/policy/CMP0099.html for details.
+ # This provides yet another way of linking object libraries if user sets the policy to NEW
+ # before calling find_package(Qt...).
+ target_link_options(${target} INTERFACE
+ "${target_link_options_genex}"
+ )
+
+ # Collect link conditions for the target_link_libraries call.
+ string(JOIN "" target_link_libraries_genex
+ "$<"
+ "$<AND:"
+ "${not_static_condition},"
+ "$<NOT:${platform_link_order_condition}>,"
+ "${extra_target_link_libraries_conditions},"
+ "${extra_conditions}"
+ ">"
+ ":${objects}>"
+ )
+ target_link_libraries(${target} INTERFACE
+ "${target_link_libraries_genex}"
+ )
+endfunction()
+
+# Performs linking and propagation of the object library via the target's usage requirements.
+# Arguments:
+# NO_LINK_OBJECT_LIBRARY_REQUIREMENTS_TO_TARGET skip linking of ${object_library} to ${target}, only
+# propagate $<TARGET_OBJECTS:${object_library}> by linking it to ${target}. It's useful in case
+# if ${object_library} depends on the ${target}. E.g. resource libraries depend on the Core
+# library so linking them back to Core will cause a CMake error.
+#
+# EXTRA_CONDITIONS object library specific conditions to be checked before link the object library
+# to the end-point executable.
+function(__qt_internal_propagate_object_library target object_library)
+ set(options NO_LINK_OBJECT_LIBRARY_REQUIREMENTS_TO_TARGET)
+ set(single_args "")
+ set(multi_args EXTRA_CONDITIONS)
+ cmake_parse_arguments(arg "${options}" "${single_args}" "${multi_args}" ${ARGN})
+
+ get_target_property(is_imported ${object_library} IMPORTED)
+ if(NOT is_imported)
+ target_link_libraries(${object_library} PRIVATE ${QT_CMAKE_EXPORT_NAMESPACE}::Platform)
+ _qt_internal_copy_dependency_properties(${object_library} ${target} PRIVATE_ONLY)
+ endif()
+
+ # After internal discussion we decided to not rely on the linker order that CMake
+ # offers, until CMake provides the guaranteed linking order that suites our needs in a
+ # future CMake version.
+ # All object libraries mark themselves with the _is_qt_propagated_object_library property.
+ # Using a finalizer approach we walk through the target dependencies and look for libraries
+ # using the _is_qt_propagated_object_library property. Then, objects of the collected libraries
+ # are moved to the beginning of the linker line using target_sources.
+ #
+ # Note: target_link_libraries works well with linkers other than ld. If user didn't enforce
+ # a finalizer we rely on linker to resolve circular dependencies between objects and static
+ # libraries.
+ set_property(TARGET ${object_library} PROPERTY _is_qt_propagated_object_library TRUE)
+ if(NOT is_imported)
+ set_property(TARGET ${object_library} APPEND PROPERTY
+ EXPORT_PROPERTIES _is_qt_propagated_object_library
+ )
+ endif()
+
+ # Keep the implicit linking if finalizers are not used.
+ set(not_finalizer_mode_condition
+ "$<NOT:$<BOOL:$<TARGET_PROPERTY:_qt_object_libraries_finalizer_mode>>>"
+ )
+
+ # Use TARGET_NAME to have the correct namespaced name in the exports.
+ set(objects "$<TARGET_OBJECTS:$<TARGET_NAME:${object_library}>>")
+
+ __qt_internal_propagate_object_files(${target} ${objects}
+ EXTRA_CONDITIONS ${arg_EXTRA_CONDITIONS}
+ EXTRA_TARGET_SOURCES_CONDITIONS ${not_finalizer_mode_condition}
+ EXTRA_TARGET_LINK_LIBRARIES_CONDITIONS ${not_finalizer_mode_condition}
+ )
+
+ if(NOT arg_NO_LINK_OBJECT_LIBRARY_REQUIREMENTS_TO_TARGET)
+ # It's necessary to link the object library target, since we want to pass the object library
+ # dependencies to the 'target'. Interface linking doesn't add the objects of the library to
+ # the end-point linker line but propagates all the dependencies of the object_library added
+ # before or AFTER the line below.
+ target_link_libraries(${target} INTERFACE ${object_library})
+ endif()
+endfunction()
+
function(__qt_propagate_generated_resource target resource_name generated_source_code output_generated_target)
get_target_property(type ${target} TYPE)
if(type STREQUAL STATIC_LIBRARY)
@@ -1146,8 +2000,38 @@ function(__qt_propagate_generated_resource target resource_name generated_source
math(EXPR resource_count "${resource_count} + 1")
set_target_properties(${target} PROPERTIES _qt_generated_resource_target_count ${resource_count})
+ __qt_internal_generate_init_resource_source_file(
+ resource_init_file ${target} ${resource_name})
+
set(resource_target "${target}_resources_${resource_count}")
- add_library("${resource_target}" OBJECT "${generated_source_code}")
+ add_library("${resource_target}" OBJECT "${resource_init_file}")
+ set_target_properties(${resource_target} PROPERTIES
+ AUTOMOC FALSE
+ AUTOUIC FALSE
+ AUTORCC FALSE
+ )
+ # Needed so that qtsymbolmacros.h and its dependent headers are already created / syncqt'ed.
+ if(TARGET Core_sync_headers)
+ set(headers_available_target "Core_sync_headers")
+ else()
+ set(headers_available_target "${QT_CMAKE_EXPORT_NAMESPACE}::Core")
+ endif()
+ add_dependencies(${resource_target} ${headers_available_target})
+ target_compile_definitions("${resource_target}" PRIVATE
+ "$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Core,INTERFACE_COMPILE_DEFINITIONS>"
+ )
+ target_include_directories("${resource_target}" PRIVATE
+ "$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Core,INTERFACE_INCLUDE_DIRECTORIES>"
+ )
+ _qt_internal_set_up_static_runtime_library("${resource_target}")
+
+ # Special handling is required for the Core library resources. The linking of the Core
+ # library to the resources adds a circular dependency. This leads to the wrong
+ # objects/library order in the linker command line, since the Core library target is
+ # resolved first.
+ if(NOT target STREQUAL "Core")
+ target_link_libraries(${resource_target} INTERFACE ${QT_CMAKE_EXPORT_NAMESPACE}::Core)
+ endif()
set_property(TARGET ${resource_target} APPEND PROPERTY _qt_resource_name ${resource_name})
# Save the path to the generated source file, relative to the the current build dir.
@@ -1157,153 +2041,286 @@ function(__qt_propagate_generated_resource target resource_name generated_source
# .rcc/qrc_qprintdialog.cpp
file(RELATIVE_PATH generated_cpp_file_relative_path
"${CMAKE_CURRENT_BINARY_DIR}"
- "${generated_source_code}")
+ "${resource_init_file}")
set_property(TARGET ${resource_target} APPEND PROPERTY
_qt_resource_generated_cpp_relative_path "${generated_cpp_file_relative_path}")
- # Use TARGET_NAME genex to map to the correct prefixed target name when it is exported
- # via qt_install(EXPORT), so that the consumers of the target can find the object library
- # as well.
- target_link_libraries(${target} INTERFACE
- "$<TARGET_OBJECTS:$<TARGET_NAME:${resource_target}>>")
- set(${output_generated_target} "${resource_target}" PARENT_SCOPE)
+ if(target STREQUAL "Core")
+ set(skip_direct_linking NO_LINK_OBJECT_LIBRARY_REQUIREMENTS_TO_TARGET)
+ endif()
+ __qt_internal_propagate_object_library(${target} ${resource_target}
+ ${skip_direct_linking}
+ )
- # No need to compile Q_IMPORT_PLUGIN-containing files for non-executables.
- _qt_internal_disable_static_default_plugins("${resource_target}")
+ set(${output_generated_target} "${resource_target}" PARENT_SCOPE)
else()
set(${output_generated_target} "" PARENT_SCOPE)
- target_sources(${target} PRIVATE ${generated_source_code})
endif()
+
+ target_sources(${target} PRIVATE ${generated_source_code})
+endfunction()
+
+function(__qt_internal_sanitize_resource_name out_var name)
+ # The sanitized output should match RCCResourceLibrary::writeInitializer()'s
+ # isAsciiLetterOrNumber-based substituion.
+ # MAKE_C_IDENTIFIER matches that, it replaces non-alphanumeric chars with underscores.
+ string(MAKE_C_IDENTIFIER "${name}" sanitized_resource_name)
+ set(${out_var} "${sanitized_resource_name}" PARENT_SCOPE)
+endfunction()
+
+function(__qt_internal_generate_init_resource_source_file out_var target resource_name)
+ set(template_file "${__qt_core_macros_module_base_dir}/Qt6CoreResourceInit.in.cpp")
+
+ # Gets replaced in the template
+ __qt_internal_sanitize_resource_name(RESOURCE_NAME "${resource_name}")
+ set(resource_init_path "${CMAKE_CURRENT_BINARY_DIR}/.qt/rcc/qrc_${resource_name}_init.cpp")
+
+ configure_file("${template_file}" "${resource_init_path}" @ONLY)
+
+ set(scope_args "")
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${target})
+ endif()
+ set_source_files_properties(${resource_init_path} ${scope_args} PROPERTIES
+ SKIP_AUTOGEN TRUE
+ SKIP_UNITY_BUILD_INCLUSION TRUE
+ SKIP_PRECOMPILE_HEADERS TRUE
+ )
+
+ set(${out_var} "${resource_init_path}" PARENT_SCOPE)
endfunction()
-# Creates fake targets and adds resource files to IDE's tree
+# Make file visible in IDEs.
+# Targets that are finalized add the file as HEADER_FILE_ONLY in the finalizer.
+# Targets that are not finalized add the file under a ${target}_other_files target.
function(_qt_internal_expose_source_file_to_ide target file)
- set(ide_target_extension "other_files")
- set(qml_extensions ".qml" ".js")
- get_filename_component(resource_extension "${file}" LAST_EXT)
- if(resource_extension IN_LIST qml_extensions)
- set(ide_target_extension "qml_files")
+ get_target_property(target_expects_finalization ${target} _qt_expects_finalization)
+ if(target_expects_finalization AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.19")
+ set_property(TARGET ${target} APPEND PROPERTY _qt_deferred_files ${file})
+ return()
endif()
- set(ide_target ${target}_${ide_target_extension})
+ # Fallback for targets that are not finalized: Create fake target under which the file is added.
+ set(ide_target ${target}_other_files)
if(NOT TARGET ${ide_target})
add_custom_target(${ide_target} SOURCES "${file}")
+
+ # The new Xcode build system requires a common target to drive the generation of files,
+ # otherwise project configuration fails.
+ # By adding ${target} as a dependency of ${target}_other_files,
+ # it becomes the common target, so project configuration succeeds.
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ add_dependencies(${ide_target} ${target})
+ endif()
else()
set_property(TARGET ${ide_target} APPEND PROPERTY SOURCES "${file}")
endif()
+
+ set(scope_args)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY "${target}")
+ endif()
+ get_source_file_property(
+ target_dependency "${file}" ${scope_args} _qt_resource_target_dependency)
+ if(target_dependency)
+ if(NOT TARGET "${target_dependency}")
+ message(FATAL_ERROR "Target dependency on source file ${file} is not a cmake target.")
+ endif()
+ add_dependencies(${ide_target} ${target_dependency})
+ endif()
+endfunction()
+
+# Called by the target finalizer.
+# Adds the files that were added to _qt_deferred_files to SOURCES.
+# Sets HEADER_FILES_ONLY if they did not exist yet in SOURCES.
+function(_qt_internal_expose_deferred_files_to_ide target)
+ get_target_property(new_sources ${target} _qt_deferred_files)
+ if(NOT new_sources)
+ return()
+ endif()
+ set(new_sources_real "")
+ foreach(f IN LISTS new_sources)
+ get_filename_component(realf "${f}" REALPATH)
+ list(APPEND new_sources_real ${realf})
+ endforeach()
+
+ set(filtered_new_sources "")
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ get_filename_component(target_source_dir "${target_source_dir}" REALPATH)
+ get_target_property(existing_sources ${target} SOURCES)
+ if(existing_sources)
+ set(existing_sources_real "")
+ set(realf "")
+ foreach(f IN LISTS existing_sources)
+ get_filename_component(realf "${f}" REALPATH BASE_DIR ${target_source_dir})
+ list(APPEND existing_sources_real ${realf})
+ endforeach()
+
+ list(LENGTH new_sources max_i)
+ math(EXPR max_i "${max_i} - 1")
+ foreach(i RANGE 0 ${max_i})
+ list(GET new_sources_real ${i} realf)
+ if(NOT realf IN_LIST existing_sources_real)
+ list(GET new_sources ${i} f)
+ list(APPEND filtered_new_sources ${f})
+ endif()
+ endforeach()
+ endif()
+ if("${filtered_new_sources}" STREQUAL "")
+ return()
+ endif()
+
+ target_sources(${target} PRIVATE ${filtered_new_sources})
+ set(scope_args)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY "${target}")
+ endif()
+ set_source_files_properties(${filtered_new_sources}
+ ${scope_args} PROPERTIES HEADER_FILE_ONLY ON)
endfunction()
#
# Process resources via file path instead of QRC files. Behind the
-# scnenes, it will generate a qrc file and apply post processing steps
-# when applicable. (e.g.: QtQuickCompiler)
+# scenes, it will generate a qrc file.
#
# The QRC Prefix is set via the PREFIX parameter.
#
# Alias settings for files need to be set via the QT_RESOURCE_ALIAS property
-# via the set_soure_files_properties() command.
+# via the set_source_files_properties() command.
#
# When using this command with static libraries, one or more special targets
# will be generated. Should you wish to perform additional processing on these
# targets pass a value to the OUTPUT_TARGETS parameter.
#
function(_qt_internal_process_resource target resourceName)
-
- cmake_parse_arguments(rcc "" "PREFIX;LANG;BASE;OUTPUT_TARGETS;DESTINATION" "FILES;OPTIONS" ${ARGN})
+ cmake_parse_arguments(rcc "BIG_RESOURCES"
+ "PREFIX;LANG;BASE;OUTPUT_TARGETS;DESTINATION" "FILES;OPTIONS" ${ARGN})
if("${rcc_OPTIONS}" MATCHES "-binary")
set(isBinary TRUE)
+ if(rcc_BIG_RESOURCES)
+ message(FATAL_ERROR "BIG_RESOURCES cannot be used together with the -binary option.")
+ endif()
+ endif()
+
+ if(rcc_BIG_RESOURCES AND CMAKE_GENERATOR STREQUAL "Xcode" AND IOS)
+ message(WARNING
+ "Due to CMake limitations, the BIG_RESOURCES option can't be used when building "
+ "for iOS. "
+ "See https://bugreports.qt.io/browse/QTBUG-103497 for details. "
+ "Falling back to using regular resources. "
+ )
+ set(rcc_BIG_RESOURCES OFF)
+ endif()
+
+ if(rcc_BIG_RESOURCES AND CMAKE_VERSION VERSION_LESS "3.17")
+ message(WARNING
+ "The BIG_RESOURCES option does not work reliably with CMake < 3.17. "
+ "Consider upgrading to a more recent CMake version or disable the BIG_RESOURCES "
+ "option for older CMake versions."
+ )
endif()
string(REPLACE "/" "_" resourceName ${resourceName})
string(REPLACE "." "_" resourceName ${resourceName})
- set(output_targets "")
- # Apply base to all files
- if (rcc_BASE)
- foreach(file IN LISTS rcc_FILES)
- set(resource_file "${rcc_BASE}/${file}")
- __qt_get_relative_resource_path_for_file(alias ${resource_file})
- # Handle case where resources were generated from a directory
- # different than the one where the main .pro file resides.
- # Unless otherwise specified, we should use the original file path
- # as alias.
- if (alias STREQUAL resource_file)
- set_source_files_properties(${resource_file} PROPERTIES QT_RESOURCE_ALIAS ${file})
+ set(resource_files "")
+ # Strip the ending slashes from the file_path. If paths contain slashes in the end
+ # set/get source properties works incorrect and may have the same QT_RESOURCE_ALIAS
+ # for two different paths. See https://gitlab.kitware.com/cmake/cmake/-/issues/23212
+ # for details.
+ foreach(file_path IN LISTS rcc_FILES)
+ if(file_path MATCHES "(.+)/$")
+ set(file_path "${CMAKE_MATCH_1}")
+ endif()
+ list(APPEND resource_files ${file_path})
+ endforeach()
+
+ if(NOT "${rcc_BASE}" STREQUAL "")
+ get_filename_component(abs_base "${rcc_BASE}" ABSOLUTE)
+ foreach(file_path IN LISTS resource_files)
+ get_source_file_property(alias "${file_path}" QT_RESOURCE_ALIAS)
+ if(alias STREQUAL "NOTFOUND")
+ get_filename_component(abs_file "${file_path}" ABSOLUTE)
+ file(RELATIVE_PATH rel_file "${abs_base}" "${abs_file}")
+ set_property(SOURCE "${file_path}" PROPERTY QT_RESOURCE_ALIAS "${rel_file}")
endif()
- file(TO_CMAKE_PATH ${resource_file} resource_file)
- list(APPEND resource_files ${resource_file})
endforeach()
- else()
- set(resource_files ${rcc_FILES})
+ endif()
+
+ if(ANDROID)
+ if(COMMAND _qt_internal_collect_qml_root_paths)
+ _qt_internal_collect_qml_root_paths(${target} ${resource_files})
+ endif()
endif()
if(NOT rcc_PREFIX)
get_target_property(rcc_PREFIX ${target} QT_RESOURCE_PREFIX)
if (NOT rcc_PREFIX)
- message(FATAL_ERROR "_qt_internal_process_resource() was called without a PREFIX and the target does not provide QT_RESOURCE_PREFIX. Please either add a PREFIX or make the target ${target} provide a default.")
+ set(rcc_PREFIX "/")
endif()
endif()
- # Apply quick compiler pass. This is only enabled when Qt6QmlMacros is
- # parsed.
- if (QT6_ADD_RESOURCE_DECLARATIVE_EXTENSIONS)
- _qt_internal_quick_compiler_process_resources(${target} ${resourceName}
- FILES ${resource_files}
- PREFIX ${rcc_PREFIX}
- OUTPUT_REMAINING_RESOURCES resources
- OUTPUT_RESOURCE_NAME newResourceName
- OUTPUT_GENERATED_TARGET output_target_quick
- )
- else()
- set(newResourceName ${resourceName})
- set(resources ${resource_files})
- endif()
-
- if (NOT resources)
+ if (NOT resource_files)
if (rcc_OUTPUT_TARGETS)
- set(${rcc_OUTPUT_TARGETS} "${output_target_quick}" PARENT_SCOPE)
+ set(${rcc_OUTPUT_TARGETS} "" PARENT_SCOPE)
endif()
return()
endif()
- list(APPEND output_targets ${output_target_quick})
- set(generatedBaseName "${newResourceName}")
- set(generatedResourceFile "${CMAKE_CURRENT_BINARY_DIR}/.rcc/${generatedBaseName}.qrc")
+ set(generatedResourceFile "${CMAKE_CURRENT_BINARY_DIR}/.qt/rcc/${resourceName}.qrc")
+ _qt_internal_expose_source_file_to_ide(${target} ${generatedResourceFile})
+ set_source_files_properties(${generatedResourceFile} PROPERTIES GENERATED TRUE)
# Generate .qrc file:
# <RCC><qresource ...>
set(qrcContents "<RCC>\n <qresource")
- if (rcc_PREFIX)
- string(APPEND qrcContents " prefix=\"${rcc_PREFIX}\"")
- endif()
+ string(APPEND qrcContents " prefix=\"${rcc_PREFIX}\"")
+
if (rcc_LANG)
string(APPEND qrcContents " lang=\"${rcc_LANG}\"")
endif()
string(APPEND qrcContents ">\n")
set(resource_dependencies)
- foreach(file IN LISTS resources)
+ foreach(file IN LISTS resource_files)
__qt_get_relative_resource_path_for_file(file_resource_path ${file})
if (NOT IS_ABSOLUTE ${file})
set(file "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
endif()
+ get_property(is_empty SOURCE ${file} PROPERTY QT_DISCARD_FILE_CONTENTS)
+
### FIXME: escape file paths to be XML conform
# <file ...>...</file>
- string(APPEND qrcContents " <file alias=\"${file_resource_path}\">")
- string(APPEND qrcContents "${file}</file>\n")
+ string(APPEND qrcContents " <file alias=\"${file_resource_path}\"")
+ if(is_empty)
+ string(APPEND qrcContents " empty=\"true\"")
+ endif()
+ string(APPEND qrcContents ">${file}</file>\n")
list(APPEND files "${file}")
- get_source_file_property(target_dependency ${file} QT_RESOURCE_TARGET_DEPENDENCY)
- if (NOT target_dependency)
- list(APPEND resource_dependencies ${file})
- else()
- if (NOT TARGET ${target_dependency})
- message(FATAL_ERROR "Target dependency on resource file ${file} is not a cmake target.")
+ set(scope_args)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${target})
+ endif()
+ get_source_file_property(
+ target_dependency ${file} ${scope_args} _qt_resource_target_dependency)
+
+ # The target dependency code path does not take care of rebuilds when ${file}
+ # is touched. Limit its usage to the Xcode generator to avoid the Xcode common
+ # dependency issue.
+ # TODO: Figure out how to avoid the issue on Xcode, while also enabling proper
+ # dependency tracking when ${file} is touched.
+ if(target_dependency AND CMAKE_GENERATOR STREQUAL "Xcode")
+ if(NOT TARGET ${target_dependency})
+ message(FATAL_ERROR
+ "Target dependency on resource file ${file} is not a cmake target.")
endif()
list(APPEND resource_dependencies ${target_dependency})
+ else()
+ list(APPEND resource_dependencies ${file})
endif()
_qt_internal_expose_source_file_to_ide(${target} "${file}")
endforeach()
@@ -1315,10 +2332,11 @@ function(_qt_internal_process_resource target resourceName)
set(qt_core_configure_file_contents "${qrcContents}")
configure_file("${template_file}" "${generatedResourceFile}")
- set(rccArgs --name "${newResourceName}" "${generatedResourceFile}")
+ set(rccArgs --name "${resourceName}" "${generatedResourceFile}")
+ set(rccArgsAllPasses "")
if(rcc_OPTIONS)
- list(APPEND rccArgs ${rcc_OPTIONS})
+ list(APPEND rccArgsAllPasses ${rcc_OPTIONS})
endif()
# When cross-building, we use host tools to generate target code. If the host rcc was compiled
@@ -1328,14 +2346,14 @@ function(_qt_internal_process_resource target resourceName)
# If the target does not support zstd (feature is disabled), tell rcc not to generate
# zstd related code.
if(NOT QT_FEATURE_zstd)
- list(APPEND rccArgs "--no-zstd")
+ list(APPEND rccArgsAllPasses "--no-zstd")
endif()
set_property(SOURCE "${generatedResourceFile}" PROPERTY SKIP_AUTOGEN ON)
# Set output file name for rcc command
if(isBinary)
- set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/${generatedBaseName}.rcc")
+ set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/${resourceName}.rcc")
if(rcc_DESTINATION)
# Add .rcc suffix if it's not specified by user
get_filename_component(destinationRccExt "${rcc_DESTINATION}" LAST_EXT)
@@ -1345,68 +2363,155 @@ function(_qt_internal_process_resource target resourceName)
set(generatedOutfile "${rcc_DESTINATION}.rcc")
endif()
endif()
+ elseif(rcc_BIG_RESOURCES)
+ set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/.qt/rcc/qrc_${resourceName}_tmp.cpp")
else()
- set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qrc_${newResourceName}.cpp")
+ set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/.qt/rcc/qrc_${resourceName}.cpp")
+ endif()
+
+ set(pass_msg)
+ if(rcc_BIG_RESOURCES)
+ list(PREPEND rccArgs --pass 1)
+ set(pass_msg " pass 1")
endif()
list(PREPEND rccArgs --output "${generatedOutfile}")
# Process .qrc file:
add_custom_command(OUTPUT "${generatedOutfile}"
- COMMAND "${QT_CMAKE_EXPORT_NAMESPACE}::rcc" ${rccArgs}
+ COMMAND "${QT_CMAKE_EXPORT_NAMESPACE}::rcc" ${rccArgs} ${rccArgsAllPasses}
DEPENDS
${resource_dependencies}
${generatedResourceFile}
"${QT_CMAKE_EXPORT_NAMESPACE}::rcc"
- COMMENT "RCC ${newResourceName}"
+ COMMENT "Running rcc${pass_msg} for resource ${resourceName}"
VERBATIM)
if(isBinary)
# Add generated .rcc target to 'all' set
- add_custom_target(binary_resource_${generatedBaseName} ALL DEPENDS "${generatedOutfile}")
- else()
- set_property(SOURCE "${generatedOutfile}" PROPERTY SKIP_AUTOGEN ON)
- set_property(TARGET ${target} APPEND PROPERTY _qt_generated_qrc_files "${generatedResourceFile}")
-
- # Only do this if newResourceName is the same as resourceName, since
- # the resource will be chainloaded by the qt quickcompiler
- # qml cache loader
- if(newResourceName STREQUAL resourceName)
- __qt_propagate_generated_resource(${target} ${resourceName} "${generatedOutfile}" output_target)
- list(APPEND output_targets ${output_target})
+ add_custom_target(binary_resource_${resourceName} ALL DEPENDS "${generatedOutfile}")
+ return()
+ endif()
+
+ # We can't rely on policy CMP0118 since user project controls it.
+ # We also want SKIP_AUTOGEN known in the target's scope, where we can.
+ set(scope_args)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${target})
+ endif()
+ set_source_files_properties(${generatedOutfile} ${scope_args} PROPERTIES
+ SKIP_AUTOGEN TRUE
+ GENERATED TRUE
+ SKIP_UNITY_BUILD_INCLUSION TRUE
+ SKIP_PRECOMPILE_HEADERS TRUE
+ )
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.27")
+ set_source_files_properties(${generatedOutfile} ${scope_args} PROPERTIES SKIP_LINTING ON)
+ endif()
+
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ if(NOT target_source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ # We have to create a separate target in this scope that depends on
+ # the generated file, otherwise the original target won't have the
+ # required dependencies in place to ensure correct build order.
+ add_custom_target(${target}_${resourceName} DEPENDS ${generatedOutfile})
+ add_dependencies(${target} ${target}_${resourceName})
+ endif()
+
+ if(rcc_BIG_RESOURCES)
+ set(pass1OutputFile ${generatedOutfile})
+ set(generatedOutfile
+ "${CMAKE_CURRENT_BINARY_DIR}/.qt/rcc/qrc_${resourceName}${CMAKE_CXX_OUTPUT_EXTENSION}")
+ _qt_internal_add_rcc_pass2(
+ RESOURCE_NAME ${resourceName}
+ RCC_OPTIONS ${rccArgsAllPasses}
+ OBJECT_LIB ${target}_${resourceName}_obj
+ QRC_FILE ${generatedResourceFile}
+ PASS1_OUTPUT_FILE ${pass1OutputFile}
+ OUT_OBJECT_FILE ${generatedOutfile}
+ )
+ get_target_property(type ${target} TYPE)
+ if(type STREQUAL STATIC_LIBRARY)
+ # Create a custom target to trigger the generation of ${generatedOutfile}
+ set(pass2_target ${target}_${resourceName}_pass2)
+ add_custom_target(${pass2_target} DEPENDS ${generatedOutfile})
+ add_dependencies(${target} ${pass2_target})
+
+ # Propagate the object files to the target.
+ __qt_internal_propagate_object_files(${target} "${generatedOutfile}")
else()
- target_sources(${target} PRIVATE "${generatedOutfile}")
- endif()
- if (rcc_OUTPUT_TARGETS)
- set(${rcc_OUTPUT_TARGETS} "${output_targets}" PARENT_SCOPE)
+ target_sources(${target} PRIVATE ${generatedOutfile})
endif()
+ else()
+ __qt_propagate_generated_resource(${target} ${resourceName} "${generatedOutfile}"
+ output_targets)
+ endif()
+
+ set_property(TARGET ${target}
+ APPEND PROPERTY _qt_generated_qrc_files "${generatedResourceFile}")
+
+ if (rcc_OUTPUT_TARGETS)
+ set(${rcc_OUTPUT_TARGETS} "${output_targets}" PARENT_SCOPE)
endif()
endfunction()
-# This function is currently in Technical Preview.
-# It's signature and behavior might change.
-function(qt6_add_plugin target)
- cmake_parse_arguments(arg
- "STATIC"
- "OUTPUT_NAME;CLASS_NAME;TYPE"
- ""
- ${ARGN}
+macro(_qt_internal_get_add_plugin_keywords option_args single_args multi_args)
+ set(${option_args}
+ STATIC
+ SHARED
+ __QT_INTERNAL_NO_PROPAGATE_PLUGIN_INITIALIZER
+ )
+ set(${single_args}
+ PLUGIN_TYPE # Internal use only, may be changed or removed
+ CLASS_NAME
+ OUTPUT_NAME # Internal use only, may be changed or removed
+ OUTPUT_TARGETS
)
- if (arg_STATIC)
- add_library(${target} STATIC)
+ set(${multi_args})
+endmacro()
+
+function(qt6_add_plugin target)
+ _qt_internal_get_add_plugin_keywords(opt_args single_args multi_args)
+ list(APPEND opt_args MANUAL_FINALIZATION)
+
+ cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
+
+ if(arg_STATIC AND arg_SHARED)
+ message(FATAL_ERROR
+ "Both STATIC and SHARED options were given. Only one of the two should be used."
+ )
+ endif()
+
+ # Explicit option takes priority over the computed default.
+ if(arg_STATIC)
+ set(create_static_plugin TRUE)
+ elseif(arg_SHARED)
+ set(create_static_plugin FALSE)
else()
- add_library(${target} MODULE)
- if(APPLE)
- # CMake defaults to using .so extensions for loadable modules, aka plugins,
- # but Qt plugins are actually suffixed with .dylib.
- set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib")
- endif()
- if(WIN32)
- # CMake sets for Windows-GNU platforms the suffix "lib"
- set_property(TARGET "${target}" PROPERTY PREFIX "")
+ # If no explicit STATIC/SHARED option is set, default to the flavor of the Qt build.
+ if(QT6_IS_SHARED_LIBS_BUILD)
+ set(create_static_plugin FALSE)
+ else()
+ set(create_static_plugin TRUE)
endif()
endif()
+ # The default of _qt_internal_add_library creates SHARED in a shared Qt build, so we need to
+ # be explicit about the MODULE.
+ if(create_static_plugin)
+ set(type_to_create STATIC)
+ else()
+ set(type_to_create MODULE)
+ endif()
+
+ _qt_internal_add_library(${target} ${type_to_create} ${arg_UNPARSED_ARGUMENTS})
+ set_property(TARGET ${target} PROPERTY _qt_expects_finalization TRUE)
+
+ get_target_property(target_type "${target}" TYPE)
+ if (target_type STREQUAL "STATIC_LIBRARY")
+ target_compile_definitions(${target} PRIVATE QT_STATICPLUGIN)
+ endif()
+
set(output_name ${target})
if (arg_OUTPUT_NAME)
set(output_name ${arg_OUTPUT_NAME})
@@ -1414,42 +2519,237 @@ function(qt6_add_plugin target)
set_property(TARGET "${target}" PROPERTY OUTPUT_NAME "${output_name}")
if (ANDROID)
- qt6_android_apply_arch_suffix("${target}")
set_target_properties(${target}
PROPERTIES
- LIBRARY_OUTPUT_NAME "plugins_${arg_TYPE}_${output_name}"
+ LIBRARY_OUTPUT_NAME "plugins_${arg_PLUGIN_TYPE}_${output_name}"
)
endif()
# Derive the class name from the target name if it's not explicitly specified.
set(plugin_class_name "")
- if (NOT arg_CLASS_NAME)
- set(plugin_class_name "${target}")
+ if (NOT "${arg_PLUGIN_TYPE}" STREQUAL "qml_plugin")
+ if (NOT arg_CLASS_NAME)
+ set(plugin_class_name "${target}")
+ else()
+ set(plugin_class_name "${arg_CLASS_NAME}")
+ endif()
else()
- set(plugin_class_name "${arg_CLASS_NAME}")
+ # Make sure to set any passed-in class name for qml plugins as well, because it's used for
+ # building the qml plugin foo_init object libraries.
+ if(arg_CLASS_NAME)
+ set(plugin_class_name "${arg_CLASS_NAME}")
+ else()
+ message(FATAL_ERROR "Qml plugin target has no CLASS_NAME specified: '${target}'")
+ endif()
endif()
+
set_target_properties(${target} PROPERTIES QT_PLUGIN_CLASS_NAME "${plugin_class_name}")
- set(static_plugin_define "")
- if (arg_STATIC)
- set(static_plugin_define "QT_STATICPLUGIN")
+ # Create a plugin initializer object library for static plugins.
+ # It contains a Q_IMPORT_PLUGIN(QT_PLUGIN_CLASS_NAME) call.
+ # Project targets will automatically link to the plugin initializer whenever they link to the
+ # plugin target.
+ # The plugin init target name is stored in OUTPUT_TARGETS, so projects may install them.
+ # Qml plugin inits are handled in Qt6QmlMacros.
+ if(NOT "${arg_PLUGIN_TYPE}" STREQUAL "qml_plugin"
+ AND target_type STREQUAL "STATIC_LIBRARY")
+ __qt_internal_add_static_plugin_init_object_library("${target}" plugin_init_target)
+
+ if(arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} ${plugin_init_target} PARENT_SCOPE)
+ endif()
+
+ # We don't automatically propagate the plugin init library for Qt provided plugins, because
+ # there are 2 other code paths that take care of that, one involving finalizers and the
+ # other regular usage requirements.
+ if(NOT arg___QT_INTERNAL_NO_PROPAGATE_PLUGIN_INITIALIZER)
+ __qt_internal_propagate_object_library("${target}" "${plugin_init_target}")
+ endif()
+ else()
+ if(arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} "" PARENT_SCOPE)
+ endif()
endif()
+
target_compile_definitions(${target} PRIVATE
QT_PLUGIN
QT_DEPRECATED_WARNINGS
- ${static_plugin_define}
)
+
+ if(target_type STREQUAL "MODULE_LIBRARY")
+ if(NOT TARGET qt_internal_plugins)
+ add_custom_target(qt_internal_plugins)
+ _qt_internal_assign_to_internal_targets_folder(qt_internal_plugins)
+ endif()
+ add_dependencies(qt_internal_plugins ${target})
+ endif()
+
+ if(arg_MANUAL_FINALIZATION)
+ # Caller says they will call qt6_finalize_target() themselves later
+ return()
+ endif()
+
+ # Defer the finalization if we can. When the caller's project requires
+ # CMake 3.19 or later, this makes the calls to this function concise while
+ # still allowing target property modification before finalization.
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19)
+ # Need to wrap in an EVAL CODE or else ${target} won't be evaluated
+ # due to special behavior of cmake_language() argument handling
+ cmake_language(EVAL CODE "cmake_language(DEFER CALL qt6_finalize_target ${target})")
+ else()
+ set_target_properties("${target}" PROPERTIES _qt_is_immediately_finalized TRUE)
+ qt6_finalize_target("${target}")
+ endif()
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_add_plugin)
qt6_add_plugin(${ARGV})
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "OUTPUT_TARGETS" "")
+ if(arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} ${${arg_OUTPUT_TARGETS}} PARENT_SCOPE)
+ endif()
endfunction()
endif()
-# By default Qt6 forces usage of utf8 sources for consumers of Qt.
-# Users can opt out of utf8 sources by calling this function with the target name of their
-# application or library.
+# Creates a library by forwarding arguments to add_library, applies some Qt naming file name naming
+# conventions and ensures the execution of Qt specific finalizers.
+function(qt6_add_library target)
+ cmake_parse_arguments(PARSE_ARGV 1 arg "MANUAL_FINALIZATION" "" "")
+
+ _qt_internal_add_library("${target}" ${arg_UNPARSED_ARGUMENTS})
+ set_property(TARGET ${target} PROPERTY _qt_expects_finalization TRUE)
+
+ if(arg_MANUAL_FINALIZATION)
+ # Caller says they will call qt6_finalize_target() themselves later
+ return()
+ endif()
+
+ # Defer the finalization if we can. When the caller's project requires
+ # CMake 3.19 or later, this makes the calls to this function concise while
+ # still allowing target property modification before finalization.
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19)
+ # Need to wrap in an EVAL CODE or else ${target} won't be evaluated
+ # due to special behavior of cmake_language() argument handling
+ cmake_language(EVAL CODE "cmake_language(DEFER CALL qt6_finalize_target ${target})")
+ else()
+ set_target_properties("${target}" PROPERTIES _qt_is_immediately_finalized TRUE)
+ qt6_finalize_target("${target}")
+ endif()
+endfunction()
+
+# Creates a library target by forwarding the arguments to add_library.
+#
+# Applies some Qt specific behaviors:
+# - If no type option is specified, rather than defaulting to STATIC it defaults to STATIC or SHARED
+# depending on the Qt configuration.
+# - Applies Qt specific prefixes and suffixes to file names depending on platform.
+function(_qt_internal_add_library target)
+ set(opt_args
+ STATIC
+ SHARED
+ MODULE
+ INTERFACE
+ OBJECT
+ )
+ set(single_args "")
+ set(multi_args "")
+ cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
+
+ set(option_type_count 0)
+ if(arg_STATIC)
+ set(type_to_create STATIC)
+ math(EXPR option_type_count "${option_type_count}+1")
+ elseif(arg_SHARED)
+ set(type_to_create SHARED)
+ math(EXPR option_type_count "${option_type_count}+1")
+ elseif(arg_MODULE)
+ set(type_to_create MODULE)
+ math(EXPR option_type_count "${option_type_count}+1")
+ elseif(arg_INTERFACE)
+ set(type_to_create INTERFACE)
+ math(EXPR option_type_count "${option_type_count}+1")
+ elseif(arg_OBJECT)
+ set(type_to_create OBJECT)
+ math(EXPR option_type_count "${option_type_count}+1")
+ endif()
+
+ if(option_type_count GREATER 1)
+ message(FATAL_ERROR
+ "Multiple type options were given. Only one should be used."
+ )
+ endif()
+
+ # If no explicit type option is set, default to the flavor of the Qt build.
+ # This in contrast to CMake which defaults to STATIC.
+ if(NOT arg_STATIC AND NOT arg_SHARED AND NOT arg_MODULE AND NOT arg_INTERFACE
+ AND NOT arg_OBJECT)
+ if(DEFINED BUILD_SHARED_LIBS AND NOT QT_BUILDING_QT AND NOT QT_BUILD_STANDALONE_TESTS)
+ __qt_internal_setup_policy(QTP0003 "6.7.0"
+ "BUILD_SHARED_LIBS is set to ${BUILD_SHARED_LIBS} but it has no effect on\
+ default library type created by Qt CMake API commands. The default library type\
+ is set to the Qt build type.\
+ This behavior can be changed by setting QTP0003 to NEW.\
+ Check https://doc.qt.io/qt-6/qt-cmake-policy-qtp0003.html for policy details."
+ )
+ qt6_policy(GET QTP0003 build_shared_libs_policy)
+ else()
+ set(build_shared_libs_policy "")
+ endif()
+
+ if(build_shared_libs_policy STREQUAL "NEW" OR QT_BUILDING_QT OR QT_BUILD_STANDALONE_TESTS)
+ if(BUILD_SHARED_LIBS OR (NOT DEFINED BUILD_SHARED_LIBS AND QT6_IS_SHARED_LIBS_BUILD))
+ set(type_to_create SHARED)
+ else()
+ set(type_to_create STATIC)
+ endif()
+ else()
+ if(QT6_IS_SHARED_LIBS_BUILD)
+ set(type_to_create SHARED)
+ else()
+ set(type_to_create STATIC)
+ endif()
+ endif()
+ endif()
+
+ add_library(${target} ${type_to_create} ${arg_UNPARSED_ARGUMENTS})
+ _qt_internal_disable_autorcc_zstd_when_not_supported("${target}")
+ _qt_internal_set_up_static_runtime_library(${target})
+
+ if(NOT type_to_create STREQUAL "INTERFACE" AND NOT type_to_create STREQUAL "OBJECT")
+ _qt_internal_apply_win_prefix_and_suffix("${target}")
+ endif()
+
+ if(arg_MODULE AND APPLE)
+ # CMake defaults to using .so extensions for loadable modules, aka plugins,
+ # but Qt plugins are actually suffixed with .dylib.
+ set_property(TARGET "${target}" PROPERTY SUFFIX ".dylib")
+ endif()
+
+ if(ANDROID)
+ set_property(TARGET "${target}"
+ PROPERTY _qt_android_apply_arch_suffix_called_from_qt_impl TRUE)
+ qt6_android_apply_arch_suffix("${target}")
+ endif()
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_add_library)
+ qt6_add_library(${ARGV})
+ endfunction()
+endif()
+
+# TODO: Remove once all repositories use qt_internal_add_example instead of add_subdirectory.
+macro(_qt_internal_override_example_install_dir_to_dot)
+ # Set INSTALL_EXAMPLEDIR to ".".
+ # This overrides the install destination of unclean Qt example projects to install directly
+ # to CMAKE_INSTALL_PREFIX.
+ if(QT_INTERNAL_SET_EXAMPLE_INSTALL_DIR_TO_DOT)
+ set(INSTALL_EXAMPLEDIR ".")
+ set(_qt_internal_example_dir_set_to_dot TRUE)
+ endif()
+endmacro()
+
function(qt6_allow_non_utf8_sources target)
set_target_properties("${target}" PROPERTIES QT_NO_UTF8_SOURCE TRUE)
endfunction()
@@ -1475,3 +2775,986 @@ function(_qt_internal_apply_strict_cpp target)
endif()
endif()
endfunction()
+
+# Copies properties of the dependency to the target.
+# Arguments:
+# PROPERTIES list of properties to copy. If not specified the following properties are copied
+# by default: INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES COMPILE_DEFINITIONS
+# COMPILE_OPTIONS COMPILE_FEATURES
+# PRIVATE_ONLY copy only private properties (without INTERFACE analogues). Optional.
+# INTERFACE_ONLY copy only interface properties (without non-prefixed analogues). Optional.
+# Note: Not all properties have INTERFACE properties analogues.
+# See https://cmake.org/cmake/help/latest/prop_tgt/EXPORT_PROPERTIES.html for details.
+#
+# PRIVATE_ONLY and INTERFACE_ONLY in the same call are not allowed. Omit these options to copy
+# both sets.
+function(_qt_internal_copy_dependency_properties target dependency)
+ cmake_parse_arguments(arg "INTERFACE_ONLY;PRIVATE_ONLY" "" "PROPERTIES" ${ARGN})
+ if(arg_PRIVATE_ONLY AND arg_INTERFACE_ONLY)
+ message("Both PRIVATE_ONLY and INTERFACE_ONLY options are set.\
+Please use _qt_internal_copy_dependency_properties without these options to copy a set of
+properties of both types."
+ )
+ endif()
+
+ if(arg_PROPERTIES)
+ set(common_props_to_set ${arg_PROPERTIES})
+ else()
+ set(common_props_to_set
+ INCLUDE_DIRECTORIES SYSTEM_INCLUDE_DIRECTORIES
+ COMPILE_DEFINITIONS COMPILE_OPTIONS
+ COMPILE_FEATURES
+ )
+ endif()
+
+ set(props_to_set "")
+ if(NOT arg_INTERFACE_ONLY)
+ set(props_to_set ${common_props_to_set})
+ endif()
+ if(NOT arg_PRIVATE_ONLY)
+ list(TRANSFORM common_props_to_set PREPEND INTERFACE_
+ OUTPUT_VARIABLE interface_properties)
+ list(APPEND props_to_set ${interface_properties})
+ endif()
+
+ foreach(prop ${props_to_set})
+ set_property(TARGET
+ "${target}" APPEND PROPERTY
+ ${prop} "$<TARGET_PROPERTY:${dependency},${prop}>"
+ )
+ endforeach()
+endfunction()
+
+function(qt6_disable_unicode_defines target)
+ set_target_properties(${target} PROPERTIES QT_NO_UNICODE_DEFINES TRUE)
+endfunction()
+
+# Finalizer function for the top-level user projects.
+#
+# This function is currently in Technical Preview.
+# Its signature and behavior might change.
+function(qt6_finalize_project)
+ if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
+ message("qt6_finalize_project is called not in the top-level CMakeLists.txt.")
+ endif()
+ if(ANDROID)
+ _qt_internal_collect_apk_dependencies()
+ endif()
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ function(qt_finalize_project)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_finalize_project()
+ else()
+ message(FATAL_ERROR "qt_finalize_project() is only available in Qt 6.")
+ endif()
+ endfunction()
+
+ function(qt_disable_unicode_defines)
+ qt6_disable_unicode_defines(${ARGV})
+ endfunction()
+endif()
+
+function(_qt_internal_get_deploy_impl_dir var)
+ set(${var} "${CMAKE_BINARY_DIR}/.qt" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_add_deploy_support deploy_support_file)
+ get_filename_component(deploy_support_file "${deploy_support_file}" REALPATH)
+
+ set(target ${QT_CMAKE_EXPORT_NAMESPACE}::Core)
+ get_target_property(aliased_target ${target} ALIASED_TARGET)
+ if(aliased_target)
+ set(target ${aliased_target})
+ endif()
+
+ get_property(scripts TARGET ${target} PROPERTY _qt_deploy_support_files)
+ if(NOT "${deploy_support_file}" IN_LIST scripts)
+ set_property(TARGET ${target} APPEND PROPERTY
+ _qt_deploy_support_files "${deploy_support_file}"
+ )
+ endif()
+endfunction()
+
+# Sets up the commands for use at install/deploy time
+function(_qt_internal_setup_deploy_support)
+ if(QT_SKIP_SETUP_DEPLOYMENT)
+ return()
+ endif()
+
+ get_property(cmake_role GLOBAL PROPERTY CMAKE_ROLE)
+ if(NOT cmake_role STREQUAL "PROJECT")
+ return()
+ endif()
+
+ # Always set QT_DEPLOY_SUPPORT in the caller's scope, even if we've generated
+ # the deploy support file in a previous call. The project may be calling
+ # find_package() from sibling directories with separate variable scopes.
+ _qt_internal_get_deploy_impl_dir(deploy_impl_dir)
+
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ set(QT_DEPLOY_SUPPORT "${deploy_impl_dir}/QtDeploySupport-$<CONFIG>.cmake")
+ else()
+ set(QT_DEPLOY_SUPPORT "${deploy_impl_dir}/QtDeploySupport.cmake")
+ endif()
+ set(QT_DEPLOY_SUPPORT "${QT_DEPLOY_SUPPORT}" PARENT_SCOPE)
+
+ get_property(have_generated_file GLOBAL PROPERTY _qt_have_generated_deploy_support)
+ if(have_generated_file)
+ return()
+ endif()
+ set_property(GLOBAL PROPERTY _qt_have_generated_deploy_support TRUE)
+
+ include(GNUInstallDirs)
+ set(target ${QT_CMAKE_EXPORT_NAMESPACE}::Core)
+ get_target_property(aliased_target ${target} ALIASED_TARGET)
+ if(aliased_target)
+ set(target ${aliased_target})
+ endif()
+
+ # Generate deployment information for each target if the CMake version is recent enough.
+ # The call is deferred to have all targets of the projects available.
+ if(CMAKE_VERSION GREATER_EQUAL "3.19.0")
+ if(is_multi_config)
+ set(targets_file "${deploy_impl_dir}/QtDeployTargets-$<CONFIG>.cmake")
+ else()
+ set(targets_file "${deploy_impl_dir}/QtDeployTargets.cmake")
+ endif()
+ cmake_language(EVAL CODE
+ "cmake_language(DEFER
+ DIRECTORY [[${CMAKE_SOURCE_DIR}]]
+ CALL _qt_internal_write_target_deploy_info [[${targets_file}]])"
+ )
+ _qt_internal_add_deploy_support("${targets_file}")
+ endif()
+
+ # Make sure to look under the Qt bin dir with find_program, rather than randomly picking up
+ # a deployqt tool in the system.
+ # QT6_INSTALL_PREFIX is not set during Qt build, so add the hints conditionally.
+ set(find_program_hints)
+ if(QT6_INSTALL_PREFIX)
+ set(find_program_hints HINTS ${QT6_INSTALL_PREFIX}/${QT6_INSTALL_BINS})
+ endif()
+
+ # In the generator expression logic below, we need safe_target_file because
+ # CMake evaluates expressions in both the TRUE and FALSE branches of $<IF:...>.
+ # We still need a target to give to $<TARGET_FILE:...> when we have no deploy
+ # tool, so we cannot use something like $<TARGET_FILE:macdeployqt> directly.
+ if(APPLE AND NOT IOS)
+ find_program(MACDEPLOYQT_EXECUTABLE macdeployqt
+ ${find_program_hints})
+ set(fallback "$<$<BOOL:${MACDEPLOYQT_EXECUTABLE}>:${MACDEPLOYQT_EXECUTABLE}>")
+ set(target_if_exists "$<TARGET_NAME_IF_EXISTS:${QT_CMAKE_EXPORT_NAMESPACE}::macdeployqt>")
+ set(have_deploy_tool "$<BOOL:${target_if_exists}>")
+ set(safe_target_file
+ "$<TARGET_FILE:$<IF:${have_deploy_tool},${target_if_exists},${target}>>")
+ set(__QT_DEPLOY_TOOL "$<IF:${have_deploy_tool},${safe_target_file},${fallback}>")
+ elseif(WIN32)
+ find_program(WINDEPLOYQT_EXECUTABLE windeployqt
+ ${find_program_hints})
+ set(fallback "$<$<BOOL:${WINDEPLOYQT_EXECUTABLE}>:${WINDEPLOYQT_EXECUTABLE}>")
+ set(target_if_exists "$<TARGET_NAME_IF_EXISTS:${QT_CMAKE_EXPORT_NAMESPACE}::windeployqt>")
+ set(have_deploy_tool "$<BOOL:${target_if_exists}>")
+ set(safe_target_file
+ "$<TARGET_FILE:$<IF:${have_deploy_tool},${target_if_exists},${target}>>")
+ set(__QT_DEPLOY_TOOL "$<IF:${have_deploy_tool},${safe_target_file},${fallback}>")
+ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND NOT CMAKE_CROSSCOMPILING)
+ set(__QT_DEPLOY_TOOL "GRD")
+ else()
+ # Android is handled as a build target, not via this install-based approach.
+ # Therefore, we don't consider androiddeployqt here.
+ set(__QT_DEPLOY_TOOL "")
+ endif()
+
+ # Determine whether this is a multi-config build with a Debug configuration.
+ set(is_multi_config_build_with_debug_config FALSE)
+ get_target_property(target_is_imported ${target} IMPORTED)
+ if(target_is_imported)
+ get_target_property(target_imported_configs ${target} IMPORTED_CONFIGURATIONS)
+ list(LENGTH target_imported_configs target_imported_configs_length)
+ if(target_imported_configs_length GREATER "1"
+ AND "DEBUG" IN_LIST target_imported_configs)
+ set(is_multi_config_build_with_debug_config TRUE)
+ endif()
+ endif()
+
+ _qt_internal_add_deploy_support("${CMAKE_CURRENT_LIST_DIR}/Qt6CoreDeploySupport.cmake")
+
+ set(deploy_ignored_lib_dirs "")
+ if(__QT_DEPLOY_TOOL STREQUAL "GRD" AND NOT "${QT6_INSTALL_PREFIX}" STREQUAL "")
+ # Set up the directories we want to ignore when running file(GET_RUNTIME_DEPENDENCIES).
+ # If the Qt prefix is the root of one of those directories, don't ignore that directory.
+ # For example, if Qt's installation prefix is /usr, then we don't want to ignore /usr/lib.
+ foreach(link_dir IN LISTS CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES)
+ file(RELATIVE_PATH relative_dir "${QT6_INSTALL_PREFIX}" "${link_dir}")
+ if(relative_dir STREQUAL "")
+ # The Qt prefix is exactly ${link_dir}.
+ continue()
+ endif()
+ if(IS_ABSOLUTE "${relative_dir}" OR relative_dir MATCHES "^\\.\\./")
+ # The Qt prefix is outside of ${link_dir}.
+ list(APPEND deploy_ignored_lib_dirs "${link_dir}")
+ endif()
+ endforeach()
+ endif()
+
+ # Check whether we will have to adjust the RPATH of plugins.
+ if("${QT_DEPLOY_FORCE_ADJUST_RPATHS}" STREQUAL "")
+ set(must_adjust_plugins_rpath "")
+ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows"
+ AND NOT CMAKE_INSTALL_LIBDIR STREQUAL QT6_INSTALL_LIBS)
+ set(must_adjust_plugins_rpath ON)
+ endif()
+ else()
+ set(must_adjust_plugins_rpath "${QT_DEPLOY_FORCE_ADJUST_RPATHS}")
+ endif()
+
+ # Find the patchelf executable if necessary.
+ if(must_adjust_plugins_rpath)
+ if(CMAKE_VERSION VERSION_LESS "3.21")
+ set(QT_DEPLOY_USE_PATCHELF ON)
+ endif()
+ if(QT_DEPLOY_USE_PATCHELF)
+ find_program(QT_DEPLOY_PATCHELF_EXECUTABLE patchelf)
+ if(NOT QT_DEPLOY_PATCHELF_EXECUTABLE)
+ set(QT_DEPLOY_PATCHELF_EXECUTABLE "patchelf")
+ message(WARNING "The patchelf executable could not be located. "
+ "To use Qt's CMake deployment API, install patchelf or upgrade CMake to 3.21 "
+ "or newer.")
+ endif()
+ endif()
+ endif()
+
+ # Generate path to the target (not host) qtpaths file. Needed for windeployqt when
+ # cross-compiling from an x86_64 host to an arm64 target, so it knows which architecture
+ # libraries should be deployed.
+ if(CMAKE_HOST_WIN32)
+ if(CMAKE_CROSSCOMPILING)
+ set(qt_paths_ext ".bat")
+ else()
+ set(qt_paths_ext ".exe")
+ endif()
+ else()
+ set(qt_paths_ext "")
+ endif()
+
+
+
+ set(target_qtpaths_path "")
+ set(qtpaths_prefix "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_BINS}")
+ get_property(qt_major_version TARGET "${target}" PROPERTY INTERFACE_QT_MAJOR_VERSION)
+ if(qt_major_version)
+ set(target_qtpaths_with_major_version_path
+ "${qtpaths_prefix}/qtpaths${qt_major_version}${qt_paths_ext}")
+ if(EXISTS "${target_qtpaths_with_major_version_path}")
+ set(target_qtpaths_path "${target_qtpaths_with_major_version_path}")
+ endif()
+ endif()
+
+ if(NOT target_qtpaths_path)
+ set(target_qtpaths_path_without_version "${qtpaths_prefix}/qtpaths${qt_paths_ext}")
+ if(EXISTS "${target_qtpaths_path_without_version}")
+ set(target_qtpaths_path "${target_qtpaths_path_without_version}")
+ endif()
+ endif()
+
+ if(NOT target_qtpaths_path)
+ message(DEBUG "No qtpaths executable found for deployment purposes.")
+ endif()
+
+ file(GENERATE OUTPUT "${QT_DEPLOY_SUPPORT}" CONTENT
+"cmake_minimum_required(VERSION 3.16...3.21)
+
+# These are part of the public API. Projects should use them to provide a
+# consistent set of prefix-relative destinations.
+if(NOT QT_DEPLOY_BIN_DIR)
+ set(QT_DEPLOY_BIN_DIR \"${CMAKE_INSTALL_BINDIR}\")
+endif()
+if(NOT QT_DEPLOY_LIBEXEC_DIR)
+ set(QT_DEPLOY_LIBEXEC_DIR \"${CMAKE_INSTALL_LIBEXECDIR}\")
+endif()
+if(NOT QT_DEPLOY_LIB_DIR)
+ set(QT_DEPLOY_LIB_DIR \"${CMAKE_INSTALL_LIBDIR}\")
+endif()
+if(NOT QT_DEPLOY_PLUGINS_DIR)
+ set(QT_DEPLOY_PLUGINS_DIR \"plugins\")
+endif()
+if(NOT QT_DEPLOY_QML_DIR)
+ set(QT_DEPLOY_QML_DIR \"qml\")
+endif()
+if(NOT QT_DEPLOY_TRANSLATIONS_DIR)
+ set(QT_DEPLOY_TRANSLATIONS_DIR \"translations\")
+endif()
+if(NOT QT_DEPLOY_PREFIX)
+ set(QT_DEPLOY_PREFIX \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}\")
+endif()
+if(QT_DEPLOY_PREFIX STREQUAL \"\")
+ set(QT_DEPLOY_PREFIX .)
+endif()
+if(NOT QT_DEPLOY_IGNORED_LIB_DIRS)
+ set(QT_DEPLOY_IGNORED_LIB_DIRS \"${deploy_ignored_lib_dirs}\")
+endif()
+
+# These are internal implementation details. They may be removed at any time.
+set(__QT_DEPLOY_SYSTEM_NAME \"${CMAKE_SYSTEM_NAME}\")
+set(__QT_DEPLOY_IS_SHARED_LIBS_BUILD \"${QT6_IS_SHARED_LIBS_BUILD}\")
+set(__QT_DEPLOY_TOOL \"${__QT_DEPLOY_TOOL}\")
+set(__QT_DEPLOY_IMPL_DIR \"${deploy_impl_dir}\")
+set(__QT_DEPLOY_VERBOSE \"${QT_ENABLE_VERBOSE_DEPLOYMENT}\")
+set(__QT_CMAKE_EXPORT_NAMESPACE \"${QT_CMAKE_EXPORT_NAMESPACE}\")
+set(__QT_DEPLOY_GENERATOR_IS_MULTI_CONFIG \"${is_multi_config}\")
+set(__QT_DEPLOY_ACTIVE_CONFIG \"$<CONFIG>\")
+set(__QT_NO_CREATE_VERSIONLESS_FUNCTIONS \"${QT_NO_CREATE_VERSIONLESS_FUNCTIONS}\")
+set(__QT_DEFAULT_MAJOR_VERSION \"${QT_DEFAULT_MAJOR_VERSION}\")
+set(__QT_DEPLOY_QT_ADDITIONAL_PACKAGES_PREFIX_PATH \"${QT_ADDITIONAL_PACKAGES_PREFIX_PATH}\")
+set(__QT_DEPLOY_QT_INSTALL_PREFIX \"${QT6_INSTALL_PREFIX}\")
+set(__QT_DEPLOY_QT_INSTALL_BINS \"${QT6_INSTALL_BINS}\")
+set(__QT_DEPLOY_QT_INSTALL_DATA \"${QT6_INSTALL_DATA}\")
+set(__QT_DEPLOY_QT_INSTALL_LIBEXECS \"${QT6_INSTALL_LIBEXECS}\")
+set(__QT_DEPLOY_QT_INSTALL_PLUGINS \"${QT6_INSTALL_PLUGINS}\")
+set(__QT_DEPLOY_QT_INSTALL_TRANSLATIONS \"${QT6_INSTALL_TRANSLATIONS}\")
+set(__QT_DEPLOY_TARGET_QT_PATHS_PATH \"${target_qtpaths_path}\")
+set(__QT_DEPLOY_PLUGINS \"\")
+set(__QT_DEPLOY_MUST_ADJUST_PLUGINS_RPATH \"${must_adjust_plugins_rpath}\")
+set(__QT_DEPLOY_USE_PATCHELF \"${QT_DEPLOY_USE_PATCHELF}\")
+set(__QT_DEPLOY_PATCHELF_EXECUTABLE \"${QT_DEPLOY_PATCHELF_EXECUTABLE}\")
+set(__QT_DEPLOY_QT_IS_MULTI_CONFIG_BUILD_WITH_DEBUG \"${is_multi_config_build_with_debug_config}\")
+set(__QT_DEPLOY_QT_DEBUG_POSTFIX \"${QT6_DEBUG_POSTFIX}\")
+
+# Define the CMake commands to be made available during deployment.
+set(__qt_deploy_support_files
+ \"$<JOIN:$<TARGET_GENEX_EVAL:${target},$<TARGET_PROPERTY:${target},_qt_deploy_support_files>>,\"
+ \">\"
+)
+foreach(__qt_deploy_support_file IN LISTS __qt_deploy_support_files)
+ include(\"\${__qt_deploy_support_file}\")
+endforeach()
+
+unset(__qt_deploy_support_file)
+unset(__qt_deploy_support_files)
+")
+endfunction()
+
+# Write deployment information for the targets of the project.
+function(_qt_internal_write_target_deploy_info out_file)
+ set(targets "")
+ _qt_internal_collect_buildsystem_targets(targets
+ "${CMAKE_SOURCE_DIR}" INCLUDE EXECUTABLE SHARED_LIBRARY MODULE_LIBRARY)
+ set(content "")
+ foreach(target IN LISTS targets)
+ set(var_prefix "__QT_DEPLOY_TARGET_${target}")
+ string(APPEND content "set(${var_prefix}_FILE $<TARGET_FILE:${target}>)\n")
+ if(WIN32 AND CMAKE_VERSION GREATER_EQUAL "3.21")
+ string(APPEND content
+ "set(${var_prefix}_RUNTIME_DLLS $<TARGET_RUNTIME_DLLS:${target}>)\n")
+ endif()
+ endforeach()
+ file(GENERATE OUTPUT "${out_file}" CONTENT "${content}")
+endfunction()
+
+function(_qt_internal_is_examples_deployment_supported_in_current_config out_var out_var_reason)
+ # Deployment API doesn't work when examples / tests are built in-tree of a prefix qt build.
+ if(QT_BUILDING_QT AND QT_WILL_INSTALL AND NOT QT_INTERNAL_BUILD_STANDALONE_PARTS)
+ set(deployment_supported FALSE)
+ set(not_supported_reason "PREFIX_BUILD")
+ else()
+ set(deployment_supported TRUE)
+ set(not_supported_reason "")
+ endif()
+
+ set(${out_var} "${deployment_supported}" PARENT_SCOPE)
+ set(${out_var_reason} "${not_supported_reason}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_should_skip_deployment_api out_var out_var_reason)
+ set(skip_deployment FALSE)
+ _qt_internal_is_examples_deployment_supported_in_current_config(
+ deployment_supported
+ not_supported_reason
+ )
+
+ # Allow opting out of deployment, so that we can add deployment api to all our examples,
+ # but only run it in the CI for a select few, to avoid the overhead of deploying all examples.
+ if(QT_INTERNAL_SKIP_DEPLOYMENT OR (NOT deployment_supported))
+ set(skip_deployment TRUE)
+ endif()
+
+ set(reason "")
+ if(NOT deployment_supported)
+ set(reason "${not_supported_reason}")
+ elseif(QT_INTERNAL_SKIP_DEPLOYMENT)
+ set(reason "SKIP_REQUESTED")
+ endif()
+
+ set(${out_var} "${skip_deployment}" PARENT_SCOPE)
+ set(${out_var_reason} "${reason}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_should_skip_post_build_deployment_api out_var out_var_reason)
+ set(skip_deployment FALSE)
+ set(deployment_supported TRUE)
+
+ # Allow opting out of deployment, so that we can add deployment api to all our examples,
+ # but only run it in the CI for a select few, to avoid the overhead of deploying all examples.
+ if(QT_INTERNAL_SKIP_DEPLOYMENT OR (NOT deployment_supported))
+ set(skip_deployment TRUE)
+ endif()
+
+ set(reason "")
+ if(NOT deployment_supported)
+ set(reason "REASON_UNSPECIFIED")
+ elseif(QT_INTERNAL_SKIP_DEPLOYMENT)
+ set(reason "SKIP_REQUESTED")
+ endif()
+
+ set(${out_var} "${skip_deployment}" PARENT_SCOPE)
+ set(${out_var_reason} "${reason}" PARENT_SCOPE)
+endfunction()
+
+# Generate a deploy script that does nothing aside from showing a warning message.
+# The warning can be hidden by setting the QT_INTERNAL_HIDE_NO_OP_DEPLOYMENT_WARNING variable.
+function(_qt_internal_generate_no_op_deploy_script)
+ set(no_value_options
+ )
+ set(single_value_options
+ FUNCTION_NAME
+ NAME
+ OUTPUT_SCRIPT
+ SKIP_REASON
+ TARGET
+ )
+ set(multi_value_options
+ )
+
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+
+ if(NOT arg_OUTPUT_SCRIPT)
+ message(FATAL_ERROR "No OUTPUT_SCRIPT option specified")
+ endif()
+ if(NOT arg_FUNCTION_NAME)
+ message(FATAL_ERROR "No FUNCTION_NAME option specified")
+ endif()
+
+ set(generate_args "")
+ if(arg_NAME)
+ list(APPEND generate_args NAME "${arg_NAME}")
+ endif()
+ if(arg_TARGET)
+ list(APPEND generate_args TARGET "${arg_TARGET}")
+ endif()
+
+ set(function_name "${arg_FUNCTION_NAME}")
+
+ # The empty space is required, otherwise
+ set(content "
+message(DEBUG \"Running no-op deployment script because QT_INTERNAL_SKIP_DEPLOYMENT was ON.\")
+")
+ if(NOT QT_INTERNAL_HIDE_NO_OP_DEPLOYMENT_WARNING AND arg_SKIP_REASON STREQUAL "PREFIX_BUILD")
+ set(content "
+message(STATUS \"${function_name}(TARGET ${arg_TARGET}) is a no-op for prefix \"
+\"non-standalone builds due to various issues. Consider using a -no-prefix build \"
+\"or qt-internal-configure-tests or qt-internal-configure-examples if you want deployment to run.\")
+")
+ endif()
+
+ qt6_generate_deploy_script(
+ ${generate_args}
+ OUTPUT_SCRIPT deploy_script
+ CONTENT "${content}")
+
+ set("${arg_OUTPUT_SCRIPT}" "${deploy_script}" PARENT_SCOPE)
+endfunction()
+
+# We basically mirror CMake's policy setup
+# A policy can be set to OLD, set to NEW or unset
+# unset is the default state
+#
+function(qt6_policy mode policy behaviorOrVariable)
+ # When building Qt, tests and examples might expect a policy to be known, but they won't be
+ # known depending on which scope or when a find_package(Module) with the respective policy
+ # is called. Check the global list of known policies to accommodate that.
+ if(QT_BUILDING_QT AND NOT DEFINED QT_KNOWN_POLICY_${policy})
+ get_property(global_known_policies GLOBAL PROPERTY _qt_global_known_policies)
+ if(policy IN_LIST global_known_policies)
+ set(QT_KNOWN_POLICY_${policy} TRUE)
+ endif()
+ endif()
+
+ if (NOT DEFINED QT_KNOWN_POLICY_${policy})
+ message(FATAL_ERROR
+ "${policy} is not a known Qt policy. Did you include the necessary Qt module?"
+ )
+ endif()
+ if (${mode} STREQUAL "SET")
+ set(behavior ${behaviorOrVariable})
+ if (${behavior} STREQUAL "NEW" OR ${behavior} STREQUAL "OLD")
+ set(__QT_INTERNAL_POLICY_${policy} ${behavior} PARENT_SCOPE)
+ else()
+ message(FATAL_ERROR "Qt policies must be either set to NEW or OLD, but got ${behavior}")
+ endif()
+ else(${mode} STREQUAL "GET")
+ set(variable "${behaviorOrVariable}")
+ set("${variable}" "${__QT_INTERNAL_POLICY_${policy}}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Internal helper function; can be used in any module before doing a policy check
+function(__qt_internal_setup_policy policy sinceversion policyexplanation)
+ if(DEFINED __QT_INTERNAL_POLICY_${policy})
+ if (__QT_INTERNAL_POLICY_${policy} STREQUAL "OLD")
+ # policy is explicitly disabled
+ message(DEPRECATION
+ "Qt policy ${policy} is set to OLD. "
+ "Support for the old behavior will be removed in a future major version of Qt."
+ )
+ endif()
+ #else: policy is already enabled, nothing to do
+ elseif (${sinceversion} VERSION_LESS_EQUAL __qt_policy_check_version)
+ # we cannot use the public function here as we want to set it in parent scope
+ set(__QT_INTERNAL_POLICY_${policy} "NEW" PARENT_SCOPE)
+ elseif(NOT "${QT_NO_SHOW_OLD_POLICY_WARNINGS}")
+ message(AUTHOR_WARNING
+ "Qt policy ${policy} is not set: "
+ "${policyexplanation} "
+ "Use the qt_policy command to set the policy and suppress this warning.\n"
+ )
+ endif()
+endfunction()
+
+# Note this needs to be a macro because it sets variables intended for the
+# calling scope.
+macro(qt6_standard_project_setup)
+ # A parent project might want to prevent child projects pulled in with
+ # add_subdirectory() from changing the parent's preferred arrangement.
+ # They can set this variable to true to effectively disable this function.
+ if(NOT QT_NO_STANDARD_PROJECT_SETUP)
+
+ set(__qt_sps_args_option)
+ set(__qt_sps_args_single
+ REQUIRES
+ SUPPORTS_UP_TO
+ I18N_SOURCE_LANGUAGE
+ I18N_NATIVE_LANGUAGE # intermediate, remove after dependencies trickled through
+ )
+ set(__qt_sps_args_multi
+ I18N_TRANSLATED_LANGUAGES
+ I18N_LANGUAGES # intermediate, remove after dependencies trickled through
+ )
+ cmake_parse_arguments(__qt_sps_arg
+ "${__qt_sps_args_option}"
+ "${__qt_sps_args_single}"
+ "${__qt_sps_args_multi}"
+ ${ARGN}
+ )
+
+ # intermediate, remove after dependencies trickled through
+ if(DEFINED arg_I18N_NATIVE_LANGUAGE)
+ set(arg_I18N_SOURCE_LANGUAGE ${arg_I18N_NATIVE_LANGUAGE})
+ endif()
+ if(DEFINED arg_I18N_LANGUAGES)
+ set(arg_I18N_TRANSLATED_LANGUAGES ${arg_I18N_LANGUAGES})
+ endif()
+
+ if(__qt_sps_arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ # Set the Qt CMake policy based on the requested version(s)
+ set(__qt_policy_check_version "6.0.0")
+ if(Qt6_VERSION_MAJOR)
+ set(__qt_current_version
+ "${Qt6_VERSION_MAJOR}.${Qt6_VERSION_MINOR}.${Qt6_VERSION_PATCH}")
+ elseif(QT_BUILDING_QT)
+ set(__qt_current_version
+ "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+ else()
+ message(FATAL_ERROR "Can not determine Qt version.")
+ endif()
+ if(__qt_sps_arg_REQUIRES)
+ if("${__qt_current_version}" VERSION_LESS "${__qt_sps_arg_REQUIRES}")
+ message(FATAL_ERROR
+ "Project required a Qt minimum version of ${__qt_sps_arg_REQUIRES}, "
+ "but current version is only ${__qt_current_version}.")
+ endif()
+ set(__qt_policy_check_version "${__qt_sps_arg_REQUIRES}")
+ endif()
+ if(__qt_sps_arg_SUPPORTS_UP_TO)
+ if(__qt_sps_arg_REQUIRES)
+ if(${__qt_sps_arg_SUPPORTS_UP_TO} VERSION_LESS ${__qt_sps_arg_REQUIRES})
+ message(FATAL_ERROR "SUPPORTS_UP_TO must be larger than or equal to REQUIRES.")
+ endif()
+ set(__qt_policy_check_version "${__qt_sps_arg_SUPPORTS_UP_TO}")
+ else()
+ message(FATAL_ERROR "Please specify the REQUIRES as well.")
+ endif()
+ endif()
+
+ # All changes below this point should not result in a change to an
+ # existing value, except for CMAKE_INSTALL_RPATH which may append new
+ # values (but no duplicates).
+
+ # Use standard install locations, provided by GNUInstallDirs. All
+ # platforms should have this included so that we know the
+ # CMAKE_INSTALL_xxxDIR variables will be set.
+ include(GNUInstallDirs)
+ if(WIN32)
+ # Windows has no RPATH support, so we need all non-plugin DLLs in
+ # the same directory as application executables if we want to be
+ # able to run them without having to augment the PATH environment
+ # variable. Don't discard an existing value in case the project has
+ # already set this to somewhere else. Our setting is somewhat
+ # opinionated, so make it easy for projects to choose something else.
+ if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ endif()
+ elseif(NOT APPLE)
+ # Apart from Windows and Apple, most other platforms support RPATH
+ # and $ORIGIN. Make executables and non-static libraries use an
+ # install RPATH that allows them to find library dependencies if the
+ # project installs things to the directories defined by the
+ # CMAKE_INSTALL_xxxDIR variables (which is what CMake's defaults
+ # are based on).
+ file(RELATIVE_PATH __qt_relDir
+ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}
+ ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}
+ )
+ list(APPEND CMAKE_INSTALL_RPATH $ORIGIN $ORIGIN/${__qt_relDir})
+ list(REMOVE_DUPLICATES CMAKE_INSTALL_RPATH)
+ unset(__qt_reldir)
+ endif()
+
+ # Turn these on by default, unless they are already set. Projects can
+ # always turn off any they really don't want after we return.
+ foreach(auto_set IN ITEMS MOC UIC)
+ if(NOT DEFINED CMAKE_AUTO${auto_set})
+ set(CMAKE_AUTO${auto_set} TRUE)
+ endif()
+ endforeach()
+
+ # Enable folder support for IDEs. CMake >= 3.26 enables USE_FOLDERS by default but this is
+ # guarded by CMake policy CMP0143.
+ get_property(__qt_use_folders GLOBAL PROPERTY USE_FOLDERS)
+ if(__qt_use_folders OR "${__qt_use_folders}" STREQUAL "")
+ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+ get_property(__qt_qt_targets_folder GLOBAL PROPERTY QT_TARGETS_FOLDER)
+ if("${__qt_qt_targets_folder}" STREQUAL "")
+ set(__qt_qt_targets_folder QtInternalTargets)
+ set_property(GLOBAL PROPERTY QT_TARGETS_FOLDER ${__qt_qt_targets_folder})
+ endif()
+ get_property(__qt_autogen_targets_folder GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER)
+ if("${__qt_autogen_targets_folder}" STREQUAL "")
+ set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER ${__qt_qt_targets_folder})
+ endif()
+ endif()
+
+ # Hide generated files in dedicated folder. Unfortunately we can't use a
+ # top level "Generated Files" folder for this, as CMake will then put the
+ # folder first in the list of folders, whereas we want to keep Sources and
+ # Headers front and center. See also _qt_internal_finalize_source_groups
+ set_property(GLOBAL PROPERTY AUTOGEN_SOURCE_GROUP "Source Files/Generated")
+
+ # Treat metatypes JSON files as generated. We propagate these INTERFACE_SOURCES,
+ # due to CMake's lack of a generic mechanism for property inheritance (see
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/20416), but we don't want
+ # them to clutter up the user's project.
+ source_group("Source Files/Generated" REGULAR_EXPRESSION "(_metatypes\\.json)$")
+
+ # I18N support.
+ if(DEFINED __qt_sps_arg_I18N_TRANSLATED_LANGUAGES
+ AND NOT DEFINED QT_I18N_TRANSLATED_LANGUAGES)
+ set(QT_I18N_TRANSLATED_LANGUAGES ${__qt_sps_arg_I18N_TRANSLATED_LANGUAGES})
+ endif()
+ if(NOT DEFINED __qt_sps_arg_I18N_SOURCE_LANGUAGE)
+ set(__qt_sps_arg_I18N_SOURCE_LANGUAGE en)
+ endif()
+ if(NOT DEFINED QT_I18N_SOURCE_LANGUAGE)
+ set(QT_I18N_SOURCE_LANGUAGE ${__qt_sps_arg_I18N_SOURCE_LANGUAGE})
+ endif()
+ endif()
+endmacro()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ macro(qt_standard_project_setup)
+ qt6_standard_project_setup(${ARGV})
+ endmacro()
+ macro(qt_policy)
+ qt6_policy(${ARGV})
+ endmacro()
+endif()
+
+function(qt6_generate_deploy_script)
+ set(no_value_options "")
+ set(single_value_options
+ CONTENT
+ OUTPUT_SCRIPT
+ NAME
+ TARGET
+
+ # TODO: For backward compatibility / transitional use only,
+ # remove at some point
+ FILENAME_VARIABLE
+ )
+ set(multi_value_options "")
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+
+ # TODO: Remove when FILENAME_VARIABLE is fully removed
+ # Handle the slow deprecation of FILENAME_VARIABLE
+ if(arg_FILENAME_VARIABLE)
+ if(arg_OUTPUT_SCRIPT AND NOT arg_FILENAME_VARIABLE STREQUAL arg_OUTPUT_SCRIPT)
+ message(FATAL_ERROR
+ "Both FILENAME_VARIABLE and OUTPUT_SCRIPT were given and were different. "
+ "Only one of the two should be used."
+ )
+ endif()
+ message(AUTHOR_WARNING
+ "The FILENAME_VARIABLE keyword is deprecated and will be removed soon. Please use OUTPUT_SCRIPT instead.")
+ set(arg_OUTPUT_SCRIPT "${arg_FILENAME_VARIABLE}")
+ unset(arg_FILENAME_VARIABLE)
+ endif()
+
+ if(NOT arg_OUTPUT_SCRIPT)
+ message(FATAL_ERROR "OUTPUT_SCRIPT must be specified")
+ endif()
+
+ if("${arg_CONTENT}" STREQUAL "")
+ message(FATAL_ERROR "CONTENT must be specified")
+ endif()
+
+ # Check whether manual finalization is needed.
+ if(CMAKE_VERSION VERSION_LESS "3.19")
+ get_target_property(is_immediately_finalized ${arg_TARGET} _qt_is_immediately_finalized)
+ if(is_immediately_finalized)
+ message(WARNING
+ "Deployment of plugins for target '${arg_TARGET}' will not work. "
+ "Either, upgrade CMake to version 3.19 or newer, or call "
+ "qt_finalize_target(${arg_TARGET}) after generating the deployment script."
+ )
+ endif()
+ endif()
+
+ # Mark the target as "to be deployed".
+ set_property(TARGET ${arg_TARGET} PROPERTY _qt_marked_for_deployment ON)
+
+ # If the target already was finalized, maybe because it was defined in a subdirectory, generate
+ # the plugin deployment information here.
+ get_target_property(is_finalized "${arg_TARGET}" _qt_is_finalized)
+ if(is_finalized)
+ __qt_internal_generate_plugin_deployment_info(${arg_TARGET})
+ endif()
+
+ # Create a file name that will be unique for this target and the combination
+ # of arguments passed to this command. This allows the project to call us
+ # multiple times with different arguments for the same target (e.g. to
+ # create deployment scripts for different scenarios).
+ set(file_base_name "custom")
+ if(NOT "${arg_NAME}" STREQUAL "")
+ set(file_base_name "${arg_NAME}")
+ elseif(NOT "${arg_TARGET}" STREQUAL "")
+ set(file_base_name "${arg_TARGET}")
+ endif()
+ string(MAKE_C_IDENTIFIER "${file_base_name}" target_id)
+ string(SHA1 args_hash "${ARGV}")
+ string(SUBSTRING "${args_hash}" 0 10 short_hash)
+ _qt_internal_get_deploy_impl_dir(deploy_impl_dir)
+ set(deploy_script "${deploy_impl_dir}/deploy_${target_id}_${short_hash}")
+ get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+ if(is_multi_config)
+ set(config_infix "-$<CONFIG>")
+ else()
+ set(config_infix "")
+ endif()
+ string(APPEND deploy_script "${config_infix}.cmake")
+ set(${arg_OUTPUT_SCRIPT} "${deploy_script}" PARENT_SCOPE)
+
+ set(boiler_plate "include(${QT_DEPLOY_SUPPORT})
+include(\"\${CMAKE_CURRENT_LIST_DIR}/${arg_TARGET}-plugins${config_infix}.cmake\" OPTIONAL)
+set(__QT_DEPLOY_ALL_MODULES_FOUND_VIA_FIND_PACKAGE \"${QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE}\")
+")
+ list(TRANSFORM arg_CONTENT REPLACE "\\$" "\$")
+ file(GENERATE OUTPUT ${deploy_script} CONTENT "${boiler_plate}${arg_CONTENT}")
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ macro(qt_generate_deploy_script)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_generate_deploy_script(${ARGV})
+ else()
+ message(FATAL_ERROR "qt_generate_deploy_script() is only available in Qt 6.")
+ endif()
+ endmacro()
+endif()
+
+function(qt6_generate_deploy_app_script)
+ # We use a TARGET keyword option instead of taking the target as the first
+ # positional argument. This is to keep open the possibility of deploying
+ # an app for which we don't have a target (e.g. an application from a
+ # third party project that the caller may want to include in their own
+ # package). We would add an EXECUTABLE keyword for that, which would be
+ # mutually exclusive with the TARGET keyword.
+ set(no_value_options
+ NO_TRANSLATIONS
+ NO_COMPILER_RUNTIME
+ NO_UNSUPPORTED_PLATFORM_ERROR
+ )
+ set(single_value_options
+ TARGET
+ OUTPUT_SCRIPT
+
+ # TODO: For backward compatibility / transitional use only,
+ # remove at some point
+ FILENAME_VARIABLE
+ )
+ set(qt_deploy_runtime_dependencies_options
+ # These options are forwarded as is to qt_deploy_runtime_dependencies.
+ DEPLOY_TOOL_OPTIONS
+ PRE_INCLUDE_REGEXES
+ PRE_EXCLUDE_REGEXES
+ POST_INCLUDE_REGEXES
+ POST_EXCLUDE_REGEXES
+ POST_INCLUDE_FILES
+ POST_EXCLUDE_FILES
+ )
+ set(multi_value_options
+ ${qt_deploy_runtime_dependencies_options}
+ )
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+ if(arg_UNPARSED_ARGUMENTS)
+ message(FATAL_ERROR "Unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
+ endif()
+ if(NOT arg_TARGET)
+ message(FATAL_ERROR "TARGET must be specified")
+ endif()
+
+ # TODO: Remove when FILENAME_VARIABLE is fully removed
+ # Handle the slow deprecation of FILENAME_VARIABLE
+ if(arg_FILENAME_VARIABLE)
+ if(arg_OUTPUT_SCRIPT AND NOT arg_FILENAME_VARIABLE STREQUAL arg_OUTPUT_SCRIPT)
+ message(FATAL_ERROR
+ "Both FILENAME_VARIABLE and OUTPUT_SCRIPT were given and were different. "
+ "Only one of the two should be used."
+ )
+ endif()
+ message(AUTHOR_WARNING
+ "The FILENAME_VARIABLE keyword is deprecated and will be removed soon. Please use OUTPUT_SCRIPT instead.")
+ set(arg_OUTPUT_SCRIPT "${arg_FILENAME_VARIABLE}")
+ unset(arg_FILENAME_VARIABLE)
+ endif()
+
+ if(NOT arg_OUTPUT_SCRIPT)
+ message(FATAL_ERROR "OUTPUT_SCRIPT must be specified")
+ endif()
+
+ get_target_property(is_bundle ${arg_TARGET} MACOSX_BUNDLE)
+
+ set(unsupported_platform_extra_message "")
+ if(QT6_IS_SHARED_LIBS_BUILD)
+ set(qt_build_type_string "shared Qt libs")
+ else()
+ set(qt_build_type_string "static Qt libs")
+ endif()
+
+ if(CMAKE_CROSSCOMPILING)
+ string(APPEND qt_build_type_string ", cross-compiled")
+ endif()
+
+ if(NOT is_bundle)
+ string(APPEND qt_build_type_string ", non-bundle app")
+ set(unsupported_platform_extra_message
+ "Executable targets have to be app bundles to use this command on Apple platforms.")
+ endif()
+
+ set(generate_args
+ TARGET ${arg_TARGET}
+ OUTPUT_SCRIPT deploy_script
+ )
+
+ set(common_deploy_args "")
+ if(arg_NO_TRANSLATIONS)
+ string(APPEND common_deploy_args " NO_TRANSLATIONS\n")
+ endif()
+ if(arg_NO_COMPILER_RUNTIME)
+ string(APPEND common_deploy_args " NO_COMPILER_RUNTIME\n")
+ endif()
+
+ # Forward the arguments that are exactly the same for qt_deploy_runtime_dependencies.
+ foreach(var IN LISTS qt_deploy_runtime_dependencies_options)
+ if(NOT "${arg_${var}}" STREQUAL "")
+ list(APPEND common_deploy_args ${var} ${arg_${var}})
+ endif()
+ endforeach()
+
+ _qt_internal_should_skip_deployment_api(skip_deployment skip_reason)
+ if(skip_deployment)
+ _qt_internal_generate_no_op_deploy_script(
+ FUNCTION_NAME "qt6_generate_deploy_app_script"
+ SKIP_REASON "${skip_reason}"
+ ${generate_args}
+ )
+ elseif(APPLE AND NOT IOS AND QT6_IS_SHARED_LIBS_BUILD AND is_bundle)
+ # TODO: Consider handling non-bundle applications in the future using the generic cmake
+ # runtime dependency feature.
+ qt6_generate_deploy_script(${generate_args}
+ CONTENT "
+qt6_deploy_runtime_dependencies(
+ EXECUTABLE $<TARGET_FILE_NAME:${arg_TARGET}>.app
+${common_deploy_args})
+")
+
+ elseif(WIN32 AND QT6_IS_SHARED_LIBS_BUILD)
+ qt6_generate_deploy_script(${generate_args}
+ CONTENT "
+qt6_deploy_runtime_dependencies(
+ EXECUTABLE $<TARGET_FILE:${arg_TARGET}>
+ GENERATE_QT_CONF
+${common_deploy_args})
+")
+
+ elseif(UNIX AND NOT APPLE AND NOT ANDROID AND QT6_IS_SHARED_LIBS_BUILD
+ AND NOT CMAKE_CROSSCOMPILING)
+ qt6_generate_deploy_script(${generate_args}
+ CONTENT "
+qt6_deploy_runtime_dependencies(
+ EXECUTABLE $<TARGET_FILE:${arg_TARGET}>
+ GENERATE_QT_CONF
+${common_deploy_args})
+")
+
+ elseif(NOT arg_NO_UNSUPPORTED_PLATFORM_ERROR AND NOT QT_INTERNAL_NO_UNSUPPORTED_PLATFORM_ERROR)
+ # Currently we don't deploy runtime dependencies if cross-compiling or using a static Qt.
+ # Error out by default unless the project opted out of the error.
+ # This provides us a migration path in the future without breaking compatibility promises.
+ message(FATAL_ERROR
+ "Support for installing runtime dependencies is not implemented for "
+ "this target platform (${CMAKE_SYSTEM_NAME}, ${qt_build_type_string}). "
+ ${unsupported_platform_extra_message}
+ )
+ else()
+ set(skip_message
+ "_qt_internal_show_skip_runtime_deploy_message(\"${qt_build_type_string}\"")
+ if(unsupported_platform_extra_message)
+ string(APPEND skip_message
+ "\n EXTRA_MESSAGE \"${unsupported_platform_extra_message}\"")
+ endif()
+ string(APPEND skip_message "\n)")
+ qt6_generate_deploy_script(${generate_args} CONTENT "${skip_message}")
+ endif()
+
+ set(${arg_OUTPUT_SCRIPT} "${deploy_script}" PARENT_SCOPE)
+endfunction()
+
+if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
+ macro(qt_generate_deploy_app_script)
+ qt6_generate_deploy_app_script(${ARGV})
+ endmacro()
+endif()