f4aaba593c
At the moment only the Qt internal qt_manual_moc function allows manually running moc and generating a metatypes json file. There is no such functionality available in the public qt6_wrap_cpp and qt6_generate_moc functions. Change qt6_wrap_cpp to accept a new internal option called __QT_INTERNAL_OUTPUT_MOC_JSON_FILES to allow creating and retrieving the associated json file with metatypes information. This is needed to fix qtremoteobjects CMake API which needs to run moc manually and process the metatypes json file. The option is internal because we don't want to introduce new API in 6.2.0. Task-number: QTBUG-95832 Change-Id: Ic8dd27fc960c3f8dea8c101dfc028db45494953d Reviewed-by: Alexey Edelev <alexey.edelev@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Jani Heikkinen <jani.heikkinen@qt.io> (cherry picked from commit 90e7d6db1bb44de3629ec2b70df26fbafe4294fa) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
2323 lines
93 KiB
CMake
2323 lines
93 KiB
CMake
#=============================================================================
|
|
# 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.
|
|
#=============================================================================
|
|
|
|
######################################
|
|
#
|
|
# Macros for building Qt files
|
|
#
|
|
######################################
|
|
|
|
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
|
|
macro(_qt_internal_make_output_file infile prefix ext outfile )
|
|
string(LENGTH ${CMAKE_CURRENT_BINARY_DIR} _binlength)
|
|
string(LENGTH ${infile} _infileLength)
|
|
set(_checkinfile ${CMAKE_CURRENT_SOURCE_DIR})
|
|
if(_infileLength GREATER _binlength)
|
|
string(SUBSTRING "${infile}" 0 ${_binlength} _checkinfile)
|
|
if(_checkinfile STREQUAL "${CMAKE_CURRENT_BINARY_DIR}")
|
|
file(RELATIVE_PATH rel ${CMAKE_CURRENT_BINARY_DIR} ${infile})
|
|
else()
|
|
file(RELATIVE_PATH rel ${CMAKE_CURRENT_SOURCE_DIR} ${infile})
|
|
endif()
|
|
else()
|
|
file(RELATIVE_PATH rel ${CMAKE_CURRENT_SOURCE_DIR} ${infile})
|
|
endif()
|
|
if(WIN32 AND rel MATCHES "^([a-zA-Z]):(.*)$") # absolute path
|
|
set(rel "${CMAKE_MATCH_1}_${CMAKE_MATCH_2}")
|
|
endif()
|
|
set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${rel}")
|
|
string(REPLACE ".." "__" _outfile ${_outfile})
|
|
get_filename_component(outpath ${_outfile} PATH)
|
|
if(CMAKE_VERSION VERSION_LESS "3.14")
|
|
get_filename_component(_outfile_ext ${_outfile} EXT)
|
|
get_filename_component(_outfile_ext ${_outfile_ext} NAME_WE)
|
|
get_filename_component(_outfile ${_outfile} NAME_WE)
|
|
string(APPEND _outfile ${_outfile_ext})
|
|
else()
|
|
get_filename_component(_outfile ${_outfile} NAME_WLE)
|
|
endif()
|
|
file(MAKE_DIRECTORY ${outpath})
|
|
set(${outfile} ${outpath}/${prefix}${_outfile}.${ext})
|
|
endmacro()
|
|
|
|
macro(_qt_internal_get_moc_flags _moc_flags)
|
|
set(${_moc_flags})
|
|
get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES)
|
|
|
|
if(CMAKE_INCLUDE_CURRENT_DIR)
|
|
list(APPEND _inc_DIRS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
|
endif()
|
|
|
|
foreach(_current ${_inc_DIRS})
|
|
if("${_current}" MATCHES "\\.framework/?$")
|
|
string(REGEX REPLACE "/[^/]+\\.framework" "" framework_path "${_current}")
|
|
set(${_moc_flags} ${${_moc_flags}} "-F${framework_path}")
|
|
else()
|
|
set(${_moc_flags} ${${_moc_flags}} "-I${_current}")
|
|
endif()
|
|
endforeach()
|
|
|
|
get_directory_property(_defines COMPILE_DEFINITIONS)
|
|
foreach(_current ${_defines})
|
|
set(${_moc_flags} ${${_moc_flags}} "-D${_current}")
|
|
endforeach()
|
|
|
|
if(WIN32)
|
|
set(${_moc_flags} ${${_moc_flags}} -DWIN32)
|
|
endif()
|
|
if (MSVC)
|
|
set(${_moc_flags} ${${_moc_flags}} --compiler-flavor=msvc)
|
|
endif()
|
|
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 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
|
|
# MinGW builds does not seem to handle spaces in the path to the
|
|
# file given with the @ syntax.
|
|
get_filename_component(_moc_outfile_name "${outfile}" NAME)
|
|
get_filename_component(_moc_outfile_dir "${outfile}" PATH)
|
|
if(_moc_outfile_dir)
|
|
set(_moc_working_dir WORKING_DIRECTORY ${_moc_outfile_dir})
|
|
endif()
|
|
set (_moc_parameters_file ${outfile}_parameters)
|
|
set (_moc_parameters ${moc_flags} ${moc_options} -o "${outfile}" "${infile}")
|
|
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()
|
|
string (REPLACE ";" "\n" _moc_parameters "${_moc_parameters}")
|
|
|
|
if(moc_target)
|
|
set(_moc_parameters_file ${_moc_parameters_file}$<$<BOOL:$<CONFIGURATION>>:_$<CONFIGURATION>>)
|
|
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>")
|
|
|
|
file (GENERATE
|
|
OUTPUT ${_moc_parameters_file}
|
|
CONTENT "${targetdefines}${targetincludes}${_moc_parameters}\n"
|
|
)
|
|
|
|
set(targetincludes)
|
|
set(targetdefines)
|
|
else()
|
|
file(WRITE ${_moc_parameters_file} "${_moc_parameters}\n")
|
|
endif()
|
|
|
|
set(_moc_extra_parameters_file @${_moc_parameters_file})
|
|
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)
|
|
endfunction()
|
|
|
|
function(qt6_generate_moc infile outfile )
|
|
# get include dirs and flags
|
|
_qt_internal_get_moc_flags(moc_flags)
|
|
get_filename_component(abs_infile ${infile} ABSOLUTE)
|
|
set(_outfile "${outfile}")
|
|
if(NOT IS_ABSOLUTE "${outfile}")
|
|
set(_outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}")
|
|
endif()
|
|
if ("x${ARGV2}" STREQUAL "xTARGET")
|
|
set(moc_target ${ARGV3})
|
|
endif()
|
|
_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)
|
|
function(qt_generate_moc)
|
|
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
|
|
qt5_generate_moc(${ARGV})
|
|
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
|
|
qt6_generate_moc(${ARGV})
|
|
endif()
|
|
endfunction()
|
|
endif()
|
|
|
|
|
|
# qt6_wrap_cpp(outfiles inputfile ... )
|
|
|
|
function(qt6_wrap_cpp outfiles )
|
|
# get include dirs
|
|
_qt_internal_get_moc_flags(moc_flags)
|
|
|
|
set(options)
|
|
set(oneValueArgs
|
|
TARGET
|
|
__QT_INTERNAL_OUTPUT_MOC_JSON_FILES
|
|
)
|
|
set(multiValueArgs OPTIONS DEPENDS)
|
|
|
|
cmake_parse_arguments(_WRAP_CPP "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
set(moc_files ${_WRAP_CPP_UNPARSED_ARGUMENTS})
|
|
set(moc_options ${_WRAP_CPP_OPTIONS})
|
|
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)
|
|
|
|
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}"
|
|
"${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(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.
|
|
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
|
function(qt_wrap_cpp outfiles)
|
|
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
|
|
qt5_wrap_cpp("${outfiles}" ${ARGN})
|
|
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
|
|
qt6_wrap_cpp("${outfiles}" ${ARGN})
|
|
endif()
|
|
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
|
endfunction()
|
|
endif()
|
|
|
|
|
|
# _qt6_parse_qrc_file(infile _out_depends _rc_depends)
|
|
# internal
|
|
|
|
function(_qt6_parse_qrc_file infile _out_depends _rc_depends)
|
|
get_filename_component(rc_path ${infile} PATH)
|
|
|
|
if(EXISTS "${infile}")
|
|
# parse file for dependencies
|
|
# all files are absolute paths or relative to the location of the qrc file
|
|
file(READ "${infile}" RC_FILE_CONTENTS)
|
|
string(REGEX MATCHALL "<file[^<]+" RC_FILES "${RC_FILE_CONTENTS}")
|
|
foreach(RC_FILE ${RC_FILES})
|
|
string(REGEX REPLACE "^<file[^>]*>" "" RC_FILE "${RC_FILE}")
|
|
if(NOT IS_ABSOLUTE "${RC_FILE}")
|
|
set(RC_FILE "${rc_path}/${RC_FILE}")
|
|
endif()
|
|
set(RC_DEPENDS ${RC_DEPENDS} "${RC_FILE}")
|
|
endforeach()
|
|
# Since this cmake macro is doing the dependency scanning for these files,
|
|
# let's make a configured file and add it as a dependency so cmake is run
|
|
# again when dependencies need to be recomputed.
|
|
_qt_internal_make_output_file("${infile}" "" "qrc.depends" out_depends)
|
|
configure_file("${infile}" "${out_depends}" COPYONLY)
|
|
else()
|
|
# The .qrc file does not exist (yet). Let's add a dependency and hope
|
|
# that it will be generated later
|
|
set(out_depends)
|
|
endif()
|
|
|
|
set(${_out_depends} ${out_depends} PARENT_SCOPE)
|
|
set(${_rc_depends} ${RC_DEPENDS} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
|
|
# qt6_add_binary_resources(target inputfiles ... )
|
|
|
|
function(qt6_add_binary_resources target )
|
|
|
|
set(options)
|
|
set(oneValueArgs DESTINATION)
|
|
set(multiValueArgs OPTIONS)
|
|
|
|
cmake_parse_arguments(_RCC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
set(rcc_files ${_RCC_UNPARSED_ARGUMENTS})
|
|
set(rcc_options ${_RCC_OPTIONS})
|
|
set(rcc_destination ${_RCC_DESTINATION})
|
|
|
|
if(NOT rcc_destination)
|
|
set(rcc_destination ${CMAKE_CURRENT_BINARY_DIR}/${target}.rcc)
|
|
endif()
|
|
|
|
foreach(it ${rcc_files})
|
|
get_filename_component(infile ${it} ABSOLUTE)
|
|
|
|
_qt6_parse_qrc_file(${infile} _out_depends _rc_depends)
|
|
set_source_files_properties(${infile} PROPERTIES SKIP_AUTORCC ON)
|
|
set(infiles ${infiles} ${infile})
|
|
set(out_depends ${out_depends} ${_out_depends})
|
|
set(rc_depends ${rc_depends} ${_rc_depends})
|
|
endforeach()
|
|
|
|
add_custom_command(OUTPUT ${rcc_destination}
|
|
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::rcc
|
|
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::rcc
|
|
ARGS ${rcc_options} --binary --name ${target} --output ${rcc_destination} ${infiles}
|
|
DEPENDS
|
|
${QT_CMAKE_EXPORT_NAMESPACE}::rcc
|
|
${rc_depends}
|
|
${out_depends}
|
|
${infiles}
|
|
VERBATIM)
|
|
|
|
add_custom_target(${target} ALL DEPENDS ${rcc_destination})
|
|
endfunction()
|
|
|
|
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
|
function(qt_add_binary_resources)
|
|
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
|
|
qt5_add_binary_resources(${ARGV})
|
|
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
|
|
qt6_add_binary_resources(${ARGV})
|
|
endif()
|
|
endfunction()
|
|
endif()
|
|
|
|
|
|
# qt6_add_resources(target resourcename ...
|
|
# or
|
|
# qt6_add_resources(outfiles inputfile ... )
|
|
|
|
function(qt6_add_resources outfiles )
|
|
if (TARGET ${outfiles})
|
|
cmake_parse_arguments(arg "" "OUTPUT_TARGETS" "" ${ARGN})
|
|
_qt_internal_process_resource(${ARGV})
|
|
if (arg_OUTPUT_TARGETS)
|
|
set(${arg_OUTPUT_TARGETS} ${${arg_OUTPUT_TARGETS}} PARENT_SCOPE)
|
|
endif()
|
|
else()
|
|
set(options)
|
|
set(oneValueArgs)
|
|
set(multiValueArgs OPTIONS)
|
|
|
|
cmake_parse_arguments(_RCC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
set(rcc_files ${_RCC_UNPARSED_ARGUMENTS})
|
|
set(rcc_options ${_RCC_OPTIONS})
|
|
|
|
if("${rcc_options}" MATCHES "-binary")
|
|
message(WARNING "Use qt6_add_binary_resources for binary option")
|
|
endif()
|
|
|
|
foreach(it ${rcc_files})
|
|
get_filename_component(outfilename ${it} NAME_WE)
|
|
get_filename_component(infile ${it} ABSOLUTE)
|
|
set(outfile ${CMAKE_CURRENT_BINARY_DIR}/qrc_${outfilename}.cpp)
|
|
|
|
_qt6_parse_qrc_file(${infile} _out_depends _rc_depends)
|
|
set_source_files_properties(${infile} PROPERTIES SKIP_AUTORCC ON)
|
|
|
|
add_custom_command(OUTPUT ${outfile}
|
|
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::rcc
|
|
ARGS ${rcc_options} --name ${outfilename} --output ${outfile} ${infile}
|
|
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)
|
|
list(APPEND ${outfiles} ${outfile})
|
|
endforeach()
|
|
set(${outfiles} ${${outfiles}} PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
|
function(qt_add_resources outfiles)
|
|
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
|
|
qt5_add_resources("${outfiles}" ${ARGN})
|
|
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
|
|
qt6_add_resources("${outfiles}" ${ARGN})
|
|
endif()
|
|
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()
|
|
endif()
|
|
|
|
|
|
# qt6_add_big_resources(outfiles inputfile ... )
|
|
|
|
function(qt6_add_big_resources outfiles )
|
|
if (CMAKE_VERSION VERSION_LESS 3.9)
|
|
message(FATAL_ERROR, "qt6_add_big_resources requires CMake 3.9 or newer")
|
|
endif()
|
|
|
|
set(options)
|
|
set(oneValueArgs)
|
|
set(multiValueArgs OPTIONS)
|
|
|
|
cmake_parse_arguments(_RCC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
set(rcc_files ${_RCC_UNPARSED_ARGUMENTS})
|
|
set(rcc_options ${_RCC_OPTIONS})
|
|
|
|
if("${rcc_options}" MATCHES "-binary")
|
|
message(WARNING "Use qt6_add_binary_resources for binary option")
|
|
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_AUTOGEN ON)
|
|
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
|
|
VERBATIM)
|
|
add_custom_target(big_resources_${outfilename} ALL DEPENDS ${tmpoutfile})
|
|
add_library(rcc_object_${outfilename} OBJECT ${tmpoutfile})
|
|
_qt_internal_set_up_static_runtime_library(rcc_object_${outfilename})
|
|
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)
|
|
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})
|
|
endforeach()
|
|
set(${outfiles} ${${outfiles}} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
|
function(qt_add_big_resources outfiles)
|
|
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
|
|
qt5_add_big_resources(${outfiles} ${ARGN})
|
|
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
|
|
qt6_add_big_resources(${outfiles} ${ARGN})
|
|
endif()
|
|
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
|
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
|
|
# target properties.
|
|
function(qt6_add_executable target)
|
|
cmake_parse_arguments(PARSE_ARGV 1 arg "MANUAL_FINALIZATION" "" "")
|
|
|
|
_qt_internal_create_executable("${target}" ${arg_UNPARSED_ARGUMENTS})
|
|
target_link_libraries("${target}" PRIVATE Qt6::Core)
|
|
|
|
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()
|
|
|
|
function(_qt_internal_create_executable target)
|
|
if(ANDROID)
|
|
list(REMOVE_ITEM ARGN "WIN32" "MACOSX_BUNDLE")
|
|
add_library("${target}" MODULE ${ARGN})
|
|
# On our qmake builds we do don't compile the executables with
|
|
# visibility=hidden. Not having this flag set will cause the
|
|
# executable to have main() hidden and can then no longer be loaded
|
|
# through dlopen()
|
|
set_property(TARGET "${target}" PROPERTY C_VISIBILITY_PRESET default)
|
|
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)
|
|
qt6_android_apply_arch_suffix("${target}")
|
|
set_property(TARGET "${target}" PROPERTY _qt_is_android_executable TRUE)
|
|
else()
|
|
add_executable("${target}" ${ARGN})
|
|
endif()
|
|
|
|
_qt_internal_set_up_static_runtime_library("${target}")
|
|
endfunction()
|
|
|
|
function(_qt_internal_finalize_executable target)
|
|
get_target_property(is_finalized "${target}" _qt_executable_is_finalized)
|
|
if(is_finalized)
|
|
message(AUTHOR_WARNING
|
|
"Tried to call qt6_finalize_target twice on executable: '${target}'. \
|
|
Did you forget to specify MANUAL_FINALIZATION to qt6_add_executable?")
|
|
return()
|
|
endif()
|
|
|
|
# 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
|
|
# (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
|
|
# vast majority of use cases, since projects will typically link directly
|
|
# to Qt::* targets. For the cases where this isn't so, the project will be
|
|
# responsible for calling any relevant functions themselves instead of
|
|
# relying on these automatic finalization calls.
|
|
set(finalizers)
|
|
|
|
__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
|
|
)
|
|
if(dep_finalizers)
|
|
list(APPEND finalizers ${dep_finalizers})
|
|
endif()
|
|
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)"
|
|
)
|
|
else()
|
|
foreach(finalizer_func IN LISTS finalizers)
|
|
cmake_language(CALL ${finalizer_func} ${target})
|
|
endforeach()
|
|
endif()
|
|
endif()
|
|
|
|
if(ANDROID)
|
|
qt6_android_generate_deployment_settings("${target}")
|
|
qt6_android_add_apk_target("${target}")
|
|
endif()
|
|
if(EMSCRIPTEN)
|
|
_qt_internal_wasm_add_target_helpers("${target}")
|
|
endif()
|
|
if(IOS)
|
|
_qt_internal_finalize_ios_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()
|
|
|
|
set_target_properties(${target} PROPERTIES _qt_executable_is_finalized TRUE)
|
|
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)
|
|
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(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()
|
|
endfunction()
|
|
|
|
function(_qt_internal_find_ios_development_team_id out_var)
|
|
get_property(team_id GLOBAL PROPERTY _qt_internal_ios_development_team_id)
|
|
get_property(team_id_computed GLOBAL PROPERTY _qt_internal_ios_development_team_id_computed)
|
|
if(team_id_computed)
|
|
# Just in case if the value is non-empty but still booly FALSE.
|
|
if(NOT team_id)
|
|
set(team_id "")
|
|
endif()
|
|
set("${out_var}" "${team_id}" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
|
|
set_property(GLOBAL PROPERTY _qt_internal_ios_development_team_id_computed "TRUE")
|
|
|
|
set(home_dir "$ENV{HOME}")
|
|
set(xcode_preferences_path "${home_dir}/Library/Preferences/com.apple.dt.Xcode.plist")
|
|
|
|
# Extract the first account name (email) from the user's Xcode preferences
|
|
message(DEBUG "Trying to extract an Xcode development team id from '${xcode_preferences_path}'")
|
|
execute_process(COMMAND "/usr/libexec/PlistBuddy"
|
|
-x -c "print IDEProvisioningTeams" "${xcode_preferences_path}"
|
|
OUTPUT_VARIABLE teams_xml
|
|
ERROR_VARIABLE plist_error)
|
|
if(teams_xml AND NOT plist_error)
|
|
string(REPLACE "\n" ";" teams_xml_lines "${teams_xml}")
|
|
foreach(xml_line ${teams_xml_lines})
|
|
if(xml_line MATCHES "<key>(.+)</key>")
|
|
set(first_account "${CMAKE_MATCH_1}")
|
|
string(STRIP "${first_account}" first_account)
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
if(NOT first_account)
|
|
message(DEBUG "Failed to extract an Xcode development team id.")
|
|
return()
|
|
endif()
|
|
|
|
# Extract the first team ID
|
|
execute_process(COMMAND "/usr/libexec/PlistBuddy"
|
|
-c "print IDEProvisioningTeams:${first_account}:0:teamID"
|
|
"${xcode_preferences_path}"
|
|
OUTPUT_VARIABLE team_id
|
|
ERROR_VARIABLE team_id_error)
|
|
if(team_id AND NOT team_id_error)
|
|
message(DEBUG "Successfully extracted the first encountered Xcode development team id.")
|
|
string(STRIP "${team_id}" team_id)
|
|
set_property(GLOBAL PROPERTY _qt_internal_ios_development_team_id "${team_id}")
|
|
set("${out_var}" "${team_id}" PARENT_SCOPE)
|
|
else()
|
|
set("${out_var}" "" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(_qt_internal_get_ios_bundle_identifier_prefix out_var)
|
|
get_property(prefix GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix)
|
|
get_property(prefix_computed GLOBAL PROPERTY
|
|
_qt_internal_ios_bundle_identifier_prefix_computed)
|
|
if(prefix_computed)
|
|
# Just in case if the value is non-empty but still booly FALSE.
|
|
if(NOT prefix)
|
|
set(prefix "")
|
|
endif()
|
|
set("${out_var}" "${prefix}" PARENT_SCOPE)
|
|
return()
|
|
endif()
|
|
|
|
set_property(GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix_computed "TRUE")
|
|
|
|
set(home_dir "$ENV{HOME}")
|
|
set(xcode_preferences_path "${home_dir}/Library/Preferences/com.apple.dt.Xcode.plist")
|
|
|
|
message(DEBUG "Trying to extract the default bundle identifier prefix from Xcode preferences.")
|
|
execute_process(COMMAND "/usr/libexec/PlistBuddy"
|
|
-c "print IDETemplateOptions:bundleIdentifierPrefix"
|
|
"${xcode_preferences_path}"
|
|
OUTPUT_VARIABLE prefix
|
|
ERROR_VARIABLE prefix_error)
|
|
if(prefix AND NOT prefix_error)
|
|
message(DEBUG "Successfully extracted the default bundle indentifier prefix.")
|
|
string(STRIP "${prefix}" prefix)
|
|
else()
|
|
message(DEBUG "Failed to extract the default bundle indentifier prefix.")
|
|
endif()
|
|
|
|
if(prefix AND NOT prefix_error)
|
|
set_property(GLOBAL PROPERTY _qt_internal_ios_bundle_identifier_prefix "${prefix}")
|
|
set("${out_var}" "${prefix}" PARENT_SCOPE)
|
|
else()
|
|
set("${out_var}" "" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(_qt_internal_get_default_ios_bundle_identifier out_var)
|
|
_qt_internal_get_ios_bundle_identifier_prefix(prefix)
|
|
if(NOT prefix)
|
|
set(prefix "com.yourcompany")
|
|
endif()
|
|
set("${out_var}" "${prefix}.\${PRODUCT_NAME:rfc1034identifier}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
function(_qt_internal_set_placeholder_apple_bundle_version target)
|
|
# If user hasn't provided neither a bundle version nor a bundle short version string for the
|
|
# app, set a placeholder value for both which will add them to the generated Info.plist file.
|
|
# This is required so that the app launches in the simulator (but apparently not for running
|
|
# on-device).
|
|
get_target_property(bundle_version "${target}" MACOSX_BUNDLE_BUNDLE_VERSION)
|
|
get_target_property(bundle_short_version "${target}" MACOSX_BUNDLE_SHORT_VERSION_STRING)
|
|
|
|
if(NOT MACOSX_BUNDLE_BUNDLE_VERSION AND
|
|
NOT MACOSX_BUNDLE_SHORT_VERSION_STRING AND
|
|
NOT bundle_version AND
|
|
NOT bundle_short_version AND
|
|
NOT QT_NO_SET_XCODE_BUNDLE_VERSION
|
|
)
|
|
set(bundle_version "0.0.1")
|
|
set(bundle_short_version "0.0.1")
|
|
set_target_properties("${target}"
|
|
PROPERTIES
|
|
MACOSX_BUNDLE_BUNDLE_VERSION "${bundle_version}"
|
|
MACOSX_BUNDLE_SHORT_VERSION_STRING "${bundle_short_version}"
|
|
)
|
|
endif()
|
|
endfunction()
|
|
|
|
function(_qt_internal_finalize_ios_app target)
|
|
# If user hasn't provided a development team id, try to find the first one specified
|
|
# in the Xcode preferences.
|
|
if(NOT CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM AND NOT QT_NO_SET_XCODE_DEVELOPMENT_TEAM_ID)
|
|
get_target_property(existing_team_id "${target}" XCODE_ATTRIBUTE_DEVELOPMENT_TEAM)
|
|
if(NOT existing_team_id)
|
|
_qt_internal_find_ios_development_team_id(team_id)
|
|
set_target_properties("${target}"
|
|
PROPERTIES XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${team_id}")
|
|
endif()
|
|
endif()
|
|
|
|
# If user hasn't provided a bundle identifier for the app, get a default identifier
|
|
# using the default bundle prefix from Xcode preferences and add it to the generated
|
|
# Info.plist file.
|
|
if(NOT MACOSX_BUNDLE_GUI_IDENTIFIER AND NOT QT_NO_SET_XCODE_BUNDLE_IDENTIFIER)
|
|
get_target_property(existing_id "${target}" MACOSX_BUNDLE_GUI_IDENTIFIER)
|
|
if(NOT existing_id)
|
|
_qt_internal_get_default_ios_bundle_identifier(bundle_id)
|
|
set_target_properties("${target}"
|
|
PROPERTIES MACOSX_BUNDLE_GUI_IDENTIFIER "${bundle_id}")
|
|
endif()
|
|
endif()
|
|
|
|
# Reuse the same bundle identifier for the Xcode property.
|
|
if(NOT CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER
|
|
AND NOT QT_NO_SET_XCODE_BUNDLE_IDENTIFIER)
|
|
get_target_property(existing_id "${target}" XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER)
|
|
if(NOT existing_id)
|
|
set_target_properties("${target}"
|
|
PROPERTIES XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER
|
|
"${bundle_id}")
|
|
endif()
|
|
endif()
|
|
|
|
_qt_internal_set_placeholder_apple_bundle_version("${target}")
|
|
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_target(${ARGV})
|
|
endfunction()
|
|
endif()
|
|
|
|
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}")
|
|
if(TARGET "${qt_plugin_with_version}")
|
|
set("${out_var}" "${qt_plugin_with_version}" PARENT_SCOPE)
|
|
else()
|
|
set("${out_var}" "" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
macro(_qt_import_plugin target plugin)
|
|
set(_final_plugin_name "${plugin}")
|
|
if(NOT TARGET "${plugin}")
|
|
_qt_get_plugin_name_with_version("${plugin}" _qt_plugin_with_version_name)
|
|
if(TARGET "${_qt_plugin_with_version_name}")
|
|
set(_final_plugin_name "${_qt_plugin_with_version_name}")
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT TARGET "${_final_plugin_name}")
|
|
message(
|
|
"Warning: plug-in ${_final_plugin_name} is not known to the current Qt installation.")
|
|
else()
|
|
get_target_property(_plugin_class_name "${_final_plugin_name}" QT_PLUGIN_CLASS_NAME)
|
|
if(_plugin_class_name)
|
|
set_property(TARGET "${target}" APPEND PROPERTY QT_PLUGINS "${plugin}")
|
|
endif()
|
|
endif()
|
|
endmacro()
|
|
|
|
function(_qt_internal_disable_static_default_plugins target)
|
|
set_target_properties(${target} PROPERTIES QT_DEFAULT_PLUGINS 0)
|
|
endfunction()
|
|
|
|
function(qt6_import_plugins target)
|
|
cmake_parse_arguments(arg "NO_DEFAULT" "" "INCLUDE;EXCLUDE;INCLUDE_BY_TYPE;EXCLUDE_BY_TYPE" ${ARGN})
|
|
|
|
# Handle NO_DEFAULT
|
|
if(${arg_NO_DEFAULT})
|
|
_qt_internal_disable_static_default_plugins("${target}")
|
|
endif()
|
|
|
|
# Handle INCLUDE
|
|
foreach(plugin ${arg_INCLUDE})
|
|
_qt_import_plugin("${target}" "${plugin}")
|
|
endforeach()
|
|
|
|
# Handle EXCLUDE
|
|
foreach(plugin ${arg_EXCLUDE})
|
|
set_property(TARGET "${target}" APPEND PROPERTY QT_NO_PLUGINS "${plugin}")
|
|
endforeach()
|
|
|
|
# Handle INCLUDE_BY_TYPE
|
|
set(_current_type "")
|
|
foreach(_arg ${arg_INCLUDE_BY_TYPE})
|
|
string(REGEX REPLACE "[-/]" "_" _plugin_type "${_arg}")
|
|
list(FIND QT_ALL_PLUGIN_TYPES_FOUND_VIA_FIND_PACKAGE "${_plugin_type}" _has_plugin_type)
|
|
|
|
if(${_has_plugin_type} GREATER_EQUAL 0)
|
|
set(_current_type "${_plugin_type}")
|
|
else()
|
|
if("${_current_type}" STREQUAL "")
|
|
message(FATAL_ERROR "qt_import_plugins: invalid syntax for INCLUDE_BY_TYPE")
|
|
endif()
|
|
|
|
# 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)
|
|
|
|
# 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()
|
|
endforeach()
|
|
|
|
# Handle EXCLUDE_BY_TYPE
|
|
foreach(_arg ${arg_EXCLUDE_BY_TYPE})
|
|
string(REGEX REPLACE "[-/]" "_" _plugin_type "${_arg}")
|
|
set_property(TARGET "${target}" PROPERTY "QT_PLUGINS_${_plugin_type}" "-")
|
|
endforeach()
|
|
endfunction()
|
|
|
|
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
|
function(qt_import_plugins)
|
|
if(QT_DEFAULT_MAJOR_VERSION EQUAL 5)
|
|
qt5_import_plugins(${ARGV})
|
|
elseif(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
|
|
qt6_import_plugins(${ARGV})
|
|
endif()
|
|
endfunction()
|
|
endif()
|
|
|
|
# This function is currently in Technical Preview. It's signature may change or be removed entirely.
|
|
|
|
# This function allows enabling or disabling finalizer modes for a specific target.
|
|
# Currently, the only supported finalizer mode is for plugin importing in static Qt builds which
|
|
# is called 'static_plugins'. You can enable / disable it by calling
|
|
#
|
|
# qt6_set_finalizer_mode(${target} ENABLE MODES "static_plugins")
|
|
# qt6_set_finalizer_mode(${target} DISABLE MODES "static_plugins")
|
|
#
|
|
# When the "static_plugins" finalizer mode is enabled, all plugins initializer object libraries are
|
|
# directly linked to the given ${target} (executable or shared library).
|
|
# This prevents cycles between Qt provided static libraries and reduces link time, thanks to the
|
|
# libraries not being repeated on the link line because they are not part of a cycle anymore.
|
|
#
|
|
# When the finalizer mode is disabled, each plugin initializer is propagated via usage requirements
|
|
# of its associated module, which may cause cycles in the current build system implementation.
|
|
#
|
|
# The "static_plugins" finalizer mode is enabled by default if:
|
|
# - the project calls qt_finalize_target explicitly at the end of the project file or
|
|
# - the project uses qt_add_executable and a CMake version greater than or equal to 3.19
|
|
# (which will DEFER CALL qt_finalize_target)
|
|
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()
|
|
|
|
# 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:
|
|
# OUTPUT_FILES: a variable name in which to store the list of the extracted metatype json files.
|
|
# A typical use case would to install them.
|
|
#
|
|
# TODO: Move these internal options out into an internal function to be used by Qt only.
|
|
# __QT_INTERNAL_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.
|
|
# __QT_INTERNAL_NO_INSTALL: When passed, will skip installation of the metatype file.
|
|
# __QT_INTERNAL_INSTALL: Installs the metatypes files into the default Qt metatypes folder.
|
|
# Only to be used by the Qt build.
|
|
function(qt6_extract_metatypes 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
|
|
# TODO: Remove this once all leaf module usages of it are removed. It's now a no-op.
|
|
__QT_INTERNAL_NO_INSTALL
|
|
|
|
# TODO: Move this into a separate internal function, so it doesn't pollute the public one.
|
|
__QT_INTERNAL_INSTALL
|
|
)
|
|
set(args_single
|
|
# TODO: Move this into a separate internal function, so it doesn't pollute the public one.
|
|
__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")
|
|
message(FATAL_ERROR "Meta types generation does not work on interface libraries")
|
|
return()
|
|
endif()
|
|
|
|
if (CMAKE_VERSION VERSION_LESS "3.16.0")
|
|
message(FATAL_ERROR "Meta types generation requires CMake >= 3.16")
|
|
return()
|
|
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")
|
|
|
|
get_target_property(uses_automoc ${target} AUTOMOC)
|
|
set(automoc_args)
|
|
set(automoc_dependencies)
|
|
# Handle automoc generated data
|
|
if (uses_automoc)
|
|
# Tell automoc to output json files)
|
|
set_property(TARGET "${target}" APPEND PROPERTY
|
|
AUTOMOC_MOC_OPTIONS "--output-json"
|
|
)
|
|
|
|
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(multi_config_args
|
|
--cmake-autogen-include-dir-path "${target_binary_dir}/${target}_autogen/include"
|
|
)
|
|
else()
|
|
set(cmake_autogen_cache_file
|
|
"${target_binary_dir}/CMakeFiles/${target}_autogen.dir/ParseCache_$<CONFIG>.txt")
|
|
set(multi_config_args
|
|
--cmake-autogen-include-dir-path "${target_binary_dir}/${target}_autogen/include_$<CONFIG>"
|
|
"--cmake-multi-config")
|
|
endif()
|
|
|
|
set(cmake_autogen_info_file
|
|
"${target_binary_dir}/CMakeFiles/${target}_autogen.dir/AutogenInfo.json")
|
|
|
|
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)
|
|
endif()
|
|
endif()
|
|
|
|
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}
|
|
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}"
|
|
${multi_config_args}
|
|
COMMENT "Running AUTOMOC file extraction for target ${target}"
|
|
COMMAND_EXPAND_LISTS
|
|
)
|
|
add_dependencies(${target}_automoc_json_extraction ${target}_autogen)
|
|
else()
|
|
set(cmake_autogen_timestamp_file
|
|
"${target_binary_dir}/${target}_autogen/timestamp"
|
|
)
|
|
|
|
add_custom_command(OUTPUT ${type_list_file}
|
|
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::cmake_automoc_parser
|
|
${cmake_autogen_timestamp_file}
|
|
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}"
|
|
${multi_config_args}
|
|
COMMENT "Running AUTOMOC file extraction for target ${target}"
|
|
COMMAND_EXPAND_LISTS
|
|
)
|
|
|
|
endif()
|
|
set(automoc_args "@${type_list_file}")
|
|
set(automoc_dependencies "${type_list_file}")
|
|
endif()
|
|
|
|
set(manual_args)
|
|
set(manual_dependencies)
|
|
if(arg_MANUAL_MOC_JSON_FILES)
|
|
list(REMOVE_DUPLICATES arg_MANUAL_MOC_JSON_FILES)
|
|
file(GENERATE
|
|
OUTPUT ${type_list_file_manual}
|
|
CONTENT "$<JOIN:$<GENEX_EVAL:${arg_MANUAL_MOC_JSON_FILES}>,\n>"
|
|
)
|
|
list(APPEND manual_dependencies ${arg_MANUAL_MOC_JSON_FILES} ${type_list_file_manual})
|
|
set(manual_args "@${type_list_file_manual}")
|
|
endif()
|
|
|
|
if (NOT manual_args AND NOT automoc_args)
|
|
message(FATAL_ERROR "Metatype generation requires either the use of AUTOMOC or a manual list of generated json files")
|
|
endif()
|
|
|
|
if (CMAKE_BUILD_TYPE AND NOT is_multi_config)
|
|
string(TOLOWER ${target}_${CMAKE_BUILD_TYPE} target_lowercase)
|
|
else()
|
|
string(TOLOWER ${target} target_lowercase)
|
|
endif()
|
|
|
|
set(metatypes_file_name "qt6${target_lowercase}_metatypes.json")
|
|
set(metatypes_file "${target_binary_dir}/meta_types/${metatypes_file_name}")
|
|
set(metatypes_file_gen "${target_binary_dir}/meta_types/${metatypes_file_name}.gen")
|
|
|
|
set(metatypes_dep_file_name "qt6${target_lowercase}_metatypes_dep.txt")
|
|
set(metatypes_dep_file "${target_binary_dir}/meta_types/${metatypes_dep_file_name}")
|
|
|
|
# Due to generated source file dependency rules being tied to the directory
|
|
# scope in which they are created it is not possible for other targets which
|
|
# are defined in a separate scope to see these rules. This leads to failures
|
|
# in locating the generated source files.
|
|
# To work around this we write a dummy file to disk to make sure targets
|
|
# which link against the current target do not produce the error. This dummy
|
|
# file is then replaced with the contents of the generated file during
|
|
# build.
|
|
if (NOT EXISTS ${metatypes_file})
|
|
file(MAKE_DIRECTORY "${target_binary_dir}/meta_types")
|
|
file(TOUCH ${metatypes_file})
|
|
endif()
|
|
|
|
add_custom_command(
|
|
OUTPUT
|
|
${metatypes_file_gen}
|
|
${metatypes_file}
|
|
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::moc ${automoc_dependencies} ${manual_dependencies}
|
|
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::moc
|
|
-o ${metatypes_file_gen}
|
|
--collect-json ${automoc_args} ${manual_args}
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
${metatypes_file_gen}
|
|
${metatypes_file}
|
|
COMMENT "Running moc --collect-json for target ${target}"
|
|
)
|
|
|
|
# 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_source_files_properties(${metatypes_file} ${scope_args}
|
|
PROPERTIES HEADER_FILE_ONLY TRUE
|
|
)
|
|
|
|
set_target_properties(${target} PROPERTIES
|
|
INTERFACE_QT_MODULE_HAS_META_TYPES YES
|
|
INTERFACE_QT_META_TYPES_BUILD_FILE "${metatypes_file}"
|
|
)
|
|
|
|
# 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}>>"
|
|
)
|
|
target_sources(${target} INTERFACE ${metatypes_file_genex_build})
|
|
|
|
if(arg_OUTPUT_FILES)
|
|
set(${arg_OUTPUT_FILES} "${metatypes_file}" PARENT_SCOPE)
|
|
endif()
|
|
|
|
# Chech 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)
|
|
|
|
if(NOT target_type STREQUAL "EXECUTABLE" AND arg___QT_INTERNAL_INSTALL)
|
|
set(should_install TRUE)
|
|
endif()
|
|
|
|
# Automatically fill default install args when not specified.
|
|
if(NOT arg___QT_INTERNAL_INSTALL_DIR)
|
|
# INSTALL_LIBDIR is not set when QtBuildInternals is not loaded (when not doing a Qt build).
|
|
# Default to a hardcoded location for user projects.
|
|
if(INSTALL_LIBDIR)
|
|
set(install_dir "${INSTALL_LIBDIR}/metatypes")
|
|
else()
|
|
set(install_dir "lib/metatypes")
|
|
endif()
|
|
else()
|
|
set(install_dir "${arg___QT_INTERNAL_INSTALL_DIR}")
|
|
endif()
|
|
|
|
if(should_install)
|
|
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})
|
|
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()
|
|
|
|
# Generate Win32 RC files for a target. All entries in the RC file are generated
|
|
# from target properties:
|
|
#
|
|
# QT_TARGET_COMPANY_NAME: RC Company name
|
|
# QT_TARGET_DESCRIPTION: RC File Description
|
|
# QT_TARGET_VERSION: RC File and Product Version
|
|
# QT_TARGET_COPYRIGHT: RC LegalCopyright
|
|
# QT_TARGET_PRODUCT_NAME: RC ProductName
|
|
# QT_TARGET_COMMENTS: RC Comments
|
|
# QT_TARGET_ORIGINAL_FILENAME: RC Original FileName
|
|
# QT_TARGET_TRADEMARKS: RC LegalTrademarks
|
|
# QT_TARGET_INTERNALNAME: RC InternalName
|
|
# QT_TARGET_RC_ICONS: List of paths to icon files
|
|
#
|
|
# If you do not wish to auto-generate rc files, it's possible to provide your
|
|
# own RC file by setting the property QT_TARGET_WINDOWS_RC_FILE with a path to
|
|
# an existing rc file.
|
|
function(_qt_internal_generate_win32_rc_file 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)
|
|
|
|
get_target_property(target_rc_file ${target} QT_TARGET_WINDOWS_RC_FILE)
|
|
get_target_property(target_version ${target} QT_TARGET_VERSION)
|
|
|
|
if (NOT target_rc_file AND NOT target_version)
|
|
return()
|
|
endif()
|
|
|
|
if (target_rc_file)
|
|
# Use the provided RC file
|
|
target_sources(${target} PRIVATE "${target_rc_file}")
|
|
else()
|
|
# Generate RC File
|
|
set(rc_file_output "${target_binary_dir}/")
|
|
if(QT_GENERATOR_IS_MULTI_CONFIG)
|
|
string(APPEND rc_file_output "$<CONFIG>/")
|
|
endif()
|
|
string(APPEND rc_file_output "${target}_resource.rc")
|
|
set(target_rc_file "${rc_file_output}")
|
|
|
|
set(company_name "")
|
|
get_target_property(target_company_name ${target} QT_TARGET_COMPANY_NAME)
|
|
if (target_company_name)
|
|
set(company_name "${target_company_name}")
|
|
endif()
|
|
|
|
set(file_description "")
|
|
get_target_property(target_description ${target} QT_TARGET_DESCRIPTION)
|
|
if (target_description)
|
|
set(file_description "${target_description}")
|
|
endif()
|
|
|
|
set(legal_copyright "")
|
|
get_target_property(target_copyright ${target} QT_TARGET_COPYRIGHT)
|
|
if (target_copyright)
|
|
set(legal_copyright "${target_copyright}")
|
|
endif()
|
|
|
|
set(product_name "")
|
|
get_target_property(target_product_name ${target} QT_TARGET_PRODUCT_NAME)
|
|
if (target_product_name)
|
|
set(product_name "${target_product_name}")
|
|
else()
|
|
set(product_name "${target}")
|
|
endif()
|
|
|
|
set(comments "")
|
|
get_target_property(target_comments ${target} QT_TARGET_COMMENTS)
|
|
if (target_comments)
|
|
set(comments "${target_comments}")
|
|
endif()
|
|
|
|
set(legal_trademarks "")
|
|
get_target_property(target_trademarks ${target} QT_TARGET_TRADEMARKS)
|
|
if (target_trademarks)
|
|
set(legal_trademarks "${target_trademarks}")
|
|
endif()
|
|
|
|
set(product_version "")
|
|
if (target_version)
|
|
if(target_version MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+")
|
|
# nothing to do
|
|
elseif(target_version MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+")
|
|
set(target_version "${target_version}.0")
|
|
elseif(target_version MATCHES "[0-9]+\\.[0-9]+")
|
|
set(target_version "${target_version}.0.0")
|
|
elseif (target_version MATCHES "[0-9]+")
|
|
set(target_version "${target_version}.0.0.0")
|
|
else()
|
|
message(FATAL_ERROR "Invalid version format: '${target_version}'")
|
|
endif()
|
|
set(product_version "${target_version}")
|
|
else()
|
|
set(product_version "0.0.0.0")
|
|
endif()
|
|
|
|
set(file_version "${product_version}")
|
|
string(REPLACE "." "," version_comma ${product_version})
|
|
|
|
set(original_file_name "$<TARGET_FILE_NAME:${target}>")
|
|
get_target_property(target_original_file_name ${target} QT_TARGET_ORIGINAL_FILENAME)
|
|
if (target_original_file_name)
|
|
set(original_file_name "${target_original_file_name}")
|
|
endif()
|
|
|
|
set(internal_name "")
|
|
get_target_property(target_internal_name ${target} QT_TARGET_INTERNALNAME)
|
|
if (target_internal_name)
|
|
set(internal_name "${target_internal_name}")
|
|
endif()
|
|
|
|
set(icons "")
|
|
get_target_property(target_icons ${target} QT_TARGET_RC_ICONS)
|
|
if (target_icons)
|
|
set(index 1)
|
|
foreach( icon IN LISTS target_icons)
|
|
string(APPEND icons "IDI_ICON${index} ICON \"${icon}\"\n")
|
|
math(EXPR index "${index} +1")
|
|
endforeach()
|
|
endif()
|
|
|
|
set(target_file_type "VFT_DLL")
|
|
if(target_type STREQUAL "EXECUTABLE")
|
|
set(target_file_type "VFT_APP")
|
|
endif()
|
|
|
|
set(contents "#include <windows.h>
|
|
${icons}
|
|
VS_VERSION_INFO VERSIONINFO
|
|
FILEVERSION ${version_comma}
|
|
PRODUCTVERSION ${version_comma}
|
|
FILEFLAGSMASK 0x3fL
|
|
#ifdef _DEBUG
|
|
FILEFLAGS VS_FF_DEBUG
|
|
#else
|
|
FILEFLAGS 0x0L
|
|
#endif
|
|
FILEOS VOS_NT_WINDOWS32
|
|
FILETYPE ${target_file_type}
|
|
FILESUBTYPE VFT2_UNKNOWN
|
|
BEGIN
|
|
BLOCK \"StringFileInfo\"
|
|
BEGIN
|
|
BLOCK \"040904b0\"
|
|
BEGIN
|
|
VALUE \"CompanyName\", \"${company_name}\"
|
|
VALUE \"FileDescription\", \"${file_description}\"
|
|
VALUE \"FileVersion\", \"${file_version}\"
|
|
VALUE \"LegalCopyright\", \"${legal_copyright}\"
|
|
VALUE \"OriginalFilename\", \"${original_file_name}\"
|
|
VALUE \"ProductName\", \"${product_name}\"
|
|
VALUE \"ProductVersion\", \"${product_version}\"
|
|
VALUE \"Comments\", \"${comments}\"
|
|
VALUE \"LegalTrademarks\", \"${legal_trademarks}\"
|
|
VALUE \"InternalName\", \"${internal_name}\"
|
|
END
|
|
END
|
|
BLOCK \"VarFileInfo\"
|
|
BEGIN
|
|
VALUE \"Translation\", 0x0409, 1200
|
|
END
|
|
END
|
|
/* End of Version info */\n"
|
|
)
|
|
|
|
# We can't use the output of file generate as source so we work around
|
|
# this by generating the file under a different name and then copying
|
|
# the file in place using add custom command.
|
|
file(GENERATE OUTPUT "${rc_file_output}.tmp"
|
|
CONTENT "${contents}"
|
|
)
|
|
|
|
if(QT_GENERATOR_IS_MULTI_CONFIG)
|
|
set(cfgs ${CMAKE_CONFIGURATION_TYPES})
|
|
set(outputs "")
|
|
foreach(cfg ${cfgs})
|
|
string(REPLACE "$<CONFIG>" "${cfg}" expanded_rc_file_output "${rc_file_output}")
|
|
list(APPEND outputs "${expanded_rc_file_output}")
|
|
endforeach()
|
|
else()
|
|
set(cfgs "${CMAKE_BUILD_TYPE}")
|
|
set(outputs "${rc_file_output}")
|
|
endif()
|
|
|
|
# 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 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)
|
|
set(input "${output}.tmp")
|
|
add_custom_command(OUTPUT "${output}"
|
|
DEPENDS "${input}"
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${input}" "${output}"
|
|
)
|
|
# We can't rely on policy CMP0118 since user project controls it
|
|
set_source_files_properties(${output} ${scope_args}
|
|
PROPERTIES GENERATED TRUE
|
|
)
|
|
target_sources(${end_target} PRIVATE "$<$<CONFIG:${cfg}>:${output}>")
|
|
endwhile()
|
|
endif()
|
|
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}")
|
|
endif()
|
|
set(${output_alias} ${alias} PARENT_SCOPE)
|
|
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 beginnig 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>>>"
|
|
)
|
|
|
|
# Collect object library specific conditions.
|
|
if(arg_EXTRA_CONDITIONS)
|
|
list(JOIN arg_EXTRA_CONDITIONS "," extra_conditions)
|
|
else()
|
|
set(extra_conditions "$<BOOL:TRUE>")
|
|
endif()
|
|
|
|
# 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}>>"
|
|
)
|
|
|
|
# Use TARGET_NAME to have the correct namespaced name in the exports.
|
|
set(objects "$<TARGET_OBJECTS:$<TARGET_NAME:${object_library}>>")
|
|
|
|
# Collect link conditions for the target_sources call.
|
|
string(JOIN "" target_sources_genex
|
|
"$<"
|
|
"$<AND:"
|
|
"${not_finalizer_mode_condition},"
|
|
"${not_static_condition},"
|
|
"${platform_link_order_condition},"
|
|
"$<NOT:${link_objects_using_link_options_condition}>,"
|
|
"${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 greated than or equal 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_finalizer_mode_condition},"
|
|
"${not_static_condition},"
|
|
"$<NOT:${platform_link_order_condition}>,"
|
|
"${extra_conditions}"
|
|
">"
|
|
":${objects}>"
|
|
)
|
|
target_link_libraries(${target} INTERFACE
|
|
"${target_link_libraries_genex}"
|
|
)
|
|
|
|
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)
|
|
get_target_property(resource_count ${target} _qt_generated_resource_target_count)
|
|
if(NOT resource_count)
|
|
set(resource_count "0")
|
|
endif()
|
|
math(EXPR resource_count "${resource_count} + 1")
|
|
set_target_properties(${target} PROPERTIES _qt_generated_resource_target_count ${resource_count})
|
|
|
|
set(resource_target "${target}_resources_${resource_count}")
|
|
add_library("${resource_target}" OBJECT "${generated_source_code}")
|
|
target_compile_definitions("${resource_target}" PRIVATE
|
|
"$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::Core,INTERFACE_COMPILE_DEFINITIONS>"
|
|
)
|
|
_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.
|
|
# The path will be used in static library prl file generation to ensure qmake links
|
|
# against the installed resource object files.
|
|
# Example saved path:
|
|
# .rcc/qrc_qprintdialog.cpp
|
|
file(RELATIVE_PATH generated_cpp_file_relative_path
|
|
"${CMAKE_CURRENT_BINARY_DIR}"
|
|
"${generated_source_code}")
|
|
set_property(TARGET ${resource_target} APPEND PROPERTY
|
|
_qt_resource_generated_cpp_relative_path "${generated_cpp_file_relative_path}")
|
|
|
|
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}
|
|
)
|
|
|
|
set(${output_generated_target} "${resource_target}" PARENT_SCOPE)
|
|
else()
|
|
set(${output_generated_target} "" PARENT_SCOPE)
|
|
target_sources(${target} PRIVATE ${generated_source_code})
|
|
endif()
|
|
endfunction()
|
|
|
|
# Creates fake targets and adds resource files to IDE's tree
|
|
# FIXME: We shouldn't need to create a separate target for this, the files
|
|
# should be added to the actual target instead.
|
|
function(_qt_internal_expose_source_file_to_ide target file)
|
|
set(ide_target ${target}_other_files)
|
|
if(NOT TARGET ${ide_target})
|
|
add_custom_target(${ide_target} SOURCES "${file}")
|
|
else()
|
|
set_property(TARGET ${ide_target} APPEND PROPERTY SOURCES "${file}")
|
|
endif()
|
|
endfunction()
|
|
|
|
#
|
|
# Process resources via file path instead of QRC files. Behind the
|
|
# 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_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})
|
|
|
|
if("${rcc_OPTIONS}" MATCHES "-binary")
|
|
set(isBinary TRUE)
|
|
endif()
|
|
|
|
string(REPLACE "/" "_" resourceName ${resourceName})
|
|
string(REPLACE "." "_" resourceName ${resourceName})
|
|
|
|
set(resource_files ${rcc_FILES})
|
|
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()
|
|
endforeach()
|
|
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.")
|
|
endif()
|
|
endif()
|
|
|
|
if (NOT resource_files)
|
|
if (rcc_OUTPUT_TARGETS)
|
|
set(${rcc_OUTPUT_TARGETS} "" PARENT_SCOPE)
|
|
endif()
|
|
return()
|
|
endif()
|
|
set(generatedResourceFile "${CMAKE_CURRENT_BINARY_DIR}/.rcc/${resourceName}.qrc")
|
|
|
|
# Generate .qrc file:
|
|
|
|
# <RCC><qresource ...>
|
|
set(qrcContents "<RCC>\n <qresource")
|
|
if (rcc_PREFIX)
|
|
string(APPEND qrcContents " prefix=\"${rcc_PREFIX}\"")
|
|
endif()
|
|
if (rcc_LANG)
|
|
string(APPEND qrcContents " lang=\"${rcc_LANG}\"")
|
|
endif()
|
|
string(APPEND qrcContents ">\n")
|
|
|
|
set(resource_dependencies)
|
|
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()
|
|
|
|
### FIXME: escape file paths to be XML conform
|
|
# <file ...>...</file>
|
|
string(APPEND qrcContents " <file alias=\"${file_resource_path}\">")
|
|
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.")
|
|
endif()
|
|
list(APPEND resource_dependencies ${target_dependency})
|
|
endif()
|
|
_qt_internal_expose_source_file_to_ide(${target} "${file}")
|
|
endforeach()
|
|
|
|
# </qresource></RCC>
|
|
string(APPEND qrcContents " </qresource>\n</RCC>\n")
|
|
|
|
set(template_file "${__qt_core_macros_module_base_dir}/Qt6CoreConfigureFileTemplate.in")
|
|
set(qt_core_configure_file_contents "${qrcContents}")
|
|
configure_file("${template_file}" "${generatedResourceFile}")
|
|
|
|
set(rccArgs --name "${resourceName}" "${generatedResourceFile}")
|
|
|
|
if(rcc_OPTIONS)
|
|
list(APPEND rccArgs ${rcc_OPTIONS})
|
|
endif()
|
|
|
|
# When cross-building, we use host tools to generate target code. If the host rcc was compiled
|
|
# with zstd support, it expects the target QtCore to be able to decompress zstd compressed
|
|
# content. This might be true with qmake where host tools are built as part of the
|
|
# cross-compiled Qt, but with CMake we build tools separate from the cross-compiled Qt.
|
|
# 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")
|
|
endif()
|
|
|
|
set_property(SOURCE "${generatedResourceFile}" PROPERTY SKIP_AUTOGEN ON)
|
|
|
|
# Set output file name for rcc command
|
|
if(isBinary)
|
|
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)
|
|
if("${destinationRccExt}" STREQUAL ".rcc")
|
|
set(generatedOutfile "${rcc_DESTINATION}")
|
|
else()
|
|
set(generatedOutfile "${rcc_DESTINATION}.rcc")
|
|
endif()
|
|
endif()
|
|
else()
|
|
set(generatedOutfile "${CMAKE_CURRENT_BINARY_DIR}/.rcc/qrc_${resourceName}.cpp")
|
|
endif()
|
|
|
|
list(PREPEND rccArgs --output "${generatedOutfile}")
|
|
|
|
# Process .qrc file:
|
|
add_custom_command(OUTPUT "${generatedOutfile}"
|
|
COMMAND "${QT_CMAKE_EXPORT_NAMESPACE}::rcc" ${rccArgs}
|
|
DEPENDS
|
|
${resource_dependencies}
|
|
${generatedResourceFile}
|
|
"${QT_CMAKE_EXPORT_NAMESPACE}::rcc"
|
|
COMMENT "Running rcc for resource ${resourceName}"
|
|
VERBATIM)
|
|
|
|
set(output_targets "")
|
|
if(isBinary)
|
|
# Add generated .rcc target to 'all' set
|
|
add_custom_target(binary_resource_${resourceName} ALL DEPENDS "${generatedOutfile}")
|
|
else()
|
|
# 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
|
|
)
|
|
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()
|
|
set_property(TARGET ${target} APPEND PROPERTY _qt_generated_qrc_files "${generatedResourceFile}")
|
|
|
|
__qt_propagate_generated_resource(${target} ${resourceName} "${generatedOutfile}" output_targets)
|
|
endif()
|
|
if (rcc_OUTPUT_TARGETS)
|
|
set(${rcc_OUTPUT_TARGETS} "${output_targets}" PARENT_SCOPE)
|
|
endif()
|
|
endfunction()
|
|
|
|
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}
|
|
# TODO: For backward compatibility / transitional use only, remove once all repos no longer
|
|
# use it
|
|
TYPE
|
|
|
|
PLUGIN_TYPE
|
|
CLASS_NAME
|
|
OUTPUT_NAME
|
|
OUTPUT_TARGETS
|
|
)
|
|
set(${multi_args})
|
|
endmacro()
|
|
|
|
# This function is currently in Technical Preview.
|
|
# It's signature and behavior might change.
|
|
function(qt6_add_plugin target)
|
|
_qt_internal_get_add_plugin_keywords(opt_args single_args multi_args)
|
|
|
|
# TODO: Transitional use only, replaced by CLASS_NAME. Remove this once
|
|
# all other repos have been updated to use CLASS_NAME.
|
|
list(APPEND single_args CLASSNAME)
|
|
|
|
cmake_parse_arguments(PARSE_ARGV 1 arg "${opt_args}" "${single_args}" "${multi_args}")
|
|
|
|
# Handle the inconsistent CLASSNAME/CLASS_NAME keyword naming between commands
|
|
if(arg_CLASSNAME)
|
|
if(arg_CLASS_NAME AND NOT arg_CLASSNAME STREQUAL arg_CLASS_NAME)
|
|
message(FATAL_ERROR
|
|
"Both CLASSNAME and CLASS_NAME were given and were different. "
|
|
"Only one of the two should be used."
|
|
)
|
|
endif()
|
|
set(arg_CLASS_NAME "${arg_CLASSNAME}")
|
|
unset(arg_CLASSNAME)
|
|
endif()
|
|
|
|
# Handle the inconsistent TYPE/PLUGIN_TYPE keyword naming between commands
|
|
if(arg_TYPE)
|
|
if(arg_PLUGIN_TYPE AND NOT arg_TYPE STREQUAL arg_PLUGIN_TYPE)
|
|
message(FATAL_ERROR
|
|
"Both TYPE and PLUGIN_TYPE were given and were different. "
|
|
"Only one of the two should be used."
|
|
)
|
|
endif()
|
|
message(AUTHOR_WARNING
|
|
"The TYPE keyword is deprecated and will be removed soon. Please use PLUGIN_TYPE instead.")
|
|
set(arg_PLUGIN_TYPE "${arg_TYPE}")
|
|
unset(arg_TYPE)
|
|
endif()
|
|
|
|
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()
|
|
# 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})
|
|
|
|
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})
|
|
endif()
|
|
set_property(TARGET "${target}" PROPERTY OUTPUT_NAME "${output_name}")
|
|
|
|
if (ANDROID)
|
|
set_target_properties(${target}
|
|
PROPERTIES
|
|
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_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()
|
|
# 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}")
|
|
|
|
# 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
|
|
)
|
|
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()
|
|
|
|
# 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})
|
|
|
|
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(QT6_IS_SHARED_LIBS_BUILD)
|
|
set(type_to_create SHARED)
|
|
else()
|
|
set(type_to_create STATIC)
|
|
endif()
|
|
endif()
|
|
|
|
add_library(${target} ${type_to_create} ${arg_UNPARSED_ARGUMENTS})
|
|
_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)
|
|
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()
|
|
|
|
# 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.
|
|
function(qt6_allow_non_utf8_sources target)
|
|
set_target_properties("${target}" PROPERTIES QT_NO_UTF8_SOURCE TRUE)
|
|
endfunction()
|
|
|
|
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
|
function(qt_allow_non_utf8_sources)
|
|
qt6_allow_non_utf8_sources(${ARGV})
|
|
endfunction()
|
|
endif()
|
|
|
|
function(_qt_internal_apply_strict_cpp target)
|
|
# Disable C, Obj-C and C++ GNU extensions aka no "-std=gnu++11".
|
|
# Similar to mkspecs/features/default_post.prf's CONFIG += strict_cpp.
|
|
# Allow opt-out via variable.
|
|
if(NOT QT_ENABLE_CXX_EXTENSIONS)
|
|
get_target_property(target_type "${target}" TYPE)
|
|
if(NOT target_type STREQUAL "INTERFACE_LIBRARY")
|
|
set_target_properties("${target}" PROPERTIES
|
|
CXX_EXTENSIONS OFF
|
|
C_EXTENSIONS OFF
|
|
OBJC_EXTENSIONS OFF
|
|
OBJCXX_EXTENSIONS OFF)
|
|
endif()
|
|
endif()
|
|
endfunction()
|
|
|
|
# Wraps a tool command with a script that contains the necessary environment for the tool to run
|
|
# correctly.
|
|
# _qt_internal_wrap_tool_command(var <SET|APPEND> <command> [args...])
|
|
# Arguments:
|
|
# APPEND Selects the 'append' mode for the out_variable argument.
|
|
# SET Selects the 'set' mode for the out_variable argument.
|
|
function(_qt_internal_wrap_tool_command out_variable action)
|
|
set(append FALSE)
|
|
if(action STREQUAL "APPEND")
|
|
set(append TRUE)
|
|
elseif(NOT action STREQUAL "SET")
|
|
message(FATAL_ERROR "Invalid action specified ${action}. Supported actions: SET, APPEND")
|
|
endif()
|
|
|
|
set(cmd COMMAND ${QT_TOOL_COMMAND_WRAPPER_PATH} ${ARGN})
|
|
|
|
if(append)
|
|
list(APPEND ${out_variable} ${cmd})
|
|
else()
|
|
set(${out_variable} ${cmd})
|
|
endif()
|
|
set(${out_variable} "${${out_variable}}" PARENT_SCOPE)
|
|
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()
|
|
|
|
# Disables the default unicode definitions for the target
|
|
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_target_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()
|