Revision control

Copy as Markdown

# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#
# QtDeclarative Specific extensions
#
include_guard(GLOBAL)
macro(qt_internal_get_internal_add_qml_module_keywords
option_args single_args multi_args
internal_option_args internal_single_args internal_multi_args)
set(${option_args}
DESIGNER_SUPPORTED
FOLLOW_FOREIGN_VERSIONING
NO_PLUGIN
NO_PLUGIN_OPTIONAL
NO_CREATE_PLUGIN_TARGET
NO_GENERATE_PLUGIN_SOURCE
NO_GENERATE_QMLTYPES
NO_GENERATE_QMLDIR
NO_GENERATE_EXTRA_QMLDIRS
NO_LINT
NO_CACHEGEN
ENABLE_TYPE_COMPILER
__QT_INTERNAL_STATIC_MODULE
__QT_INTERNAL_SYSTEM_MODULE
__QT_INTERNAL_NO_GENERATE_QMLLS_BUILD_INI
)
set(${single_args}
URI
VERSION
PLUGIN_TARGET
TYPEINFO
CLASS_NAME
TYPE_COMPILER_NAMESPACE
)
set(${multi_args}
QML_FILES
RESOURCES
IMPORTS
IMPORT_PATH
OPTIONAL_IMPORTS
DEFAULT_IMPORTS
DEPENDENCIES
PAST_MAJOR_VERSIONS
)
# Args used by qt_internal_add_qml_module directly, which should not be passed to any other
# functions.
#
# INSTALL_SOURCE_QMLTYPES takes a path to an existing plugins.qmltypes file that should be
# installed.
#
# INSTALL_SOURCE_QMLDIR takes a path to an existing qmldir file that should be installed.
set(${internal_option_args}
)
set(${internal_single_args}
INSTALL_SOURCE_QMLTYPES
INSTALL_SOURCE_QMLDIR
)
set(${internal_multi_args}
)
endmacro()
# This function is essentially a wrapper around qt6_add_qml_module().
# It creates the targets explicitly and sets up internal properties before
# passing those targets to qt6_add_qml_module() for further updates.
# All keywords supported by qt_internal_add_module() can be used, as can most
# keywords for qt6_add_qml_module() except RESOURCE_PREFIX and
# OUTPUT_TARGETS.
#
# OUTPUT_DIRECTORY and INSTALL_DIRECTORY will be given more appropriate defaults
# if not provided by the caller. The defaults are usually what you want to use.
#
# - SOURCES is only passed through to qt_internal_add_plugin() or
# qt_internal_add_module() but not to qt6_add_qml_module().
#
# See qt_internal_add_plugin() and qt6_add_qml_module() for the full set of
# supported keywords.
function(qt_internal_add_qml_module target)
qt_internal_get_internal_add_module_keywords(
module_option_args
module_single_args
module_multi_args
)
qt_internal_get_internal_add_qml_module_keywords(
qml_module_option_args
qml_module_single_args
qml_module_multi_args
qml_module_internal_option_args
qml_module_internal_single_args
qml_module_internal_multi_args
)
# TODO: Remove these once all repos have been updated to not use them
set(ignore_option_args
PLUGIN_OPTIONAL # Now the default
GENERATE_QMLTYPES # Now the default
INSTALL_QMLTYPES # Now the default
)
set(option_args
${module_option_args}
${qml_module_option_args}
${ignore_option_args}
${qml_module_internal_option_args}
)
set(single_args
${module_single_args}
${qml_module_single_args}
${qml_module_internal_single_args}
)
set(multi_args
${module_multi_args}
${qml_module_multi_args}
${qml_module_internal_multi_args}
)
cmake_parse_arguments(PARSE_ARGV 1 arg
"${option_args}"
"${single_args}"
"${multi_args}"
)
_qt_internal_validate_all_args_are_parsed(arg)
set(QT_QML_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_QMLDIR}")
string(REPLACE "." "/" target_path ${arg_URI})
if(NOT arg_OUTPUT_DIRECTORY)
set(arg_OUTPUT_DIRECTORY "${QT_QML_OUTPUT_DIRECTORY}/${target_path}")
endif()
if(NOT arg_INSTALL_DIRECTORY)
set(arg_INSTALL_DIRECTORY "${INSTALL_QMLDIR}/${target_path}")
endif()
if(arg_NO_PLUGIN)
unset(arg_PLUGIN_TARGET)
elseif(NOT arg_PLUGIN_TARGET)
set(arg_PLUGIN_TARGET ${target}plugin)
endif()
set(plugin_args "")
if(arg_NO_PLUGIN OR NOT arg_PLUGIN_TARGET STREQUAL target)
# Allow using an existing backing target.
if(NOT TARGET ${target})
# Create the backing target now to handle module-related things
qt_remove_args(module_args
ARGS_TO_REMOVE
${ignore_option_args}
${qml_module_option_args}
${qml_module_single_args}
${qml_module_multi_args}
${qml_module_internal_option_args}
${qml_module_internal_single_args}
${qml_module_internal_multi_args}
OUTPUT_DIRECTORY
INSTALL_DIRECTORY
ALL_ARGS
${option_args}
${single_args}
${multi_args}
ARGS
${ARGN}
)
qt_internal_add_module(${target} ${module_args})
elseif(arg_SOURCES)
# If a module target was pre-created, we still need to pass the additional sources.
target_sources(${target} PRIVATE ${arg_SOURCES})
endif()
else()
# Since we are not creating a separate backing target, we have to pass
# through the default args to the plugin target creation instead
qt_internal_get_internal_add_plugin_keywords(
plugin_option_args plugin_single_args plugin_multi_args
)
set(args_to_remove ${option_args} ${single_args} ${multi_args})
list(REMOVE_ITEM args_to_remove
${plugin_option_args}
${plugin_single_args}
${plugin_multi_args}
)
qt_remove_args(plugin_args
ARGS_TO_REMOVE
${args_to_remove}
DEFAULT_IF
OUTPUT_DIRECTORY
INSTALL_DIRECTORY
CLASS_NAME
ALL_ARGS
${option_args}
${single_args}
${multi_args}
ARGS
${ARGN}
)
endif()
set(add_qml_module_args "")
if(NOT arg_NO_PLUGIN AND NOT arg_NO_CREATE_PLUGIN_TARGET)
# If the qt_internal_add_qml_module call didn't specify a CLASS_NAME, we need to pre-compute
# it here and pass it along to qt_internal_add_plugin -> qt_add_plugin so that
# qt_add_qml_plugin does not complain about differing class names (the default pre-computed
# class name of a regular plugin and qml plugin are different).
if(NOT arg_CLASS_NAME)
_qt_internal_compute_qml_plugin_class_name_from_uri("${arg_URI}" arg_CLASS_NAME)
endif()
# If the module is explicitly marked as STATIC, the plugin should inherit that as well.
set(static_plugin "")
if(arg_STATIC)
set(static_plugin "STATIC")
endif()
# Create plugin target now so we can set internal things
list(APPEND plugin_args
${static_plugin}
PLUGIN_TYPE qml_plugin
DEFAULT_IF FALSE
OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY}
CLASS_NAME ${arg_CLASS_NAME}
)
if(NOT arg_PLUGIN_TARGET STREQUAL target)
# This is needed so that the dependency to the backing target is included in
# the plugin's Dependencies.cmake -> _qt_internal_find_qt_dependencies() call.
# For static builds, we need the backing target to be available for transitive
# linkage. For shared builds, we need it for (Android) deployment reasons.
list(APPEND plugin_args LIBRARIES Qt::${target})
endif()
qt_internal_add_plugin(${arg_PLUGIN_TARGET} ${plugin_args})
# Use the plugin target name as the main part of the plugin basename.
set(plugin_basename "${arg_PLUGIN_TARGET}")
# If the target name already ends with a "plugin" suffix, remove it and re-add it to the end
# of the base name after the infix.
if(plugin_basename MATCHES "(.+)plugin$")
set(plugin_basename "${CMAKE_MATCH_1}")
endif()
# Add a the infix if Qt was configured with one.
if(QT_LIBINFIX)
string(APPEND plugin_basename "${QT_LIBINFIX}")
endif()
# Add the "plugin" suffix after the infix.
string(APPEND plugin_basename "plugin")
# Lowercase the whole thing and use it as the basename of the plugin library.
string(TOLOWER "${plugin_basename}" plugin_basename)
set_target_properties(${arg_PLUGIN_TARGET} PROPERTIES
OUTPUT_NAME "${plugin_basename}"
)
get_target_property(export_name ${arg_PLUGIN_TARGET} EXPORT_NAME)
if(export_name)
list(APPEND add_qml_module_args
INSTALLED_PLUGIN_TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${export_name}"
)
else()
list(APPEND add_qml_module_args
INSTALLED_PLUGIN_TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${arg_PLUGIN_TARGET}"
)
endif()
list(APPEND add_qml_module_args
INSTALLED_BACKING_TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${target}"
)
endif()
# TODO: Check if we need arg_SOURCES in this condition
if (arg_SOURCES AND NOT arg_TYPEINFO)
set(arg_TYPEINFO "plugins.qmltypes")
endif()
# Pass through options if given (these are present/absent, not true/false)
foreach(opt IN LISTS qml_module_option_args)
if(arg_${opt})
list(APPEND add_qml_module_args ${opt})
endif()
endforeach()
# Pass through single and multi-value args as provided.
foreach(arg IN LISTS qml_module_single_args qml_module_multi_args)
if(DEFINED arg_${arg})
list(APPEND add_qml_module_args ${arg} ${arg_${arg}})
endif()
endforeach()
if (arg_FOLLOW_FOREIGN_VERSIONING)
message(FATAL_ERROR "Do not set FOLLOW_FOREIGN_VERSIONING for module ${target}. It is already set by default for internal modules.")
endif()
get_target_property(qt_namespace ${QT_CMAKE_EXPORT_NAMESPACE}::Core QT_NAMESPACE)
if(qt_namespace)
list(APPEND add_qml_module_args NAMESPACE ${qt_namespace})
endif()
if (arg_ENABLE_TYPE_COMPILER AND NOT arg_TYPE_COMPILER_NAMESPACE)
# if qmltc namespace is not specified explicitly, use Qt's namespace
list(APPEND add_qml_module_args TYPE_COMPILER_NAMESPACE ${qt_namespace})
endif()
if((NOT arg_NO_GENERATE_QMLDIR) OR arg_INSTALL_SOURCE_QMLDIR)
list(APPEND add_qml_module_args
INSTALLED_QMLDIR_PATH
"${arg_INSTALL_DIRECTORY}/qmldir")
endif()
# Update the backing and plugin targets with qml-specific things.
qt6_add_qml_module(${target}
${add_qml_module_args}
OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
RESOURCE_PREFIX "/qt-project.org/imports"
OUTPUT_TARGETS output_targets
FOLLOW_FOREIGN_VERSIONING
)
if(TARGET "${target}" AND NOT target STREQUAL "Qml")
qt_internal_add_autogen_sync_header_dependencies(${target} Qml)
endif()
if(TARGET "${arg_PLUGIN_TARGET}" AND NOT target STREQUAL arg_PLUGIN_TARGET)
qt_internal_add_autogen_sync_header_dependencies(${arg_PLUGIN_TARGET} Qml)
endif()
if(output_targets)
set(plugin_export_targets)
set(backing_lib_export_targets)
# Separate which output target should go to which export set.
# The plugin initializer library should go to the plugin export set, the rest should go to
# the backing lib export set.
# In the case when the plugin target is the same as the backing lib target, all of the
# output targets will go to the plugin export set.
foreach(output_target IN LISTS output_targets)
get_target_property(is_plugin_init ${output_target} _is_qt_plugin_init_target)
if(is_plugin_init)
list(APPEND plugin_export_targets ${output_target})
# Plugin initializers associated with an internal module need the internal
# platform flags.
qt_internal_link_internal_platform_for_object_library("${output_target}"
PARENT_TARGET "${target}")
else()
list(APPEND backing_lib_export_targets ${output_target})
endif()
endforeach()
if(backing_lib_export_targets)
qt_install(TARGETS ${backing_lib_export_targets}
EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets"
DESTINATION "${arg_INSTALL_DIRECTORY}"
)
qt_internal_record_rcc_object_files(${target} "${backing_lib_export_targets}"
INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}"
)
qt_internal_add_targets_to_additional_targets_export_file(
TARGETS ${backing_lib_export_targets}
EXPORT_NAME_PREFIX "${INSTALL_CMAKE_NAMESPACE}${target}"
)
endif()
if(arg_PLUGIN_TARGET AND plugin_export_targets)
qt_install(TARGETS ${plugin_export_targets}
EXPORT "${INSTALL_CMAKE_NAMESPACE}${arg_PLUGIN_TARGET}Targets"
DESTINATION "${arg_INSTALL_DIRECTORY}"
)
qt_internal_add_targets_to_additional_targets_export_file(
TARGETS ${plugin_export_targets}
EXPORT_NAME_PREFIX "${INSTALL_CMAKE_NAMESPACE}${arg_PLUGIN_TARGET}"
)
endif()
endif()
if(DEFINED arg_QML_FILES OR DEFINED arg_RESOURCES)
foreach(resource_file IN LISTS arg_QML_FILES arg_RESOURCES)
__qt_get_relative_resource_path_for_file(file_resource_path ${resource_file})
get_filename_component(resource_dir ${file_resource_path} DIRECTORY)
get_filename_component(resource_name ${file_resource_path} NAME)
if(resource_dir)
set(dest "${arg_INSTALL_DIRECTORY}/${resource_dir}")
else()
set(dest "${arg_INSTALL_DIRECTORY}")
endif()
qt_install(
FILES ${resource_file}
DESTINATION ${dest}
RENAME ${resource_name}
)
endforeach()
endif()
if(NOT arg_NO_GENERATE_QMLTYPES)
qt_install(
FILES ${arg_OUTPUT_DIRECTORY}/$<TARGET_PROPERTY:${target},QT_QML_MODULE_TYPEINFO>
DESTINATION "${arg_INSTALL_DIRECTORY}"
)
# Assign the install time metatypes file of the backing library to the plugin.
# Only do it if the backing library is different from the plugin and we do generate
# qml types.
# The install time metatypes only apply to Qt's own qml plugins, not to user project
# qml plugins.
if(arg_PLUGIN_TARGET AND
TARGET "${arg_PLUGIN_TARGET}" AND NOT target STREQUAL arg_PLUGIN_TARGET)
_qt_internal_get_metatypes_install_dir(
""
"${INSTALL_ARCHDATADIR}"
install_dir
)
_qt_internal_assign_install_metatypes_files_and_properties(
"${arg_PLUGIN_TARGET}"
INSTALL_DIR "${install_dir}"
)
endif()
endif()
if(NOT arg_NO_GENERATE_QMLDIR)
qt_install(
FILES ${arg_OUTPUT_DIRECTORY}/qmldir
DESTINATION "${arg_INSTALL_DIRECTORY}"
)
get_target_property(extra_qmldirs ${target} _qt_internal_extra_qmldirs)
if(extra_qmldirs)
foreach(extra_qmldir IN LISTS extra_qmldirs)
__qt_get_relative_resource_path_for_file(qmldir_resource_path ${extra_qmldir})
get_filename_component(qmldir_dir ${qmldir_resource_path} DIRECTORY)
qt_install(
FILES ${extra_qmldir}
DESTINATION "${arg_INSTALL_DIRECTORY}/${qmldir_dir}"
)
endforeach()
endif()
endif()
if(arg_INSTALL_SOURCE_QMLTYPES)
message(AUTHOR_WARNING
"INSTALL_SOURCE_QMLTYPES option is deprecated and should not be used. "
"Please port your module to use declarative type registration.")
set(files ${arg_INSTALL_SOURCE_QMLTYPES})
if(QT_WILL_INSTALL)
install(
FILES ${files}
DESTINATION "${arg_INSTALL_DIRECTORY}"
)
else()
file(
COPY ${files}
DESTINATION "${arg_OUTPUT_DIRECTORY}"
)
endif()
endif()
if(arg_INSTALL_SOURCE_QMLDIR)
message(AUTHOR_WARNING
"INSTALL_SOURCE_QMLDIR option is deprecated and should not be used. "
"Please port your module to use declarative type registration.")
set(files ${arg_INSTALL_SOURCE_QMLDIR})
if(QT_WILL_INSTALL)
install(
FILES ${files}
DESTINATION "${arg_INSTALL_DIRECTORY}"
)
else()
file(
COPY ${files}
DESTINATION "${arg_OUTPUT_DIRECTORY}"
)
endif()
endif()
endfunction()