diff options
Diffstat (limited to 'src/qml/Qt6QmlMacros.cmake')
-rw-r--r-- | src/qml/Qt6QmlMacros.cmake | 256 |
1 files changed, 172 insertions, 84 deletions
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake index a75a8e794b..bda7b9b83a 100644 --- a/src/qml/Qt6QmlMacros.cmake +++ b/src/qml/Qt6QmlMacros.cmake @@ -412,19 +412,7 @@ function(qt6_add_qml_module target) endif() endforeach() - # Make the prefix conform to the following: - # - Starts with a "/" - # - Does not end with a "/" unless the prefix is exactly "/" - if(NOT arg_RESOURCE_PREFIX) - set(arg_RESOURCE_PREFIX "/") - endif() - if(NOT arg_RESOURCE_PREFIX MATCHES "^/") - string(PREPEND arg_RESOURCE_PREFIX "/") - endif() - if(arg_RESOURCE_PREFIX MATCHES [[(.+)/$]]) - set(arg_RESOURCE_PREFIX "${CMAKE_MATCH_1}") - endif() - + _qt_internal_canonicalize_resource_path("${arg_RESOURCE_PREFIX}" arg_RESOURCE_PREFIX) if(arg_NO_RESOURCE_TARGET_PATH) set(qt_qml_module_resource_prefix "${arg_RESOURCE_PREFIX}") else() @@ -532,21 +520,19 @@ function(qt6_add_qml_module target) PROPERTIES QT_RESOURCE_ALIAS "qmldir" ) - if(NOT ANDROID) - foreach(prefix IN LISTS prefixes) - set(resource_targets) - qt6_add_resources(${target} ${qmldir_resource_name} - FILES ${arg_OUTPUT_DIRECTORY}/qmldir - PREFIX "${prefix}" - OUTPUT_TARGETS resource_targets - ) - list(APPEND output_targets ${resource_targets}) - # If we are adding the same file twice, we need a different resource - # name for the second one. It has the same QT_RESOURCE_ALIAS but a - # different prefix, so we can't put it in the same resource. - string(APPEND qmldir_resource_name "_copy") - endforeach() - endif() + foreach(prefix IN LISTS prefixes) + set(resource_targets) + qt6_add_resources(${target} ${qmldir_resource_name} + FILES ${arg_OUTPUT_DIRECTORY}/qmldir + PREFIX "${prefix}" + OUTPUT_TARGETS resource_targets + ) + list(APPEND output_targets ${resource_targets}) + # If we are adding the same file twice, we need a different resource + # name for the second one. It has the same QT_RESOURCE_ALIAS but a + # different prefix, so we can't put it in the same resource. + string(APPEND qmldir_resource_name "_copy") + endforeach() endif() if(NOT arg_NO_PLUGIN AND NOT arg_NO_CREATE_PLUGIN_TARGET) @@ -634,6 +620,22 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS) endfunction() endif() +# Make the prefix conform to the following: +# - Starts with a "/" +# - Does not end with a "/" unless the prefix is exactly "/" +function(_qt_internal_canonicalize_resource_path path out_var) + if(NOT path) + set(path "/") + endif() + if(NOT path MATCHES "^/") + string(PREPEND path "/") + endif() + if(path MATCHES [[(.+)/$]]) + set(path "${CMAKE_MATCH_1}") + endif() + set(${out_var} "${path}" PARENT_SCOPE) +endfunction() + function(_qt_internal_get_escaped_uri uri out_var) string(REGEX REPLACE "[^A-Za-z0-9]" "_" escaped_uri "${uri}") set(${out_var} "${escaped_uri}" PARENT_SCOPE) @@ -658,6 +660,20 @@ macro(_qt_internal_genex_getoption var target property) set(${var} "$<BOOL:$<TARGET_PROPERTY:${target},${property}>>") endmacro() +function(_qt_internal_extend_qml_import_paths import_paths_var) + set(local_var ${${import_paths_var}}) + + # prepend extra import path which is a current module's build dir: we need + # this to ensure correct importing of QML modules when having a prefix-build + # with QLibraryInfo::path(QLibraryInfo::QmlImportsPath) pointing to the + # install location + if(QT_BUILDING_QT AND QT_WILL_INSTALL) + list(PREPEND local_var -I "${QT_BUILD_DIR}/${INSTALL_QMLDIR}") + endif() + + set(${import_paths_var} ${local_var} PARENT_SCOPE) +endfunction() + function(_qt_internal_target_enable_qmllint target) set(lint_target ${target}_qmllint) if(TARGET ${lint_target}) @@ -706,6 +722,8 @@ function(_qt_internal_target_enable_qmllint target) list(APPEND import_args -I "${QT_QML_OUTPUT_DIRECTORY}") endif() + _qt_internal_extend_qml_import_paths(import_args) + set(cmd ${QT_TOOL_COMMAND_WRAPPER_PATH} ${QT_CMAKE_EXPORT_NAMESPACE}::qmllint @@ -926,8 +944,12 @@ function(_qt_internal_target_generate_qmldir target) string(APPEND content "optional ") endif() - _qt_internal_get_qml_plugin_basename(plugin_basename ${plugin_target}) - string(APPEND content "plugin ${plugin_basename}\n") + get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH) + _qt_internal_get_qml_plugin_output_name(plugin_output_name ${plugin_target} + TARGET_PATH "${target_path}" + URI "${uri}" + ) + string(APPEND content "plugin ${plugin_output_name}\n") _qt_internal_qmldir_item(classname QT_QML_MODULE_CLASS_NAME) endif() @@ -1140,32 +1162,15 @@ function(qt6_add_qml_plugin target) ) endif() - if (ANDROID) - # Adjust Qml plugin names on Android similar to qml_plugin.prf which calls - # $$qt5LibraryTarget($$TARGET, "qml/$$TARGETPATH/"). - # Example plugin names: - # qtdeclarative - # TARGET_PATH: QtQml/Models - # file name: libqml_QtQml_Models_modelsplugin_arm64-v8a.so - # qtquickcontrols2 - # TARGET_PATH: QtQuick/Controls.2/Material - # file name: - # libqml_QtQuick_Controls.2_Material_qtquickcontrols2materialstyleplugin_arm64-v8a.so - if(NOT arg_TARGET_PATH AND TARGET "${arg_BACKING_TARGET}") - get_target_property(arg_TARGET_PATH ${arg_BACKING_TARGET} QT_QML_MODULE_TARGET_PATH) - endif() - if(arg_TARGET_PATH) - string(REPLACE "/" "_" android_plugin_name_infix_name "${arg_TARGET_PATH}") - else() - string(REPLACE "." "_" android_plugin_name_infix_name "${arg_URI}") - endif() - - _qt_internal_get_qml_plugin_basename(plugin_basename ${target}) - set(final_android_qml_plugin_name - "qml_${android_plugin_name_infix_name}_${plugin_basename}") + if(ANDROID) + _qt_internal_get_qml_plugin_output_name(plugin_output_name ${target} + BACKING_TARGET "${arg_BACKING_TARGET}" + TARGET_PATH "${arg_TARGET_PATH}" + URI "${arg_URI}" + ) set_target_properties(${target} PROPERTIES - LIBRARY_OUTPUT_NAME "${final_android_qml_plugin_name}" + LIBRARY_OUTPUT_NAME "${plugin_output_name}" ) qt6_android_apply_arch_suffix(${target}) endif() @@ -1319,7 +1324,8 @@ function(qt6_target_qml_sources target) ) endif() endif() - if(NOT arg_PREFIX MATCHES [[/$]]) + _qt_internal_canonicalize_resource_path("${arg_PREFIX}" arg_PREFIX) + if(NOT arg_PREFIX STREQUAL "/") string(APPEND arg_PREFIX "/") endif() @@ -1367,6 +1373,7 @@ function(qt6_target_qml_sources target) # The application binary directory is part of the default import path. list(APPEND import_paths -I "$<TARGET_PROPERTY:${target},BINARY_DIR>") endif() + _qt_internal_extend_qml_import_paths(import_paths) set(cachegen_args ${import_paths} "$<${have_types_file}:-i$<SEMICOLON>${types_file}>" @@ -1451,7 +1458,6 @@ function(qt6_target_qml_sources target) get_filename_component(file_absolute ${qml_file_src} ABSOLUTE) __qt_get_relative_resource_path_for_file(file_resource_path ${qml_file_src}) - set(qml_file_out ${output_dir}/${file_resource_path}) # For the tooling steps below, run the tools on the copied qml file in # the build directory, not the source directory. This is required @@ -1467,7 +1473,7 @@ function(qt6_target_qml_sources target) # The set of qml files to run qmllint on may be a subset of the # full set of files, so record these in a separate property. _qt_internal_target_enable_qmllint(${target}) - set_property(TARGET ${target} APPEND PROPERTY QT_QML_LINT_FILES ${qml_file_src}) + set_property(TARGET ${target} APPEND PROPERTY QT_QML_LINT_FILES ${file_absolute}) endif() # Add qml file's type to qmldir @@ -1476,17 +1482,16 @@ function(qt6_target_qml_sources target) get_source_file_property(qml_file_typename ${qml_file_src} QT_QML_SOURCE_TYPENAME) if (NOT qml_file_typename) get_filename_component(qml_file_ext ${qml_file_src} EXT) - if (NOT qml_file_ext STREQUAL ".js" AND NOT qml_file_ext STREQUAL ".mjs") - get_filename_component(qml_file_typename ${qml_file_src} NAME_WE) - endif() + get_filename_component(qml_file_typename ${qml_file_src} NAME_WE) endif() # Do not add qmldir entries for lowercase names. Those are not components. if (qml_file_typename AND qml_file_typename MATCHES "^[A-Z]") - if (qml_file_ext AND NOT qml_file_ext STREQUAL ".qml" AND NOT qml_file_ext STREQUAL ".ui.qml") + if (qml_file_ext AND NOT qml_file_ext STREQUAL ".qml" AND NOT qml_file_ext STREQUAL ".ui.qml" + AND NOT qml_file_ext STREQUAL ".js" AND NOT qml_file_ext STREQUAL ".mjs") message(AUTHOR_WARNING - "${qml_file_src} has a file extension different from .qml and .ui.qml. " - "This leads to unexpected component names." + "${qml_file_src} has a file extension different from .qml, .ui.qml, .js, " + "and .mjs. This leads to unexpected component names." ) endif() @@ -1805,6 +1810,11 @@ function(_qt_internal_qml_type_registration target) if (TARGET ${target}Private) list(APPEND cmd_args --private-includes) + else() + string(REGEX MATCH "Private$" privateSuffix ${target}) + if (privateSuffix) + list(APPEND cmd_args --private-includes) + endif() endif() get_target_property(target_metatypes_json_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE) @@ -1877,10 +1887,12 @@ function(_qt_internal_qml_type_registration target) endif() add_dependencies(all_qmltyperegistrations ${target}_qmltyperegistration) + # Both ${target} (via target_sources) and ${target}_qmltyperegistration (via add_custom_target + # DEPENDS option) depend on ${type_registration_cpp_file}. # The new Xcode build system requires a common target to drive the generation of files, # otherwise project configuration fails. - # Make the ${target}_qmltyperegistration the common target, by adding it as a dependency for - # ${target} itself. + # Make ${target} the common target, by adding it as a dependency for + # ${target}_qmltyperegistration. # The consequence is that the ${target}_qmllint target will now first build ${target} when using # the Xcode generator (mostly only relevant for projects using Qt for iOS). # See QTBUG-95763. @@ -1993,10 +2005,24 @@ but this file does not exist. Possible reasons include: ") endif() - # Find location of qml dir. - # TODO: qt.prf implies that there might be more than one qml import path to - # pass to qmlimportscanner. - set(qml_path "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_QML}") + # Find Qt provided QML import paths. + if("${_qt_additional_packages_prefix_paths}" STREQUAL "") + # We have one installation prefix for all Qt modules. Add the "<prefix>/qml" directory. + set(qml_import_paths "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_QML}") + else() + # We have multiple installation prefixes: one per Qt repository (conan). Add those that have + # a "qml" subdirectory. + set(qml_import_paths) + __qt_internal_prefix_paths_to_roots( + additional_root_paths "${_qt_additional_packages_prefix_paths}") + foreach(root IN ITEMS ${QT6_INSTALL_PREFIX} ${additional_root_paths}) + set(candidate "${root}/${QT6_INSTALL_QML}") + if(IS_DIRECTORY "${candidate}") + list(APPEND qml_import_paths "${candidate}") + endif() + endforeach() + endif() + # Small macro to avoid duplicating code in two different loops. macro(_qt6_QmlImportScanner_parse_entry) @@ -2020,21 +2046,35 @@ but this file does not exist. Possible reasons include: set(cmd_args -rootPath "${arg_PATH_TO_SCAN}" -cmake-output - -importPath "${qml_path}" ) get_target_property(qml_import_path ${target} QT_QML_IMPORT_PATH) - - if (qml_import_path) - list(APPEND cmd_args ${qml_import_path}) + if(qml_import_path) + list(APPEND qml_import_paths ${qml_import_path}) endif() # Facilitate self-import so we can find the qmldir file - list(APPEND cmd_args "${CMAKE_CURRENT_BINARY_DIR}") + get_target_property(module_out_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY) + if(module_out_dir) + list(APPEND qml_import_paths "${module_out_dir}") + endif() - if(NOT "${QT_QML_OUTPUT_DIRECTORY}" STREQUAL "" AND EXISTS "${QT_QML_OUTPUT_DIRECTORY}") - list(APPEND cmd_args "${QT_QML_OUTPUT_DIRECTORY}") + # Find qmldir files we copied to the build directory + if(NOT "${QT_QML_OUTPUT_DIRECTORY}" STREQUAL "") + if(EXISTS "${QT_QML_OUTPUT_DIRECTORY}") + list(APPEND qml_import_paths "${QT_QML_OUTPUT_DIRECTORY}") + endif() + else() + list(APPEND qml_import_paths "${CMAKE_CURRENT_BINARY_DIR}") endif() + # Construct the -importPath arguments. + set(import_path_arguments) + foreach(path IN LISTS qml_import_paths) + list(APPEND import_path_arguments -importPath ${path}) + endforeach() + + list(APPEND cmd_args ${import_path_arguments}) + # All of the module's .qml files will be listed in one of the generated # .qrc files, so there's no need to list the files individually. We provide # the .qrc files instead because they have the additional information for @@ -2255,17 +2295,65 @@ function(_qt_internal_add_static_qml_plugin_dependencies plugin_target backing_t endif() endfunction() -# The function returns the base output name of a qml plugin that will be used as library output -# name and in a qmldir file as the 'plugin <plugin_basename>' record. -function(_qt_internal_get_qml_plugin_basename out_var plugin_target) - set(plugin_basename) +# The function returns the output name of a qml plugin that will be used as library output +# name and in a qmldir file as the 'plugin <plugin_output_name>' record. +function(_qt_internal_get_qml_plugin_output_name out_var plugin_target) + cmake_parse_arguments(arg + "" + "BACKING_TARGET;TARGET_PATH;URI" + "" + ${ARGN} + ) + set(plugin_name) if(TARGET ${plugin_target}) - get_target_property(plugin_basename ${plugin_target} OUTPUT_NAME) + get_target_property(plugin_name ${plugin_target} OUTPUT_NAME) endif() - if(NOT plugin_basename) - set(plugin_basename "${plugin_target}") + if(NOT plugin_name) + set(plugin_name "${plugin_target}") endif() - set(${out_var} "${plugin_basename}" PARENT_SCOPE) + + if(ANDROID) + # In Android all plugins are stored in directly the /libs directory. This means that plugin + # names must be unique in scope of apk. To make this work we prepend uri-based prefix to + # each qml plugin in case if users don't use the manually written qmldir files. + get_target_property(no_generate_qmldir ${target} QT_QML_MODULE_NO_GENERATE_QMLDIR) + if(TARGET "${arg_BACKING_TARGET}") + get_target_property(no_generate_qmldir ${arg_BACKING_TARGET} + QT_QML_MODULE_NO_GENERATE_QMLDIR) + + # Adjust Qml plugin names on Android similar to qml_plugin.prf which calls + # $$qt5LibraryTarget($$TARGET, "qml/$$TARGETPATH/"). + # Example plugin names: + # qtdeclarative + # TARGET_PATH: QtQml/Models + # file name: libqml_QtQml_Models_modelsplugin_x86_64.so + # qtquickcontrols2 + # TARGET_PATH: QtQuick/Controls.2/Material + # file name: + # libqml_QtQuick_Controls.2_Material_qtquickcontrols2materialstyleplugin_x86_64.so + if(NOT arg_TARGET_PATH) + get_target_property(arg_TARGET_PATH ${arg_BACKING_TARGET} + QT_QML_MODULE_TARGET_PATH) + endif() + endif() + if(arg_TARGET_PATH) + string(REPLACE "/" "_" android_plugin_name_infix_name "${arg_TARGET_PATH}") + else() + string(REPLACE "." "_" android_plugin_name_infix_name "${arg_URI}") + endif() + + # If plugin supposed to use manually written qmldir file we don't prepend the uri-based + # prefix to the plugin output name. User should keep the file name of a QML plugin in + # qmldir the same as the name of plugin on a file system. Exception is the + # ABI-/platform-specific suffix that has the separate processing and should not be + # a part of plugin name in qmldir. + if(NOT no_generate_qmldir) + set(plugin_name + "qml_${android_plugin_name_infix_name}_${plugin_name}") + endif() + endif() + + set(${out_var} "${plugin_name}" PARENT_SCOPE) endfunction() # Used to add extra dependencies between ${target} and ${dep_target} qml plugins in a static |