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
Pick-to: 6.1
Change-Id: I629ff63a9f8302c79694970f7b8e664a2b5d587b
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Craig Scott 2021-03-01 19:17:20 +11:00
parent ba9261a3a2
commit c42d558dc9
2 changed files with 106 additions and 174 deletions

View File

@ -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})
if (arg_SOURCES AND NOT arg_TYPEINFO)
set(arg_TYPEINFO "plugins.qmltypes")
endif()
if (arg_DESIGNER_SUPPORTED)
set(designer_supported_arg DESIGNER_SUPPORTED)
endif()
set(add_qml_module_args DO_NOT_CREATE_TARGET)
if (arg_SKIP_TYPE_REGISTRATION)
set(skip_registration_arg SKIP_TYPE_REGISTRATION)
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_PLUGIN_OPTIONAL)
set(plugin_optional_arg PLUGIN_OPTIONAL)
endif()
if (arg_GENERATE_QMLTYPES)
set(generate_qmltypes_arg GENERATE_QMLTYPES)
endif()
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)

View File

@ -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)
#
@ -95,7 +91,6 @@ function(qt6_add_qml_module target)
GENERATE_QMLTYPES
INSTALL_QMLTYPES
DESIGNER_SUPPORTED
DO_NOT_INSTALL_METADATA
SKIP_TYPE_REGISTRATION
PLUGIN_OPTIONAL
PURE_MODULE
@ -111,7 +106,7 @@ function(qt6_add_qml_module target)
TARGET_PATH
VERSION
OUTPUT_DIRECTORY
INSTALL_LOCATION
INSTALL_DIRECTORY
CLASSNAME
TYPEINFO
RESOURCE_EXPORT
@ -232,16 +227,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}
@ -250,22 +238,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)
@ -403,30 +391,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
@ -444,41 +435,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()
@ -596,6 +592,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
@ -613,7 +610,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()
@ -625,12 +622,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$")
@ -895,6 +891,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()