aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/Qt6QmlBuildInternals.cmake
diff options
context:
space:
mode:
authorCraig Scott <craig.scott@qt.io>2021-06-02 16:54:21 +1000
committerCraig Scott <craig.scott@qt.io>2021-06-04 16:54:52 +1000
commit1c4ba17015fe99da48ce73fab75ecc60cf9cb975 (patch)
tree1311d8cebc4007d43888477045ca534404f2f7ca /src/qml/Qt6QmlBuildInternals.cmake
parent6432e00b954beec7d0c6bc9b70fed6191b87bd38 (diff)
Refactor and update qml CMake API
The existing CMake API for qml modules had a number of shortcomings. Refactor it to achieve the following: - Clearly separate public and internal aspects. - Re-use code from qtbase for adding plugins and module targets rather than reimplementing close variations. - Provide more robust and complete support for qmllint, qmlcachegen and automatic generation of qmldir files. - Reduce the steps needed for more common scenarios. - Encourage the use of separate backing library and plugin targets. - Automatically generate the plugin class .cpp file where possible. - Specify .qml files directly through qml-specific API elements rather than assuming they can be extracted out of a set of resources. [ChangeLog][QtQml] The qml CMake API has changed from 6.1 and is now out of Technical Preview status. The most notable change is that .qml files should no longer be specified as resources, there is dedicated handling for them in the qt6_add_qml_module(). A related change is that the qt6_target_qml_files() command has been replaced by qt6_target_qml_sources(). More complete integration with qmlcachegen, qmllint and qmldir generation is also part of the CMake API. Fixes: QTBUG-91621 Task-number: QTBUG-82598 Task-number: QTBUG-88763 Task-number: QTBUG-89274 Task-number: QTBUG-91444 Change-Id: I25aae1b0e89890394dfe2ba2824008164b2ca8d9 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'src/qml/Qt6QmlBuildInternals.cmake')
-rw-r--r--src/qml/Qt6QmlBuildInternals.cmake289
1 files changed, 224 insertions, 65 deletions
diff --git a/src/qml/Qt6QmlBuildInternals.cmake b/src/qml/Qt6QmlBuildInternals.cmake
index ef2c1c4ac6..5196a2f7ed 100644
--- a/src/qml/Qt6QmlBuildInternals.cmake
+++ b/src/qml/Qt6QmlBuildInternals.cmake
@@ -4,51 +4,58 @@
include_guard(GLOBAL)
-# This function is essentially a convenience wrapper around a pair of calls
-# to qt_internal_add_plugin() and qt6_add_qml_module(). It ensures a consistent
-# set of arguments are used for both. Most keywords for either command are
-# supported, with a few exceptions:
+# 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.
#
-# - RESOURCE_PREFIX and RESOURCE_EXPORT are both hard-coded and cannot be
-# overridden by the caller.
-# - OUTPUT_DIRECTORY and INSTALL_DIRECTORY will be set if not provided.
-# - SOURCES is only passed through to qt_internal_add_plugin() but not to
-# qt6_add_qml_module(). If SOURCES is not set, PURE_MODULE will be passed to
-# qt6_add_qml_module() so that a dummy plugin.cpp file will be generated.
+# 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_add_plugin_keywords(
- public_option_args
- public_single_args
- public_multi_args
- )
- qt_internal_get_internal_add_plugin_keywords(
- internal_option_args
- internal_single_args
- internal_multi_args
+ qt_internal_get_internal_add_module_keywords(
+ module_option_args
+ module_single_args
+ module_multi_args
)
# We don't want to pass CLASS_NAME to qt_internal_add_plugin(), we will
# pass it to qt6_add_qml_module() to handle instead. qt_internal_add_plugin()
# would just ignore it anyway because we set TYPE to qml_plugin, but we have
# to remove it to prevent duplicates in argument parsing.
- list(REMOVE_ITEM public_single_args CLASS_NAME)
+ list(REMOVE_ITEM module_single_args CLASS_NAME)
set(qml_module_option_args
- GENERATE_QMLTYPES
- INSTALL_QMLTYPES
DESIGNER_SUPPORTED
- SKIP_TYPE_REGISTRATION
- PLUGIN_OPTIONAL
+ NO_PLUGIN_OPTIONAL
+ NO_CREATE_PLUGIN_TARGET
+ NO_GENERATE_PLUGIN_SOURCE
+ NO_GENERATE_QMLTYPES
+ NO_GENERATE_QMLDIR
+ NO_LINT
+ NO_CACHEGEN
+ )
+ # TODO: Remove these once all repos have been updated to not use them
+ set(ignore_option_args
+ SKIP_TYPE_REGISTRATION # Now always done
+ PLUGIN_OPTIONAL # Now the default
+ GENERATE_QMLTYPES # Now the default
+ INSTALL_QMLTYPES # Now the default
)
set(qml_module_single_args
URI
TARGET_PATH
VERSION
+ PLUGIN_TARGET
TYPEINFO
CLASS_NAME
CLASSNAME # TODO: Remove once all other repos have been updated to use
@@ -56,26 +63,36 @@ function(qt_internal_add_qml_module target)
)
set(qml_module_multi_args
+ # SOURCES will be handled by qt_internal_add_module()
QML_FILES
IMPORTS
+ IMPORT_PATH
OPTIONAL_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_single_args
+ INSTALL_SOURCE_QMLTYPES
+ INSTALL_SOURCE_QMLDIR)
+
set(option_args
- ${public_option_args}
- ${internal_option_args}
+ ${module_option_args}
${qml_module_option_args}
+ ${ignore_option_args}
)
set(single_args
- ${public_single_args}
- ${internal_single_args}
+ ${module_single_args}
${qml_module_single_args}
+ ${internal_single_args}
)
set(multi_args
- ${public_multi_args}
- ${internal_multi_args}
+ ${module_multi_args}
${qml_module_multi_args}
)
@@ -86,44 +103,123 @@ function(qt_internal_add_qml_module target)
${ARGN}
)
- if (NOT arg_TARGET_PATH)
+ if(NOT arg_TARGET_PATH)
string(REPLACE "." "/" arg_TARGET_PATH ${arg_URI})
endif()
- if (NOT arg_OUTPUT_DIRECTORY)
+ if(NOT arg_OUTPUT_DIRECTORY)
set(arg_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}")
endif()
- if (NOT arg_INSTALL_DIRECTORY)
+ if(NOT arg_INSTALL_DIRECTORY)
set(arg_INSTALL_DIRECTORY "${INSTALL_QMLDIR}/${arg_TARGET_PATH}")
endif()
+ if(NOT arg_PLUGIN_TARGET)
+ set(arg_PLUGIN_TARGET ${target}plugin)
+ endif()
- qt_remove_args(plugin_args
- ARGS_TO_REMOVE
- ${qml_module_option_args}
- ${qml_module_single_args}
- ${qml_module_multi_args}
- OUTPUT_DIRECTORY
- INSTALL_DIRECTORY
- ALL_ARGS
- ${option_args}
- ${single_args}
- ${multi_args}
- ARGS
- ${ARGN}
- )
+ # TODO: Support for old keyword, remove once all repos no longer use CLASSNAME
+ 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. "
+ "Update call site to only use CLASS_NAME."
+ )
+ endif()
+ set(arg_CLASS_NAME "${arg_CLASSNAME}")
+ unset(arg_CLASSNAME)
+ endif()
- qt_internal_add_plugin(${target}
- TYPE qml_plugin
- OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
- INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY}
- ${plugin_args}
- )
+ set(plugin_args "")
+ if(NOT arg_PLUGIN_TARGET STREQUAL 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}
+ ${internal_single_args}
+ OUTPUT_DIRECTORY
+ INSTALL_DIRECTORY
+ ALL_ARGS
+ ${option_args}
+ ${single_args}
+ ${multi_args}
+ ARGS
+ ${ARGN}
+ )
+ qt_internal_add_module(${target} ${module_args})
+ 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
+ CLASSNAME
+ ALL_ARGS
+ ${option_args}
+ ${single_args}
+ ${multi_args}
+ ARGS
+ ${ARGN}
+ )
+ endif()
+
+ if(NOT arg_NO_CREATE_PLUGIN_TARGET)
+ # Create plugin target now so we can set internal things
+ list(APPEND plugin_args
+ TYPE qml_plugin
+ DEFAULT_IF FALSE
+ OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
+ INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY}
+ CLASS_NAME ${arg_CLASS_NAME}
+ )
+
+ qt_internal_add_plugin(${arg_PLUGIN_TARGET} ${plugin_args})
+
+ if(NOT arg_PLUGIN_TARGET STREQUAL target)
+ get_target_property(lib_type ${arg_PLUGIN_TARGET} TYPE)
+ if(lib_type STREQUAL "STATIC_LIBRARY")
+ # This is needed so that the dependency on the backing target
+ # is included in the plugin's find_package() support.
+ # The naming of backing targets and plugins don't typically
+ # follow the pattern of other plugins with regard to Private
+ # suffixes, so the dependency logic in qt_internal_add_plugin()
+ # doesn't find these. For non-static builds, the private
+ # dependency doesn't get exposed to find_package(), so we don't
+ # have to make the dependency known for that case.
+ set_property(TARGET ${arg_PLUGIN_TARGET} APPEND PROPERTY
+ _qt_target_deps "${INSTALL_CMAKE_NAMESPACE}${target}\;${PROJECT_VERSION}"
+ )
+ endif()
+ endif()
+
+ # FIXME: Some repos expect this to be set and use it to install other
+ # things relative to it. They should just specify the install
+ # location directly. Once the other repos have been updated to
+ # not rely on this, remove this property.
+ set_target_properties(${arg_PLUGIN_TARGET} PROPERTIES
+ QT_QML_MODULE_INSTALL_DIR ${arg_INSTALL_DIRECTORY}
+ )
+ endif()
+ # TODO: Check if we need arg_SOURCES in this condition
if (arg_SOURCES AND NOT arg_TYPEINFO)
set(arg_TYPEINFO "plugins.qmltypes")
endif()
- set(add_qml_module_args DO_NOT_CREATE_TARGET)
-
# Pass through options if given (these are present/absent, not true/false)
foreach(opt IN LISTS qml_module_option_args)
if(arg_${opt})
@@ -131,29 +227,92 @@ function(qt_internal_add_qml_module target)
endif()
endforeach()
- # Pass through single and multi-value args as provided
+ # 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()
-
- # Because qt_internal_add_qml_module does not propagate its SOURCES option to
- # qt6_add_qml_module, but only to qt_internal_add_plugin, we need a way to tell
- # qt6_add_qml_module if it should generate a dummy plugin cpp file. Otherwise we'd generate
- # a dummy plugin.cpp file twice and thus cause duplicate symbol issues.
- if (NOT arg_SOURCES)
- list(APPEND add_qml_module_args PURE_MODULE)
+ if(QT_LIBINFIX)
+ list(APPEND add_qml_module_args __QT_INTERNAL_QT_LIBINFIX "${QT_LIBINFIX}")
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}
- INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY}
RESOURCE_PREFIX "/qt-project.org/imports"
- RESOURCE_EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets"
+ OUTPUT_TARGETS resource_targets
)
+
+ if(resource_targets)
+ qt_install(TARGETS ${resource_targets}
+ EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets"
+ DESTINATION "${arg_INSTALL_DIRECTORY}"
+ )
+ qt_internal_record_rcc_object_files(${target} "${resource_targets}"
+ INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}"
+ )
+ endif()
+
+ # Empty list will not cause an installation error.
+ qt_install(
+ FILES $<TARGET_PROPERTY:${target},QT_QML_MODULE_FILES>
+ DESTINATION "${arg_INSTALL_DIRECTORY}"
+ )
+
+ if(NOT arg_NO_GENERATE_QMLTYPES)
+ qt_install(
+ FILES ${arg_OUTPUT_DIRECTORY}/$<TARGET_PROPERTY:${target},QT_QMLTYPES_FILENAME>
+ DESTINATION "${arg_INSTALL_DIRECTORY}"
+ )
+ endif()
+
+ if(NOT arg_NO_GENERATE_QMLDIR)
+ qt_install(
+ FILES ${arg_OUTPUT_DIRECTORY}/qmldir
+ DESTINATION "${arg_INSTALL_DIRECTORY}"
+ )
+ 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()
if(NOT QT_NO_INTERNAL_COMPATIBILITY_FUNCTIONS)