From 50eff429c5d4e6ac98418f2b8d2da01e80d858b5 Mon Sep 17 00:00:00 2001 From: Craig Scott Date: Mon, 1 Mar 2021 19:17:20 +1100 Subject: CMake: Fix argument handling in qt_internal_add_qml_module() and friends If OUTPUT_DIRECTORY is set, all the QML files, as well as the qmldir and the plugin should end up in that directory. We should not confuse that with the install directory, which is separate. For qt_internal_add_qml_module(), we can provide the defaults for both OUTPUT_DIRECTORY and INSTALL_DIRECTORY. For the latter, don't support a separate INSTALL_LOCATION keyword, only use INSTALL_DIRECTORY. With these changes, qtbase no longer has to contain qml-specific logic for these paths in QtPluginHelpers.cmake. Refactor the way arguments are collected and passed through to the internal call to qt6_add_qml_module(). This simplifies the code and also exposed that QML_FILES was not being identified as an allowed argument, TYPEINFO was the wrong type of argument and DO_NOT_INSTALL was not a valid argument (or at least was ignored). The qt_internal_add_module() function was also duplicating logic that was largely already implemented by qt6_add_qml_module(). Rework things a little to remove that duplication. Task-number: QTBUG-88763 Change-Id: I629ff63a9f8302c79694970f7b8e664a2b5d587b Reviewed-by: Fabian Kosmale (cherry picked from commit c42d558dc9ff89d452546412ee88a16ae1e324e4) Reviewed-by: Joerg Bornemann --- src/qml/Qt6QmlBuildInternals.cmake | 160 +++++++++++-------------------------- src/qml/Qt6QmlMacros.cmake | 120 ++++++++++++++-------------- 2 files changed, 106 insertions(+), 174 deletions(-) diff --git a/src/qml/Qt6QmlBuildInternals.cmake b/src/qml/Qt6QmlBuildInternals.cmake index c2d8259bc0..dc0204adac 100644 --- a/src/qml/Qt6QmlBuildInternals.cmake +++ b/src/qml/Qt6QmlBuildInternals.cmake @@ -4,27 +4,26 @@ include_guard(GLOBAL) -# This function creates a CMake target for qml modules. It will also make -# sure that if no C++ source are present, that qml files show up in the project -# in an IDE. Finally, it will also create a custom ${target}_qmltypes which -# can be used to generate the respective plugins.qmltypes file. +# 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: # -# URI: Module's uri. -# TARGET_PATH: Expected installation path for the Qml Module. Equivalent -# to the module's URI where '.' is replaced with '/'. Use this to override the -# default substitution pattern. -# VERSION: Version of the qml module -# SKIP_TYPE_REGISTRATION: All qml files are expected to be registered by the -# c++ plugin code. -# PLUGIN_OPTIONAL: Any plugins are optional +# - 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. # +# See qt_internal_add_plugin() and qt6_add_qml_module() for the full set of +# supported keywords. function(qt_internal_add_qml_module target) set(qml_module_optional_args GENERATE_QMLTYPES INSTALL_QMLTYPES DESIGNER_SUPPORTED - DO_NOT_INSTALL SKIP_TYPE_REGISTRATION PLUGIN_OPTIONAL ) @@ -34,12 +33,13 @@ function(qt_internal_add_qml_module target) TARGET_PATH VERSION CLASSNAME + TYPEINFO ) set(qml_module_multi_args + QML_FILES IMPORTS OPTIONAL_IMPORTS - TYPEINFO DEPENDENCIES PAST_MAJOR_VERSIONS ) @@ -49,70 +49,60 @@ function(qt_internal_add_qml_module target) "${__qt_add_plugin_single_args};${qml_module_single_args}" "${__qt_add_plugin_multi_args};${qml_module_multi_args}" ${ARGN}) - if (NOT arg_URI) - message(FATAL_ERROR "qt_add_qml_module called without specifying the module's uri. Please specify one using the URI parameter.") - endif() - - set(target_path ${arg_TARGET_PATH}) - - if (NOT arg_VERSION) - message(FATAL_ERROR "qt_add_qml_module called without specifying the module's import version. Please specify one using the VERSION parameter.") - endif() - if (NOT arg_TARGET_PATH) string(REPLACE "." "/" arg_TARGET_PATH ${arg_URI}) endif() + if (NOT arg_OUTPUT_DIRECTORY) + set(arg_OUTPUT_DIRECTORY "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}") + endif() + if (NOT arg_INSTALL_DIRECTORY) + set(arg_INSTALL_DIRECTORY "${INSTALL_QMLDIR}/${arg_TARGET_PATH}") + endif() qt_remove_args(plugin_args ARGS_TO_REMOVE - ${target} ${qml_module_optional_args} ${qml_module_single_args} ${qml_module_multi_args} + OUTPUT_DIRECTORY + INSTALL_DIRECTORY ALL_ARGS ${__qt_add_plugin_optional_args} - ${qml_module_optional_args} ${__qt_add_plugin_single_args} - ${qml_module_single_args} ${__qt_add_plugin_multi_args} + ${qml_module_optional_args} + ${qml_module_single_args} ${qml_module_multi_args} ARGS - ${ARGV} + ${ARGN} ) qt_internal_add_plugin(${target} - TYPE - qml_plugin - QML_TARGET_PATH - "${arg_TARGET_PATH}" + TYPE qml_plugin + OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} + INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY} ${plugin_args} ) - set(no_create_option DO_NOT_CREATE_TARGET) - - if (arg_CLASSNAME) - set(classname_arg CLASSNAME ${arg_CLASSNAME}) - endif() - - if (arg_DESIGNER_SUPPORTED) - set(designer_supported_arg DESIGNER_SUPPORTED) + if (arg_SOURCES AND NOT arg_TYPEINFO) + set(arg_TYPEINFO "plugins.qmltypes") endif() - if (arg_SKIP_TYPE_REGISTRATION) - set(skip_registration_arg SKIP_TYPE_REGISTRATION) - endif() + set(add_qml_module_args DO_NOT_CREATE_TARGET) - if (arg_PLUGIN_OPTIONAL) - set(plugin_optional_arg PLUGIN_OPTIONAL) - endif() - - if (arg_GENERATE_QMLTYPES) - set(generate_qmltypes_arg GENERATE_QMLTYPES) - endif() + # Pass through options if given (these are present/absent, not true/false) + foreach(opt IN LISTS qml_module_optional_args) + if(arg_${opt}) + list(APPEND add_qml_module_args ${opt}) + endif() + endforeach() - if (arg_INSTALL_QMLTYPES) - set(install_qmltypes_arg INSTALL_QMLTYPES) - endif() + # 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 @@ -120,72 +110,16 @@ function(qt_internal_add_qml_module target) # 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) - set(pure_qml_module "PURE_MODULE") - endif() - - qt_path_join(qml_module_install_dir ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/${arg_TARGET_PATH}") - - if (arg_SOURCES AND NOT arg_TYPEINFO) - set(arg_TYPEINFO "plugins.qmltypes") + list(APPEND add_qml_module_args PURE_MODULE) endif() qt6_add_qml_module(${target} - ${designer_supported_arg} - ${no_create_option} - ${skip_registration_arg} - ${plugin_optional_arg} - ${classname_arg} - ${generate_qmltypes_arg} - ${install_qmltypes_arg} - ${pure_qml_module} + ${add_qml_module_args} + OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY} + INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY} RESOURCE_PREFIX "/qt-project.org/imports" - TARGET_PATH ${arg_TARGET_PATH} - URI ${arg_URI} - VERSION ${arg_VERSION} - PAST_MAJOR_VERSIONS ${arg_PAST_MAJOR_VERSIONS} - QML_FILES ${arg_QML_FILES} - IMPORTS "${arg_IMPORTS}" - OPTIONAL_IMPORTS "${arg_OPTIONAL_IMPORTS}" - TYPEINFO "${arg_TYPEINFO}" - DO_NOT_INSTALL_METADATA - INSTALL_LOCATION "${qml_module_install_dir}" - DEPENDENCIES ${arg_DEPENDENCIES} RESOURCE_EXPORT "${INSTALL_CMAKE_NAMESPACE}${target}Targets" ) - - get_target_property(qmldir_file ${target} QT_QML_MODULE_QMLDIR_FILE) - get_target_property(plugin_types ${target} QT_QML_MODULE_PLUGIN_TYPES_FILE) - set(files_to_install) - if (EXISTS ${plugin_types}) - list(APPEND files_to_install ${plugin_types}) - qt_copy_or_install(FILES ${plugin_types} - DESTINATION "${qml_module_install_dir}" - ) - - if(QT_WILL_INSTALL) - # plugin.qmltypes when present should also be copied to the - # cmake binary dir when doing prefix builds - file(COPY ${plugin_types} - DESTINATION "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}" - ) - endif() - endif() - - list(APPEND files_to_install ${qmldir_file}) - if (QT_WILL_INSTALL) - install(FILES ${files_to_install} DESTINATION ${qml_module_install_dir}) - endif() - - set(copy_destination "${QT_BUILD_DIR}/${INSTALL_QMLDIR}/${arg_TARGET_PATH}") - foreach(file IN LISTS files_to_install) - get_filename_component(file_name "${file}" NAME) - add_custom_command(TARGET ${target} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${file}" - "${copy_destination}/${file_name}" - COMMENT "Copying ${file} to ${copy_destination}" - ) - endforeach() endfunction() if(NOT QT_NO_INTERNAL_COMPATIBILITY_FUNCTIONS) diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake index 65ebfd2477..6e8bfb7d37 100644 --- a/src/qml/Qt6QmlMacros.cmake +++ b/src/qml/Qt6QmlMacros.cmake @@ -29,11 +29,7 @@ set(__qt_qml_macros_module_base_dir "${CMAKE_CURRENT_LIST_DIR}") # ${CMAKE_CURRENT_BINARY_DIR}. This ensures the qmldir file is copied to the # right location. (OPTIONAL) # -# INSTALL_LOCATION: Intended installation directory for this module. If no -# value is supplied, the default installation path will be ${INSTALL_QMLDIR}. -# (OPTIONAL). -# -# DO_NOT_INSTALL_METADATA: When present, will not install the supporting files. +# INSTALL_DIRECTORY: Intended installation directory for this module. (OPTIONAL) # # SOURCES: List of C++ sources. (OPTIONAL) # @@ -93,7 +89,6 @@ function(qt6_add_qml_module target) GENERATE_QMLTYPES INSTALL_QMLTYPES DESIGNER_SUPPORTED - DO_NOT_INSTALL_METADATA SKIP_TYPE_REGISTRATION PLUGIN_OPTIONAL PURE_MODULE @@ -109,7 +104,7 @@ function(qt6_add_qml_module target) TARGET_PATH VERSION OUTPUT_DIRECTORY - INSTALL_LOCATION + INSTALL_DIRECTORY CLASSNAME TYPEINFO RESOURCE_EXPORT @@ -225,16 +220,9 @@ function(qt6_add_qml_module target) set(arg_RESOURCE_PREFIX "/org.qt-project/imports") endif() - set(should_install "TRUE") - if (NOT arg_INSTALL_LOCATION) - message(AUTHOR_WARNING "No Qml install location provided for target ${target}." - "Consider specifying the INSTALL_LOCATION option.") - set(should_install "FALSE") - endif() - - if (DEFINED QT_WILL_INSTALL AND NOT QT_WILL_INSTALL - AND NOT IS_ABSOLUTE "${arg_INSTALL_LOCATION}" AND QT_BUILD_DIR) - set(arg_INSTALL_LOCATION "${QT_BUILD_DIR}/${arg_INSTALL_LOCATION}") + set(should_install TRUE) + if (NOT arg_INSTALL_DIRECTORY) + set(should_install FALSE) endif() set_target_properties(${target} @@ -243,22 +231,22 @@ function(qt6_add_qml_module target) QT_QML_MODULE_URI "${arg_URI}" QT_RESOURCE_PREFIX "${arg_RESOURCE_PREFIX}/${arg_TARGET_PATH}" QT_QML_MODULE_VERSION "${arg_VERSION}" - QT_QML_MODULE_INSTALL_DIR "${arg_INSTALL_LOCATION}" + QT_QML_MODULE_INSTALL_DIR "${arg_INSTALL_DIRECTORY}" QT_QML_MODULE_RESOURCE_EXPORT "${arg_RESOURCE_EXPORT}" ) + if (arg_OUTPUT_DIRECTORY) + set_target_properties(${target} + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" + ARCHIVE_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" + QT_QML_MODULE_OUTPUT_DIR "${arg_OUTPUT_DIRECTORY}" + ) + endif() - if (NOT DO_NOT_CREATE_TARGET) - if (arg_OUTPUT_DIRECTORY) - set_target_properties(${target} - PROPERTIES - LIBRARY_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" - ARCHIVE_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}" - ) - elseif (should_install) - install(TARGETS ${target} - DESTINATION "${arg_INSTALL_LOCATION}" - ) - endif() + if (NOT DO_NOT_CREATE_TARGET AND should_install) + install(TARGETS ${target} + DESTINATION "${arg_INSTALL_DIRECTORY}" + ) endif() if (arg_OUTPUT_DIRECTORY) @@ -392,30 +380,33 @@ function(qt6_add_qml_module target) if (resource_targets AND arg_RESOURCE_EXPORT) install(TARGETS ${resource_targets} EXPORT "${arg_RESOURCE_EXPORT}" - DESTINATION "${arg_INSTALL_LOCATION}" + DESTINATION "${arg_INSTALL_DIRECTORY}" ) # When building a static Qt, we need to record information about the compiled resource # object files to embed them into .prl files. if(COMMAND qt_internal_record_rcc_object_files) qt_internal_record_rcc_object_files( - "${target}" "${resource_targets}" INSTALL_LOCATION "${arg_INSTALL_LOCATION}") + "${target}" "${resource_targets}" INSTALL_DIRECTORY "${arg_INSTALL_DIRECTORY}") endif() endif() - else() - # Copy QMLDIR file to build directory - add_custom_command(TARGET ${target} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${qmldir_file} - ${target_output_dir} - ) + endif() - # Install QMLDIR file - if (NOT DO_NOT_INSTALL_METADATA AND should_install) - install(FILES ${qmldir_file} - DESTINATION "${arg_INSTALL_LOCATION}" - ) - endif() + # Copy QMLDIR file to build directory. We want to do this even for static + # builds so that tools and IDEs can read it. + add_custom_command(TARGET ${target} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${qmldir_file} + ${target_output_dir}/qmldir + BYPRODUCTS + ${target_output_dir}/qmldir + ) + + # Install QMLDIR file + if (should_install) + install(FILES ${qmldir_file} + DESTINATION "${arg_INSTALL_DIRECTORY}" + ) endif() # Install and Copy plugin.qmltypes if exists @@ -433,41 +424,46 @@ function(qt6_add_qml_module target) _qt_internal_qmldir_defer_file(APPEND "${qmldir_file}" "typeinfo plugins.qmltypes\n") - if (NOT arg_DO_NOT_INSTALL_METADATA AND should_install) + if (should_install) install(FILES "${target_plugin_qmltypes}" - DESTINATION "${arg_INSTALL_LOCATION}" + DESTINATION "${arg_INSTALL_DIRECTORY}" ) endif() add_custom_command(TARGET ${target} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${target_plugin_qmltypes} - ${target_output_dir} + ${target_output_dir}/plugins.qmltypes + BYPRODUCTS + ${target_output_dir}/plugins.qmltypes ) endif() # Copy/Install type info file if (EXISTS ${arg_TYPEINFO}) - if (NOT arg_DO_NOT_INSTALL_METADATA AND should_install) + if (should_install) install(FILES "${arg_TYPEINFO}" - DESTINATION "${arg_INSTALL_LOCATION}" + DESTINATION "${arg_INSTALL_DIRECTORY}" ) endif() + get_filename_component(filename ${arg_TYPEINFO} NAME) add_custom_command(TARGET ${target} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${arg_TYPEINFO} - ${target_output_dir} + ${target_output_dir}/${filename} + BYPRODUCTS + ${target_output_dir}/${filename} ) endif() if (arg_INSTALL_QMLTYPES) set_target_properties(${target} PROPERTIES QT_QML_MODULE_INSTALL_QMLTYPES TRUE) - if (arg_INSTALL_LOCATION) + if (arg_INSTALL_DIRECTORY) get_target_property(qml_module_install_dir ${target} QT_QML_MODULE_INSTALL_DIR) if (NOT qml_module_install_dir) set_target_properties(${target} - PROPERTIES QT_QML_MODULE_INSTALL_DIR "${arg_INSTALL_LOCATION}" + PROPERTIES QT_QML_MODULE_INSTALL_DIR "${arg_INSTALL_DIRECTORY}" ) endif() endif() @@ -585,6 +581,7 @@ function(qt6_target_qml_files target) get_target_property(skip_type_registration ${target} QT_QML_MODULE_SKIP_TYPE_REGISTRATION) get_target_property(target_resource_export ${target} QT_QML_MODULE_RESOURCE_EXPORT) get_target_property(qml_module_install_dir ${target} QT_QML_MODULE_INSTALL_DIR) + get_target_property(qml_module_output_dir ${target} QT_QML_MODULE_OUTPUT_DIR) if(NOT qml_module_install_dir) message(AUTHOR_WARNING @@ -602,7 +599,7 @@ function(qt6_target_qml_files target) # object files to embed them into .prl files. if(COMMAND qt_internal_record_rcc_object_files) qt_internal_record_rcc_object_files( - "${target}" "${resource_targets}" INSTALL_LOCATION "${qml_module_install_dir}") + "${target}" "${resource_targets}" INSTALL_DIRECTORY "${qml_module_install_dir}") endif() endif() @@ -614,12 +611,11 @@ function(qt6_target_qml_files target) if (NOT "${qml_file_dir}" STREQUAL "") set(qml_file_dir "/${qml_file_dir}") endif() + if (qml_module_output_dir) + file(COPY "${qml_file}" DESTINATION "${qml_module_output_dir}${qml_file_dir}") + endif() if (qml_module_install_dir) - if (NOT QT_WILL_INSTALL) - file(COPY "${qml_file}" DESTINATION "${qml_module_install_dir}${qml_file_dir}") - else() - install(FILES "${qml_file}" DESTINATION "${qml_module_install_dir}${qml_file_dir}") - endif() + install(FILES "${qml_file}" DESTINATION "${qml_module_install_dir}${qml_file_dir}") endif() if (skip_type_registration AND qml_file MATCHES "\\.qml$") @@ -880,6 +876,8 @@ function(qt6_qml_type_registration target) COMMAND ${CMAKE_COMMAND} -E copy_if_different "${plugin_types_file}" "${qml_install_dir}/${qmltypes_output_name}" + BYPRODUCTS + "${qml_install_dir}/${qmltypes_output_name}" COMMENT "Copying ${plugin_types_file} to ${qml_install_dir}" ) endif() -- cgit v1.2.3