Revision control

++ # Copyright (C) 2024 The Qt Company Ltd.
++ # SPDX-License-Identifier: BSD-3-Clause
++
++ # Returns the path to the template file from either user defined template directory, or
++ # Qt default template directory.
++ function(_qt_internal_android_get_template_path out_var target template_name)
++ if(template_name STREQUAL "")
++ message(FATAL_ERROR "Template name is empty."
++ " This is a Qt issue, please report a bug at https://bugreports.qt.io.")
++ endif()
++
++ _qt_internal_android_template_dir(template_directory)
++ get_filename_component(template_directory "${template_directory}" ABSOLUTE)
++
++ # The paths are ordered according to their priority, from highest to lowest.
++ set(possible_paths
++ "${template_directory}/${template_name}.in"
++ "${template_directory}/${template_name}"
++ )
++
++ get_target_property(android_target_type ${target} _qt_android_target_type)
++ if(android_target_type STREQUAL "APPLICATION")
++ _qt_internal_android_get_package_source_dir(user_template_directory ${target})
++ get_filename_component(user_template_directory "${user_template_directory}" ABSOLUTE)
++
++ # Add possible user manifest first so it takes precedence.
++ if(template_name STREQUAL "app/AndroidManifest.xml")
++ set(user_manifest "${user_template_directory}/AndroidManifest.xml")
++ if(EXISTS "${user_manifest}")
++ list(PREPEND possible_paths "${user_manifest}")
++ endif()
++ endif()
++
++ # Add user template with the higher priority
++ list(PREPEND possible_paths
++ "${user_template_directory}/${template_name}.in"
++ "${user_template_directory}/${template_name}"
++ )
++
++ # When the user’s package source dir is already the module's subdir
++ # (i.e app/ or dynamic_feature/), then don't add yet another app subdir.
++ if(user_template_directory)
++ get_filename_component(user_template_dir_basename "${user_template_directory}" NAME)
++ _qt_internal_re_escape(user_template_dir_basename_re "${user_template_dir_basename}")
++ if(template_name MATCHES "^${user_template_dir_basename_re}/(.+)$")
++ set(trailing_name "${CMAKE_MATCH_1}")
++ list(INSERT possible_paths 1 "${user_template_directory}/${trailing_name}.in")
++ list(INSERT possible_paths 2 "${user_template_directory}/${trailing_name}")
++ endif()
++ endif()
++ endif()
++
++ set(template_path "")
++ foreach(possible_path IN LISTS possible_paths)
++ if(EXISTS "${possible_path}")
++ set(template_path "${possible_path}")
++ break()
++ endif()
++ endforeach()
++
++ if(template_path STREQUAL "")
++ message(FATAL_ERROR "'${template_name}' is not found."
++ " This is a Qt issue, please report a bug at https://bugreports.qt.io.")
++ endif()
++
++ set(${out_var} "${template_path}" PARENT_SCOPE)
++ endfunction()
++
++ # Reads template into out_var and adds it to CMAKE_CONFIGURE_DEPENDS for reconfigure-on-edit.
++ function(_qt_internal_android_read_template out_var template)
++ file(READ "${template}" content)
++ _qt_internal_append_cmake_configure_depends("${template}")
++ set(${out_var} "${content}" PARENT_SCOPE)
++ endfunction()
++
++ # Generates the settings.gradle file for the target. Writes the result to the target android build
++ # directory.
++ function(_qt_internal_android_generate_bundle_settings_gradle target)
++ set(settings_gradle_filename "settings.gradle")
++ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
++ set(settings_gradle_file "${android_build_dir}/${settings_gradle_filename}")
++
++ # Skip generating the file if it's already provided by user.
++ get_target_property(deployment_files ${target} _qt_android_deployment_files)
++ if("${settings_gradle_file}" IN_LIST deployment_files)
++ return()
++ endif()
++
++ _qt_internal_android_get_template_path(template_file ${target} "${settings_gradle_filename}")
++
++ _qt_internal_android_get_gradle_property(ROOT_PROJECT_NAME ${target}
++ QT_ANDROID_APP_NAME "${target}")
++
++ set(target_dynamic_features "$<TARGET_PROPERTY:${target},_qt_android_dynamic_features>")
++ set(include_prefix "include(\":")
++ set(include_suffix "\")")
++ set(include_glue "${include_suffix}\n${include_prefix}")
++ string(JOIN "" SUBPROJECTS
++ "$<$<BOOL:${target_dynamic_features}>:"
++ "${include_prefix}"
++ "$<JOIN:${target_dynamic_features},${include_glue}>"
++ "${include_suffix}"
++ ">"
++ )
++
++ _qt_internal_android_read_template(settings_gradle_content "${template_file}")
++ _qt_internal_configure_file(GENERATE OUTPUT ${settings_gradle_file}
++ CONTENT "${settings_gradle_content}")
++ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files
++ "${settings_gradle_file}")
++ endfunction()
++
++ # Generates the source sets for the target.
++ function(_qt_internal_android_get_gradle_source_sets out_var target)
++ set(known_types java aidl res resources renderscript assets jniLibs)
++ set(source_set "")
++ set(indent "\n ")
++ foreach(type IN LISTS known_types)
++ set(source_dirs
++ "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},_qt_android_gradle_${type}_source_dirs>>")
++ string(JOIN "" source_set
++ "${source_set}"
++ "$<$<BOOL:${source_dirs}>:"
++ "${indent}${type}.srcDirs = ['$<JOIN:${source_dirs},'$<COMMA> '>']"
++ ">"
++ )
++ endforeach()
++
++ set(manifest
++ "$<TARGET_PROPERTY:${target},_qt_android_manifest>")
++ string(JOIN "" source_set
++ "${source_set}"
++ "$<$<BOOL:${manifest}>:"
++ "${indent}manifest.srcFile '${manifest}'"
++ ">"
++ )
++ string(REGEX REPLACE "^${indent}" "" source_set "${source_set}")
++ set(${out_var} "${source_set}" PARENT_SCOPE)
++ endfunction()
++
++ # Generates the gradle dependency list for the target.
++ function(_qt_internal_android_get_gradle_dependencies out_var target)
++ # Use dependencies from file tree by default
++ set(known_dependencies
++ "implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])")
++ foreach(dep_type implementation api)
++ string(JOIN "\n " dep_prefix
++ "\n //noinspection GradleDependency"
++ "${dep_type} "
++ )
++ set(dep_postfix "")
++ set(dep_type_property "_qt_android_gradle_${dep_type}_dependencies")
++ set(dep_property "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},${dep_type_property}>>")
++ string(JOIN "" known_dependencies
++ "${known_dependencies}"
++ "$<$<BOOL:${dep_property}>:"
++ "${dep_prefix}$<JOIN:${dep_property},${dep_postfix}${dep_prefix}>${dep_postfix}"
++ ">"
++ )
++ endforeach()
++ set(${out_var} "${known_dependencies}" PARENT_SCOPE)
++ endfunction()
++
++ # Sets the default values of the gradle properties for the Android executable target.
++ function(_qt_internal_set_android_application_gradle_defaults target)
++ _qt_internal_android_java_dir(android_java_dir)
++
++ set(target_dynamic_features "$<TARGET_PROPERTY:${target},_qt_android_dynamic_features>")
++ string(JOIN "" implementation_dependencies
++ "$<$<BOOL:${target_dynamic_features}>:libs.play.feature.delivery>"
++ )
++ # Default dependency versions are defined in the version catalog.
++ list(APPEND implementation_dependencies "libs.androidx.core")
++
++ set_target_properties(${target} PROPERTIES
++ _qt_android_gradle_java_source_dirs "${android_java_dir}/src;src;java"
++ _qt_android_gradle_aidl_source_dirs "${android_java_dir}/src;src;aidl"
++ _qt_android_gradle_res_source_dirs "${android_java_dir}/res;res"
++ _qt_android_gradle_resources_source_dirs "resources"
++ _qt_android_gradle_renderscript_source_dirs "src"
++ _qt_android_gradle_assets_source_dirs "assets"
++ _qt_android_gradle_jniLibs_source_dirs "libs"
++ _qt_android_manifest "AndroidManifest.xml"
++ _qt_android_gradle_implementation_dependencies "${implementation_dependencies}"
++ )
++ endfunction()
++
++ # Generates the build.gradle file for the target. Writes the result to the target app deployment
++ # directory.
++ function(_qt_internal_android_generate_target_build_gradle target)
++ cmake_parse_arguments(PARSE_ARGV 1 arg "" "DEPLOYMENT_DIR" "")
++
++ if(NOT arg_DEPLOYMENT_DIR)
++ message(FATAL_ERROR "DEPLOYMENT_DIR is not specified.")
++ endif()
++
++ set(build_gradle_filename "build.gradle")
++ set(out_file "${arg_DEPLOYMENT_DIR}/${build_gradle_filename}")
++
++ # Skip generating the file if it's already provided by user.
++ get_target_property(deployment_files ${target} _qt_android_deployment_files)
++ if("${out_file}" IN_LIST deployment_files)
++ return()
++ endif()
++
++ _qt_internal_android_get_gradle_property(PACKAGE_NAME ${target}
++ QT_ANDROID_PACKAGE_NAME "org.qtproject.example.$<MAKE_C_IDENTIFIER:${target}>")
++
++ _qt_internal_android_get_target_sdk_build_tools_revision(ANDROID_BUILD_TOOLS_VERSION
++ ${target})
++
++ get_target_property(ANDROID_COMPILE_SDK_VERSION ${target} QT_ANDROID_COMPILE_SDK_VERSION)
++ if(NOT ANDROID_COMPILE_SDK_VERSION)
++ _qt_internal_detect_latest_android_platform(ANDROID_COMPILE_SDK_VERSION)
++ if(NOT ANDROID_COMPILE_SDK_VERSION)
++ message(FATAL_ERROR "Unable to detect the android platform in ${ANDROID_SDK_ROOT}. "
++ "Please check your Android SDK installation.")
++ endif()
++ endif()
++
++ set(ANDROID_COMPILE_SDK_RELEASE "")
++ set(ANDROID_COMPILE_SDK_MINOR "0")
++ if(ANDROID_COMPILE_SDK_VERSION MATCHES "^android-([0-9]+)\\.([0-9]+)$")
++ set(ANDROID_COMPILE_SDK_RELEASE "${CMAKE_MATCH_1}")
++ set(ANDROID_COMPILE_SDK_MINOR "${CMAKE_MATCH_2}")
++ elseif(ANDROID_COMPILE_SDK_VERSION MATCHES "^android-([0-9]+)$")
++ set(ANDROID_COMPILE_SDK_RELEASE "${CMAKE_MATCH_1}")
++ elseif(ANDROID_COMPILE_SDK_VERSION MATCHES "^([0-9]+)\\.([0-9]+)$")
++ set(ANDROID_COMPILE_SDK_RELEASE "${CMAKE_MATCH_1}")
++ set(ANDROID_COMPILE_SDK_MINOR "${CMAKE_MATCH_2}")
++ elseif(ANDROID_COMPILE_SDK_VERSION MATCHES "^([0-9]+)$")
++ set(ANDROID_COMPILE_SDK_RELEASE "${CMAKE_MATCH_1}")
++ else()
++ message(FATAL_ERROR "Unsupported android platform format '${ANDROID_COMPILE_SDK_VERSION}'.")
++ endif()
++
++ _qt_internal_android_get_gradle_source_sets(SOURCE_SETS ${target})
++ _qt_internal_android_get_gradle_dependencies(GRADLE_DEPENDENCIES ${target})
++
++ _qt_internal_android_get_gradle_property(min_sdk_version ${target}
++ QT_ANDROID_MIN_SDK_VERSION "28")
++
++ _qt_internal_android_get_gradle_property(target_sdk_version ${target}
++ QT_ANDROID_TARGET_SDK_VERSION "37")
++
++ get_target_property(android_target_type ${target} _qt_android_target_type)
++
++ set(default_config_lines
++ "minSdk = ${min_sdk_version}"
++ "targetSdk = ${target_sdk_version}"
++ )
++ # AGP rejects abiFilters inside a dynamic-feature module; it inherits the
++ # set from the application module. Only emit the ndk block for the app.
++ if(android_target_type STREQUAL "APPLICATION")
++ set(target_abis "$<TARGET_PROPERTY:${target},_qt_android_abis>")
++ set(target_abi_list
++ "$<JOIN:${target_abis};${CMAKE_ANDROID_ARCH_ABI},'$<COMMA> '>")
++ list(APPEND default_config_lines
++ "ndk {"
++ " abiFilters += ['${target_abi_list}']"
++ "}"
++ )
++ endif()
++ string(JOIN "\n " DEFAULT_CONFIG_VALUES ${default_config_lines})
++
++ set(target_dynamic_features "$<TARGET_PROPERTY:${target},_qt_android_dynamic_features>")
++ set(include_prefix "\":")
++ set(include_suffix "\"")
++ set(include_glue "${include_suffix}$<COMMA>${include_prefix}")
++ string(APPEND ANDROID_DEPLOYMENT_EXTRAS
++ "$<$<BOOL:${target_dynamic_features}>:dynamicFeatures = ["
++ "${include_prefix}"
++ "$<JOIN:${target_dynamic_features},${include_glue}>"
++ "${include_suffix}]"
++ ">"
++ )
++
++ if(android_target_type STREQUAL "APPLICATION")
++ _qt_internal_android_get_manifest_property(APP_PACKAGE_NAME ${target}
++ QT_ANDROID_PACKAGE_NAME "org.qtproject.example.$<MAKE_C_IDENTIFIER:${target}>")
++ _qt_internal_android_get_manifest_property(APP_NAME ${target}
++ QT_ANDROID_APP_NAME "${target}")
++ _qt_internal_android_get_manifest_property(APP_VERSION_CODE ${target}
++ QT_ANDROID_VERSION_CODE "1")
++ _qt_internal_android_get_manifest_property(APP_VERSION_NAME ${target}
++ QT_ANDROID_VERSION_NAME "1")
++ _qt_internal_android_get_manifest_property(APP_LIB_NAME ${target}
++ OUTPUT_NAME "${target}")
++ set(APP_ARGUMENTS "${QT_ANDROID_APPLICATION_ARGUMENTS}")
++
++ # Legacy packaging
++ if(QT_FEATURE_sanitize_address)
++ message(STATUS "QT_FEATURE_sanitize_address is set, using legacy packaging by default.")
++ set(legacy_packaging_value "true")
++ else()
++ set(legacy_packaging_value
++ "$<IF:$<BOOL:$<TARGET_PROPERTY:${target},QT_ANDROID_LEGACY_PACKAGING>>,true,false>")
++ endif()
++ string(APPEND ANDROID_DEPLOYMENT_EXTRAS
++ "\n packaging {"
++ "\n jniLibs {"
++ "\n useLegacyPackaging = ${legacy_packaging_value}"
++ "\n }"
++ "\n }"
++ )
++
++ set(template_subdir "app")
++ elseif(android_target_type STREQUAL "DYNAMIC_FEATURE")
++ set(template_subdir "dynamic_feature")
++ else()
++ message(FATAL_ERROR "Unsupported target type for android bundle deployment ${target}")
++ endif()
++
++ _qt_internal_android_get_template_path(template_file ${target}
++ "${template_subdir}/${build_gradle_filename}")
++ _qt_internal_android_read_template(build_gradle_content "${template_file}")
++ _qt_internal_configure_file(GENERATE
++ OUTPUT "${out_file}"
++ CONTENT "${build_gradle_content}"
++ )
++ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${out_file}")
++ endfunction()
++
++ # Registers a library copy target as a dependency of ${target}_deploy_libraries.
++ function(_qt_internal_android_add_deploy_libraries_dependency target dep_target)
++ if(NOT TARGET ${dep_target})
++ return()
++ endif()
++ if(NOT TARGET ${target}_deploy_libraries)
++ add_custom_target(${target}_deploy_libraries)
++ endif()
++ add_dependencies(${target}_deploy_libraries ${dep_target})
++ endfunction()
++
++ # Records deploy artifact files for gradle's file-level dependency tracking.
++ function(_qt_internal_android_register_deploy_files target)
++ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deploy_files "${ARGN}")
++ endfunction()
++
++ # Lists the files a secondary ABI deploys, matching what the copy steps actually write.
++ function(_qt_internal_android_get_abi_deploy_files out_var target abi)
++ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
++ set(libs_abi_dir "${deployment_dir}/libs/${abi}")
++
++ # The app binary is always deployed.
++ set(deploy_files "${libs_abi_dir}/lib${target}_${abi}.so")
++
++ # libc++ and the extra libs are skipped when Qt libs aren't deployed
++ get_target_property(no_deploy_qt_libs ${target} QT_ANDROID_NO_DEPLOY_QT_LIBS)
++ if(NOT no_deploy_qt_libs)
++ list(APPEND deploy_files "${libs_abi_dir}/libc++_shared.so")
++
++ get_target_property(extra_libs ${target} QT_ANDROID_EXTRA_LIBS)
++ if(extra_libs)
++ foreach(lib IN LISTS extra_libs)
++ get_filename_component(lib_name "${lib}" NAME)
++ if(lib_name)
++ list(APPEND deploy_files "${libs_abi_dir}/${lib_name}")
++ endif()
++ endforeach()
++ endif()
++ endif()
++
++ set(${out_var} "${deploy_files}" PARENT_SCOPE)
++ endfunction()
++
++ # Prepares the artifacts for the gradle build of the target.
++ function(_qt_internal_android_prepare_gradle_build target)
++ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
++ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
++
++ # Gradle files and resources are ABI-independent, only the main ABI packages them.
++ if(NOT QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT)
++ _qt_internal_android_copy_gradle_files(${target} "${android_build_dir}")
++ _qt_internal_android_copy_target_package_sources(${target} "${deployment_dir}")
++ _qt_internal_android_copy_android_resources(${target} "${deployment_dir}")
++ endif()
++
++ _qt_internal_android_copy_app_binary(${target} "${deployment_dir}")
++ _qt_internal_android_copy_stdlib(${target} "${deployment_dir}")
++ _qt_internal_android_copy_extra_plugins(${target} "${deployment_dir}")
++ # TODO: don't call qmlimportscanner again at all for multi-ABI external builds.
++ _qt_internal_android_parse_qmlimportscanner_output(${target})
++ _qt_internal_android_collect_qt_modules_and_plugins(${target})
++ # Needs to run after all dependencies are collected
++ _qt_internal_android_include_openssl_if_needed(${target})
++ _qt_internal_android_copy_extra_libs(${target} "${deployment_dir}")
++ _qt_internal_android_copy_non_qt_linked_libs(${target} "${deployment_dir}")
++ _qt_internal_android_copy_qt_dependencies(${target} "${deployment_dir}")
++ _qt_internal_android_copy_qml_plugins(${target} "${deployment_dir}")
++
++ # Multi-ABI external builds need to only care about the libraries deployment.
++ if(QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT)
++ add_custom_target(qt_internal_${target}_copy_apk_dependencies
++ DEPENDS ${target}_deploy_libraries)
++ add_custom_target(${target}_make_apk)
++ add_custom_target(${target}_make_aab)
++ return()
++ endif()
++
++ _qt_internal_android_create_rcc_bundle(${target} "${deployment_dir}")
++ _qt_internal_android_generate_libs_xml(${target} "${deployment_dir}")
++
++ _qt_internal_android_generate_bundle_gradle_properties(${target})
++ _qt_internal_android_generate_bundle_settings_gradle(${target})
++ _qt_internal_android_generate_bundle_local_properties(${target})
++ _qt_internal_android_generate_target_build_gradle(${target} DEPLOYMENT_DIR "${deployment_dir}")
++ _qt_internal_android_generate_target_android_manifest(${target}
++ DEPLOYMENT_DIR "${deployment_dir}")
++
++
++ _qt_internal_android_add_gradle_build(${target} apk)
++ _qt_internal_android_add_gradle_build(${target} aab)
++
++ _qt_internal_android_setup_qml_imports_reconfigure_trigger(${target})
++
++ # Make global apk, aab, and aar targets depend on the respective targets.
++ _qt_internal_android_add_global_package_dependencies(${target})
++ _qt_internal_create_global_apk_all_target_if_needed()
++ endfunction()
++
++ # Returns the path to the output package file for the target.
++ function(_qt_internal_android_get_output_package_name out_var target type)
++ _qt_internal_android_package_path(package_build_dir ${target} ${type})
++ _qt_internal_android_get_deployment_type_option(deployment_type_suffix "release" "debug")
++ if(type STREQUAL "apk")
++ _qt_internal_android_get_deployment_type_option(extra_suffix "-unsigned" "")
++ else()
++ set(extra_suffix "")
++ endif()
++
++ set(output_dir "${package_build_dir}/${deployment_type_suffix}")
++ set(${out_var} "${output_dir}/app-${deployment_type_suffix}${extra_suffix}.${type}"
++ PARENT_SCOPE)
++ endfunction()
++
++ # Adds the modern gradle build targets.
++ # These targets use the settings.gradle based build directory structure.
++ function(_qt_internal_android_add_gradle_build target type)
++ if(type STREQUAL "aab")
++ _qt_internal_android_get_deployment_type_option(android_deployment_type_option
++ "bundleRelease" "bundleDebug")
++ else()
++ _qt_internal_android_get_deployment_type_option(android_deployment_type_option
++ "assembleRelease" "assembleDebug")
++ endif()
++
++ _qt_internal_android_gradlew_name(gradlew_file_name)
++ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
++ set(gradlew "${android_build_dir}/${gradlew_file_name}")
++
++ _qt_internal_android_get_output_package_name(package_build_file_path ${target} ${type})
++
++ set(extra_deps "")
++ foreach(dep ${target}_copy_feature_names
++ ${target}_copy_apk_dependencies
++ ${target}_copy_gradle_files
++ ${target}_copy_android_res_files
++ ${target}_copy_package_sources
++ ${target}_build_qml_bundle
++ ${target}_update_libs_xml)
++ if(TARGET ${dep})
++ list(APPEND extra_deps ${dep})
++ endif()
++ endforeach()
++
++ set(gradle_scripts "$<TARGET_PROPERTY:${target},_qt_android_deployment_files>")
++ # File-level deps so gradle re-runs on deploy artifact changes.
++ set(deploy_files "$<TARGET_PROPERTY:${target},_qt_android_deploy_files>")
++ add_custom_command(OUTPUT "${package_build_file_path}"
++ COMMAND "${gradlew}" ${android_deployment_type_option}
++ DEPENDS
++ ${target}
++ ${gradle_scripts}
++ ${deploy_files}
++ ${target}_deploy_libraries
++ ${extra_deps}
++ WORKING_DIRECTORY "${android_build_dir}"
++ VERBATIM
++ )
++
++ set(package_file_path "${android_build_dir}/${target}.${type}")
++ _qt_internal_android_sign_package(signed_package_path ${target} ${type}
++ "${package_build_file_path}")
++ if(NOT signed_package_path)
++ add_custom_command(OUTPUT "${package_file_path}"
++ COMMAND ${CMAKE_COMMAND} -E copy_if_different
++ "${package_build_file_path}" "${package_file_path}"
++ DEPENDS "${package_build_file_path}"
++ VERBATIM
++ )
++ endif()
++
++ _qt_internal_android_gradle_cleanup_commands(gradle_cleanup_commands
++ "${gradlew}" "${android_build_dir}" "${target}")
++
++ if(gradle_cleanup_commands)
++ add_custom_target(${target}_${type}_cleanup
++ ${gradle_cleanup_commands}
++ DEPENDS "${package_file_path}"
++ WORKING_DIRECTORY "${android_build_dir}"
++ VERBATIM
++ )
++ add_custom_target(${target}_make_${type})
++ add_dependencies(${target}_make_${type} ${target}_${type}_cleanup)
++ else()
++ add_custom_target(${target}_make_${type} DEPENDS "${package_file_path}")
++ endif()
++ endfunction()
++
++ function(_qt_internal_android_sign_package out_file target type unsigned_build_file_path)
++ string(TOUPPER "${type}" type_upper)
++ if(type STREQUAL "aar" OR NOT QT_ANDROID_SIGN_${type_upper})
++ set(${out_file} "" PARENT_SCOPE)
++ return()
++ endif()
++
++ if(type STREQUAL "aab")
++ find_program(jarsigner NAMES jarsigner)
++ if(NOT jarsigner)
++ message(FATAL_ERROR "jarsigner is not found. Please install"
++ " a JDK version to sign '${target}'.")
++ endif()
++
++ set(program ${jarsigner})
++ set(extra_args "")
++ elseif(type STREQUAL "apk")
++ _qt_internal_android_get_target_sdk_build_tools_revision(build_tools_version ${target})
++ if(CMAKE_HOST_WIN32)
++ set(suffix ".bat")
++ else()
++ set(suffix "")
++ endif()
++ set(build_tools_base_path "${ANDROID_SDK_ROOT}/build-tools/${build_tools_version}")
++ set(program "${build_tools_base_path}/apksigner${suffix}")
++ set(extra_args "-DZIPALIGN_PATH=${build_tools_base_path}/zipalign${suffix}")
++ endif()
++
++ _qt_internal_android_get_output_package_name(package_build_file_path ${target} ${type})
++
++ _qt_internal_android_package_path(package_build_dir ${target} ${type})
++ _qt_internal_android_get_deployment_type_option(deployment_type_suffix
++ "release" "debug")
++ set(base_output_path "${package_build_dir}/${deployment_type_suffix}")
++ set(package_build_file_path_signed
++ "${base_output_path}/app-${deployment_type_suffix}-signed.${type}")
++
++ set(package_file_path "${android_build_dir}/${target}.${type}")
++
++ set(sign_package_script "${_qt_6_config_cmake_dir}/QtAndroidSignPackage.cmake")
++ add_custom_command(OUTPUT "${package_file_path}"
++ BYPRODUCTS "${package_build_file_path_signed}"
++ COMMAND
++ ${CMAKE_COMMAND} "-DPROGRAM=${program}" "-DUNSIGNED_PACKAGE=${package_build_file_path}"
++ "-DSIGNED_PACKAGE=${package_build_file_path_signed}" ${extra_args}
++ -P "${sign_package_script}"
++ COMMAND
++ ${CMAKE_COMMAND} -E copy_if_different
++ "${package_build_file_path_signed}" "${package_file_path}"
++ DEPENDS
++ ${unsigned_build_file_path}
++ ${sign_package_script}
++ WORKING_DIRECTORY
++ "${android_build_dir}"
++ VERBATIM
++ )
++
++ set(${out_file} "${package_file_path}" PARENT_SCOPE)
++ endfunction()
++
++ # Returns the path to the android executable package either apk or aab.
++ function(_qt_internal_android_package_path out_var target type)
++ set(supported_package_types apk aab)
++ if(NOT type IN_LIST supported_package_types)
++ message(FATAL_ERROR "Invalid package type, supported types: ${supported_package_types}")
++ endif()
++
++ # aab packages are located in the bundle directory
++ if(type STREQUAL "aab")
++ set(type "bundle")
++ endif()
++
++ _qt_internal_android_get_target_deployment_dir(deployment_dir ${target})
++
++ set(${out_var} "${deployment_dir}/build/outputs/${type}" PARENT_SCOPE)
++ endfunction()
++
++ # Returns the path to the gradle build directory.
++ function(_qt_internal_android_gradle_template_dir out_var)
++ if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD)
++ set(${out_var} "${QtBase_SOURCE_DIR}/src/3rdparty/gradle" PARENT_SCOPE)
++ else()
++ set(${out_var} "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/3rdparty/gradle" PARENT_SCOPE)
++ endif()
++ endfunction()
++
++ # Returns the path to the Android templates resource directory.
++ function(_qt_internal_android_template_res_dir out_var)
++ if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD)
++ set(android_templates_root "${QtBase_SOURCE_DIR}/src/android")
++ else()
++ set(android_templates_root
++ "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/android")
++ endif()
++
++ set(template_res_dir "${android_templates_root}/templates/res")
++ if(NOT EXISTS "${template_res_dir}")
++ message(FATAL_ERROR "Android template resource directory '${template_res_dir}' not found."
++ " Please check your Qt installation.")
++ endif()
++ set(${out_var} "${template_res_dir}" PARENT_SCOPE)
++ endfunction()
++
++ # Returns the path to the android java dir.
++ function(_qt_internal_android_java_dir out_var)
++ if(PROJECT_NAME STREQUAL "QtBase" OR QT_SUPERBUILD)
++ set(${out_var} "${QtBase_SOURCE_DIR}/src/android/java" PARENT_SCOPE)
++ else()
++ set(${out_var} "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_DATA}/src/android/java" PARENT_SCOPE)
++ endif()
++ endfunction()
++
++ # Sanitize the target name to be used in file names
++ function(_qt_internal_android_sanitize_target_name out_var target)
++ string(REPLACE "::" "_" sanitized "${target}")
++ set(${out_var} "${sanitized}" PARENT_SCOPE)
++ endfunction()
++
++ # Returns (and creates) the per-directory staging dir for Android build tracking artifacts.
++ function(_qt_internal_android_staging_dir out_var)
++ set(dir "${CMAKE_CURRENT_BINARY_DIR}/.qt/android")
++ file(MAKE_DIRECTORY "${dir}")
++ set(${out_var} "${dir}" PARENT_SCOPE)
++ endfunction()
++
++ # Returns the platform-spefic name of the gradlew script.
++ function(_qt_internal_android_gradlew_name out_var)
++ if(CMAKE_HOST_WIN32)
++ set(gradlew_file_name "gradlew.bat")
++ else()
++ set(gradlew_file_name "gradlew")
++ endif()
++
++ set(${out_var} "${gradlew_file_name}" PARENT_SCOPE)
++ endfunction()
++
++ # Return Gradle clean command if QT_ANDROID_POST_BUILD_GRADLE_CLEANUP is set
++ function(_qt_internal_android_gradle_cleanup_commands out_var gradlew working_dir target)
++ if(NOT QT_ANDROID_POST_BUILD_GRADLE_CLEANUP)
++ set(${out_var} "" PARENT_SCOPE)
++ return()
++ endif()
++
++ set(commands "")
++ list(APPEND commands
++ COMMAND ${CMAKE_COMMAND} -E echo "Running gradle clean for ${target} in ${working_dir}..."
++ COMMAND "${gradlew}" -p "${working_dir}" clean
++ )
++ set(${out_var} "${commands}" PARENT_SCOPE)
++ endfunction()
++
++ # Returns the generator expression for the gradle_property value. Defaults to the default_value
++ # argument.
++ function(_qt_internal_android_get_gradle_property out_var target target_property default_value)
++ set(target_property_genex "$<GENEX_EVAL:$<TARGET_PROPERTY:${target},${target_property}>>")
++ string(JOIN "" result
++ "$<IF:$<BOOL:${target_property_genex}>,"
++ "${target_property_genex},"
++ "${default_value}"
++ ">"
++ )
++ set(${out_var} "${result}" PARENT_SCOPE)
++ endfunction()
++
++ # Constucts generator expression that returns either target property or the default value
++ function(_qt_internal_android_get_manifest_property out_var target property default)
++ set(target_property "$<TARGET_PROPERTY:${target},${property}>")
++ string(JOIN "" out_genex
++ "$<IF:$<BOOL:${target_property}>,"
++ "${target_property},"
++ "${default}"
++ ">"
++ )
++
++ set(${out_var} "${out_genex}" PARENT_SCOPE)
++ endfunction()
++
++ # Converts androiddeployqt-style placeholders to CMake placeholders.
++ function(_qt_internal_android_convert_manifest_placeholders manifest_content out_placeholders)
++ set(updated "${manifest_content}")
++ if(updated MATCHES "%%INSERT_")
++ string(REPLACE "-- %%INSERT_VERSION_CODE%% --" "@APP_VERSION_CODE@"
++ updated "${updated}")
++ string(REPLACE "-- %%INSERT_VERSION_NAME%% --" "@APP_VERSION_NAME@"
++ updated "${updated}")
++ string(REPLACE "-- %%INSERT_APP_NAME%% --" "@APP_NAME@"
++ updated "${updated}")
++ string(REPLACE "-- %%INSERT_APP_LIB_NAME%% --" "@APP_LIB_NAME@"
++ updated "${updated}")
++ string(REPLACE "-- %%INSERT_APP_ARGUMENTS%% --" "@APP_ARGUMENTS@"
++ updated "${updated}")
++ string(REPLACE "-- %%INSERT_APP_ICON%% --" "@APP_ICON@"
++ updated "${updated}")
++ string(REPLACE "android:icon=\"@APP_ICON@\"" "@APP_ICON@"
++ updated "${updated}")
++ string(REPLACE "<!-- %%INSERT_PERMISSIONS -->" "@APP_PERMISSIONS@"
++ updated "${updated}")
++ string(REPLACE "<!-- %%INSERT_FEATURES -->" "@APP_FEATURES@"
++ updated "${updated}")
++ string(REGEX REPLACE "package=\"[^\"]*\"" "package=\"@APP_PACKAGE_NAME@\""
++ updated "${updated}")
++ endif()
++
++ set(${out_placeholders} "${updated}" PARENT_SCOPE)
++ endfunction()
++
++ # Generates the target AndroidManifest.xml
++ function(_qt_internal_android_generate_target_android_manifest target)
++ cmake_parse_arguments(PARSE_ARGV 1 arg "" "DEPLOYMENT_DIR" "")
++
++ if(NOT arg_DEPLOYMENT_DIR)
++ message(FATAL_ERROR "DEPLOYMENT_DIR is not specified.")
++ endif()
++
++ set(android_manifest_filename "AndroidManifest.xml")
++ set(out_file "${arg_DEPLOYMENT_DIR}/${android_manifest_filename}")
++
++ # Skip generating the file if it's already provided by user.
++ get_target_property(deployment_files ${target} _qt_android_deployment_files)
++ if("${out_file}" IN_LIST deployment_files)
++ return()
++ endif()
++
++ _qt_internal_android_get_template_path(template_file ${target}
++ "app/${android_manifest_filename}")
++
++ _qt_internal_android_get_manifest_property(APP_PACKAGE_NAME ${target}
++ QT_ANDROID_PACKAGE_NAME "org.qtproject.example.$<MAKE_C_IDENTIFIER:${target}>")
++ _qt_internal_android_get_manifest_property(APP_NAME ${target}
++ QT_ANDROID_APP_NAME "${target}")
++ _qt_internal_android_get_manifest_property(APP_VERSION_CODE ${target}
++ QT_ANDROID_VERSION_CODE "1")
++ _qt_internal_android_get_manifest_property(APP_VERSION_NAME ${target}
++ QT_ANDROID_VERSION_NAME "1")
++ _qt_internal_android_get_manifest_property(APP_LIB_NAME ${target} OUTPUT_NAME "${target}")
++
++ # For application icon we substitute the whole attribute definition, but not only value
++ # otherwise it leads to the Manifest processing issue.
++ set(target_property "$<TARGET_PROPERTY:${target},QT_ANDROID_APP_ICON>")
++ string(JOIN "" APP_ICON
++ "$<$<BOOL:${target_property}>:"
++ "android:icon=\"${target_property}\""
++ ">"
++ )
++
++ _qt_internal_android_read_template(manifest_content "${template_file}")
++ _qt_internal_android_convert_manifest_placeholders("${manifest_content}" manifest_content)
++ string(REPLACE ">" "$<ANGLE-R>" manifest_content "${manifest_content}")
++ string(REPLACE ";" "$<SEMICOLON>" manifest_content "${manifest_content}")
++ string(REPLACE "," "$<COMMA>" manifest_content "${manifest_content}")
++
++ _qt_internal_android_convert_permissions(APP_PERMISSIONS ${target} XML)
++
++ set(feature_prefix "\n <uses-feature android:name=\"")
++ set(feature_suffix " \" android:required=\"false\" /$<ANGLE-R>")
++ set(feature_property "$<TARGET_PROPERTY:${target},QT_ANDROID_FEATURES>")
++ string(JOIN "" APP_FEATURES
++ "$<$<BOOL:${feature_property}>:"
++ "${feature_prefix}"
++ "$<JOIN:${feature_property},${feature_suffix},${feature_prefix}>"
++ "${feature_suffix}"
++ ">"
++ )
++
++ set(APP_ARGUMENTS "${QT_ANDROID_APPLICATION_ARGUMENTS}")
++
++ _qt_internal_configure_file(GENERATE OUTPUT "${out_file}"
++ CONTENT "${manifest_content}")
++
++ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${out_file}")
++ endfunction()
++
++ # Generates the top-level gradle.properties in the android-build directory
++ # The file contains the information about the versions of the android build
++ # tools, the list of supported ABIs.
++ function(_qt_internal_android_generate_bundle_gradle_properties target)
++ set(EXTRA_PROPERTIES "")
++
++ set(gradle_properties_file_name "gradle.properties")
++ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
++ set(out_file "${android_build_dir}/${gradle_properties_file_name}")
++
++ # Skip generating the file if it's already provided by user.
++ get_target_property(deployment_files ${target} _qt_android_deployment_files)
++ if("${out_file}" IN_LIST deployment_files)
++ return()
++ endif()
++
++ _qt_internal_android_get_template_path(template_file ${target} "${gradle_properties_file_name}")
++ _qt_internal_configure_file(CONFIGURE
++ OUTPUT "${out_file}"
++ INPUT "${template_file}"
++ )
++ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${out_file}")
++ endfunction()
++
++ # Generates the local.properties for gradle builds. Contains the path to the
++ # Android SDK root.
++ function(_qt_internal_android_generate_bundle_local_properties target)
++ _qt_internal_android_get_target_android_build_dir(android_build_dir ${target})
++ set(out_file "${android_build_dir}/local.properties")
++
++ # Skip generating the file if it's already provided by user.
++ get_target_property(deployment_files ${target} _qt_android_deployment_files)
++ if("${out_file}" IN_LIST deployment_files)
++ return()
++ endif()
++
++ file(TO_CMAKE_PATH "${ANDROID_SDK_ROOT}" ANDROID_SDK_ROOT_NATIVE)
++ _qt_internal_configure_file(CONFIGURE OUTPUT "${out_file}"
++ CONTENT "sdk.dir=${ANDROID_SDK_ROOT_NATIVE}\n")
++ endfunction()
++
++ # Copies the customized Android package sources to the Android build directory
++ function(_qt_internal_android_copy_target_package_sources target deployment_dir)
++ _qt_internal_android_get_package_source_dir(package_source_dir ${target})
++
++ if(NOT package_source_dir)
++ set_property(TARGET ${target} PROPERTY _qt_android_package_res_outputs "")
++ return()
++ endif()
++ get_filename_component(package_source_dir "${package_source_dir}" ABSOLUTE)
++
++ # Collect deployment files from use-defined package source directory
++ file(GLOB_RECURSE package_files
++ LIST_DIRECTORIES false
++ CONFIGURE_DEPENDS
++ RELATIVE "${package_source_dir}"
++ "${package_source_dir}/*"
++ )
++
++ # Skip manifest copying because it will be handled and generated under
++ # _qt_internal_android_generate_target_android_manifest().
++ list(REMOVE_ITEM package_files "AndroidManifest.xml")
++
++ foreach(provider_paths IN ITEMS "res/xml/qtprovider_paths.xml"
++ "res/xml-v30/qtprovider_paths.xml")
++ if("${provider_paths}" IN_LIST package_files)
++ message(WARNING
++ "${package_source_dir}/${provider_paths} in the package "
++ "source directory of ${target} is being excluded. Qt now bundles "
++ "its own copy of it under the Android sources directory, and a "
++ "duplicate would fail the Gradle build. Remove this file from your "
++ "package source directory to silence this warning.")
++ list(REMOVE_ITEM package_files "${provider_paths}")
++ endif()
++ endforeach()
++
++ # Save res outputs so default resources templates know to not override them.
++ set(package_res_files "${package_files}")
++ list(FILTER package_res_files INCLUDE REGEX "^res/")
++ list(TRANSFORM package_res_files PREPEND "${deployment_dir}/"
++ OUTPUT_VARIABLE package_res_outputs)
++ set_property(TARGET ${target} PROPERTY _qt_android_package_res_outputs "${package_res_outputs}")
++
++ # Do not copy files that we treat as CMake templates, having '.in' extention.
++ #
++ # TODO: If it ever will be an issue we may exclude only templates that are
++ # known by our build system.
++ list(FILTER package_files EXCLUDE REGEX ".+\\.in$")
++
++ list(TRANSFORM package_files PREPEND "${deployment_dir}/" OUTPUT_VARIABLE out_package_files)
++ list(TRANSFORM package_files PREPEND "${package_source_dir}/" OUTPUT_VARIABLE in_package_files)
++
++ if(in_package_files)
++ # Copy files individually so that the processed AndroidManifest.xml isn't overwritten
++ # by the unprocessed user-provided copy.
++ set(copy_commands "")
++ set(seen_dirs "")
++ foreach(rel_file IN LISTS package_files)
++ get_filename_component(dst_dir "${deployment_dir}/${rel_file}" DIRECTORY)
++ if(NOT dst_dir IN_LIST seen_dirs)
++ list(APPEND seen_dirs "${dst_dir}")
++ list(APPEND copy_commands
++ COMMAND "${CMAKE_COMMAND}" -E make_directory "${dst_dir}")
++ endif()
++ list(APPEND copy_commands
++ COMMAND "${CMAKE_COMMAND}" -E copy_if_different
++ "${package_source_dir}/${rel_file}"
++ "${deployment_dir}/${rel_file}")
++ endforeach()
++ else()
++ # We actually have nothing to deploy.
++ return()
++ endif()
++
++ add_custom_command(OUTPUT ${out_package_files}
++ ${copy_commands}
++ DEPENDS
++ ${in_package_files}
++ VERBATIM
++ )
++
++ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files ${out_package_files})
++
++ # This is used by _qt_internal_android_generate_target_android_manifest()
++ # to ensure it's run after the package sources are copied.
++ add_custom_target(${target}_copy_package_sources DEPENDS ${out_package_files})
++ endfunction()
++
++ # Copies gradle scripts to a build directory.
++ function(_qt_internal_android_copy_gradle_files target output_directory)
++ _qt_internal_android_gradlew_name(gradlew_file_name)
++ _qt_internal_android_gradle_template_dir(gradle_template_dir)
++ _qt_internal_android_template_dir(android_template_dir)
++
++ set(gradlew_src "${gradle_template_dir}/${gradlew_file_name}")
++ set(gradlew_dst "${output_directory}/${gradlew_file_name}")
++
++ set(wrapper_srcs "")
++ set(wrapper_dsts "")
++ set(wrapper_src_dir "${gradle_template_dir}/gradle/wrapper")
++ set(wrapper_dst_dir "${output_directory}/gradle/wrapper")
++ set(wrapper_filenames "gradle-wrapper.jar" "gradle-wrapper.properties")
++ foreach(file IN LISTS wrapper_filenames)
++ list(APPEND wrapper_srcs "${wrapper_src_dir}/${file}")
++ list(APPEND wrapper_dsts "${wrapper_dst_dir}/${file}")
++ endforeach()
++
++ set(libs_versions_filename "libs.versions.toml")
++ set(libs_versions_src "${android_template_dir}/gradle/${libs_versions_filename}")
++ set(libs_versions_dst "${output_directory}/gradle/${libs_versions_filename}")
++
++ add_custom_command(
++ OUTPUT "${gradlew_dst}" ${wrapper_dsts} "${libs_versions_dst}"
++ COMMAND ${CMAKE_COMMAND} -E copy_if_different "${gradlew_src}" "${gradlew_dst}"
++ COMMAND ${CMAKE_COMMAND} -E make_directory "${wrapper_dst_dir}"
++ COMMAND ${CMAKE_COMMAND} -E copy_if_different ${wrapper_srcs} "${wrapper_dst_dir}"
++ COMMAND ${CMAKE_COMMAND} -E copy_if_different "${libs_versions_src}" "${libs_versions_dst}"
++ DEPENDS "${gradlew_src}" ${wrapper_srcs} "${libs_versions_src}"
++ VERBATIM
++ )
++ add_custom_target(${target}_copy_gradle_files
++ DEPENDS "${gradlew_dst}" ${wrapper_dsts} "${libs_versions_dst}"
++ )
++ _qt_internal_android_register_deploy_files(${target}
++ "${gradlew_dst}" ${wrapper_dsts} "${libs_versions_dst}")
++ endfunction()
++
++ # Copies default Android resource templates to a build directory.
++ function(_qt_internal_android_copy_android_resources target deployment_dir)
++ _qt_internal_android_template_res_dir(template_res_dir)
++
++ set(res_dir_dst "${deployment_dir}/res")
++ file(GLOB_RECURSE template_res_files_rel RELATIVE "${template_res_dir}" CONFIGURE_DEPENDS
++ LIST_DIRECTORIES false
++ "${template_res_dir}/*"
++ )
++ if(NOT template_res_files_rel)
++ return()
++ endif()
++
++ list(TRANSFORM template_res_files_rel PREPEND "${template_res_dir}/"
++ OUTPUT_VARIABLE template_res_files)
++ list(TRANSFORM template_res_files_rel PREPEND "${res_dir_dst}/"
++ OUTPUT_VARIABLE dst_res_files)
++
++ # Exclude res outputs that are copied by QT_ANDROID_PACKAGE_SOURCE_DIR.
++ get_target_property(package_res_outputs ${target} _qt_android_package_res_outputs)
++ if(package_res_outputs)
++ list(REMOVE_ITEM dst_res_files ${package_res_outputs})
++ endif()
++
++ add_custom_command(OUTPUT ${dst_res_files}
++ COMMAND ${CMAKE_COMMAND} -E copy_directory "${template_res_dir}" "${res_dir_dst}"
++ DEPENDS
++ "${template_res_dir}"
++ ${template_res_files}
++ COMMENT "Copying Android app res templates for ${target}"
++ VERBATIM
++ )
++
++ add_custom_target(${target}_copy_android_res_files DEPENDS ${dst_res_files})
++ _qt_internal_android_register_deploy_files(${target} ${dst_res_files})
++ endfunction()
++
++ # Copies the libc++ shared runtime to a build directory.
++ function(_qt_internal_android_copy_stdlib target deployment_dir)
++ get_target_property(no_deploy_qt_libs ${target} QT_ANDROID_NO_DEPLOY_QT_LIBS)
++ if(no_deploy_qt_libs)
++ return()
++ endif()
++
++ set(stdlib_triple_by_abi_arm64_v8a "aarch64-linux-android")
++ set(stdlib_triple_by_abi_armeabi_v7a "arm-linux-androideabi")
++ set(stdlib_triple_by_abi_x86 "i686-linux-android")
++ set(stdlib_triple_by_abi_x86_64 "x86_64-linux-android")
++ string(REPLACE "-" "_" cmake_abi "${CMAKE_ANDROID_ARCH_ABI}")
++ set(stdlib_triple "${stdlib_triple_by_abi_${cmake_abi}}")
++ if(NOT stdlib_triple)
++ message(FATAL_ERROR "Unsupported ABI '${CMAKE_ANDROID_ARCH_ABI}' for libc++_shared.")
++ endif()
++
++ set(stdlib_src "${CMAKE_SYSROOT}/usr/lib/${stdlib_triple}/libc++_shared.so")
++ if(NOT EXISTS "${stdlib_src}")
++ message(FATAL_ERROR
++ "The libc++ runtime library was not found at '${stdlib_src}'. "
++ "Check your Android NDK installation.")
++ endif()
++
++ set(stdlib_dst_dir "${deployment_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}")
++ set(stdlib_dst "${stdlib_dst_dir}/libc++_shared.so")
++ _qt_internal_android_append_to_libs_xml_section(${target} qt_libs "${stdlib_dst}")
++
++ _qt_internal_android_get_deploy_command(deploy_stdlib_cmd "${stdlib_src}" "${stdlib_dst}")
++ add_custom_command(OUTPUT "${stdlib_dst}"
++ COMMAND ${CMAKE_COMMAND} -E make_directory "${stdlib_dst_dir}"
++ COMMAND ${deploy_stdlib_cmd}
++ DEPENDS "${stdlib_src}"
++ COMMENT "Copying libc++_shared for ${target}"
++ VERBATIM
++ )
++
++ add_custom_target(${target}_copy_stdlib DEPENDS "${stdlib_dst}")
++ _qt_internal_android_add_deploy_libraries_dependency(${target} ${target}_copy_stdlib)
++ _qt_internal_android_register_deploy_files(${target} "${stdlib_dst}")
++ endfunction()
++
++ # Copies additional native libraries requested via QT_ANDROID_EXTRA_LIBS.
++ function(_qt_internal_android_copy_extra_libs target deployment_dir)
++ get_target_property(no_deploy_qt_libs ${target} QT_ANDROID_NO_DEPLOY_QT_LIBS)
++ if(no_deploy_qt_libs)
++ return()
++ endif()
++
++ if(TARGET ${target}_copy_extra_libs)
++ return()
++ endif()
++
++ get_target_property(extra_libs ${target} QT_ANDROID_EXTRA_LIBS)
++ if(NOT extra_libs)
++ return()
++ endif()
++
++ set(extra_libs_dst_dir "${deployment_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}")
++ set(copy_outputs "")
++ set(copy_depends "")
++ set(copy_commands
++ COMMAND ${CMAKE_COMMAND} -E make_directory "${extra_libs_dst_dir}"
++ )
++
++ foreach(lib IN LISTS extra_libs)
++ if(lib MATCHES "^\\$<")
++ message(FATAL_ERROR
++ "QT_ANDROID_EXTRA_LIBS entry '${lib}' for ${target} is a generator expression. "
++ "This copy implementation uses add_custom_command(OUTPUT) and requires absolute "
++ "paths so outputs can be tracked reliably.")
++ endif()
++
++ file(TO_CMAKE_PATH "${lib}" lib_path)
++ if(NOT IS_ABSOLUTE "${lib_path}")
++ message(FATAL_ERROR
++ "QT_ANDROID_EXTRA_LIBS entry '${lib}' for ${target} must be an absolute path.")
++ endif()
++
++ get_filename_component(lib_name "${lib_path}" NAME)
++ if(NOT lib_name MATCHES "\\.so$")
++ message(FATAL_ERROR
++ "QT_ANDROID_EXTRA_LIBS entry '${lib}' for ${target} must be a shared library.")
++ endif()
++
++ _qt_internal_android_append_to_libs_xml_section(${target} extra_libs "${lib_name}")
++ set(dst "${extra_libs_dst_dir}/${lib_name}")
++ list(APPEND copy_outputs "${dst}")
++ list(APPEND copy_depends "${lib_path}")
++ list(APPEND copy_commands
++ COMMAND ${CMAKE_COMMAND} -E copy_if_different "${lib_path}" "${dst}"
++ )
++ endforeach()
++
++ add_custom_command(
++ OUTPUT ${copy_outputs}
++ ${copy_commands}
++ DEPENDS ${copy_depends}
++ COMMENT "Copying extra native libraries for ${target}"
++ VERBATIM
++ )
++
++ add_custom_target(${target}_copy_extra_libs DEPENDS ${copy_outputs})
++ _qt_internal_android_add_deploy_libraries_dependency(${target} ${target}_copy_extra_libs)
++ _qt_internal_android_register_deploy_files(${target} ${copy_outputs})
++ endfunction()
++
++ # Copies additional plugins requested via QT_ANDROID_EXTRA_PLUGINS.
++ function(_qt_internal_android_copy_extra_plugins target deployment_dir)
++ get_target_property(no_deploy_qt_libs ${target} QT_ANDROID_NO_DEPLOY_QT_LIBS)
++ if(no_deploy_qt_libs)
++ return()
++ endif()
++
++ if(TARGET ${target}_copy_extra_plugins)
++ return()
++ endif()
++
++ get_target_property(extra_plugins ${target} QT_ANDROID_EXTRA_PLUGINS)
++ if(NOT extra_plugins)
++ return()
++ endif()
++
++ set(extra_plugins_dst_dir "${deployment_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}")
++
++ _qt_internal_collect_buildsystem_targets(buildsystem_library_targets
++ "${CMAKE_SOURCE_DIR}" INCLUDE SHARED_LIBRARY MODULE_LIBRARY)
++
++ set(copy_commands "")
++ set(copy_depends "")
++ set(extra_plugin_targets "")
++ foreach(plugin_dir IN LISTS extra_plugins)
++ if(NOT plugin_dir)
++ continue()
++ endif()
++
++ if("${plugin_dir}" MATCHES "^[$]<")
++ # Genex paths: defer to copy_directory which evaluates at build time.
++ list(APPEND copy_commands COMMAND ${CMAKE_COMMAND} -E copy_directory
++ "${plugin_dir}" "${extra_plugins_dst_dir}")
++ if("${plugin_dir}" MATCHES "^\\$<TARGET_FILE_DIR:([^>]+)>$")
++ if(TARGET "${CMAKE_MATCH_1}")
++ list(APPEND extra_plugin_targets "${CMAKE_MATCH_1}")
++ else()
++ message(WARNING "QT_ANDROID_EXTRA_PLUGINS entry '${plugin_dir}' for ${target} "
++ "skipped invalid auto-discovered dependency ${CMAKE_MATCH_1}")
++ endif()
++ else()
++ message(WARNING "QT_ANDROID_EXTRA_PLUGINS entry '${plugin_dir}' for ${target} "
++ "skipped dependencies auto-discovery due to unsupported genex.")
++ endif()
++ continue()
++ endif()
++
++ file(TO_CMAKE_PATH "${plugin_dir}" plugin_path)
++ if(NOT IS_ABSOLUTE "${plugin_path}")
++ message(WARNING "QT_ANDROID_EXTRA_PLUGINS entry '${plugin_dir}' for ${target} "
++ "is not an absolute path.")
++ endif()
++
++ # Copy at build time to also pick up plugins generated into the directory;
++ # the glob only feeds DEPENDS.
++ list(APPEND copy_commands COMMAND ${CMAKE_COMMAND} -E copy_directory
++ "${plugin_path}" "${extra_plugins_dst_dir}")
++ file(GLOB_RECURSE plugin_files CONFIGURE_DEPENDS LIST_DIRECTORIES false
++ "${plugin_path}/*")
++ list(APPEND copy_depends ${plugin_files})
++
++ # Find targets with LIBRARY_OUTPUT_DIRECTORY resolving to extra plugin directory.
++ get_filename_component(plugin_path_abs "${plugin_path}" ABSOLUTE)
++ foreach(library_target IN LISTS buildsystem_library_targets)
++ get_target_property(library_outdir "${library_target}" LIBRARY_OUTPUT_DIRECTORY)
++ if(NOT library_outdir)
++ continue()
++ endif()
++ if(NOT IS_ABSOLUTE "${library_outdir}")
++ get_target_property(library_binary_dir "${library_target}" BINARY_DIR)
++ set(library_outdir "${library_binary_dir}/${library_outdir}")
++ endif()
++ get_filename_component(library_outdir "${library_outdir}" ABSOLUTE)
++ if(library_outdir STREQUAL plugin_path_abs)
++ list(APPEND extra_plugin_targets "${library_target}")
++ endif()
++ endforeach()
++ endforeach()
++
++ list(REMOVE_DUPLICATES extra_plugin_targets)
++
++ if(NOT copy_commands)
++ return()
++ endif()
++
++ _qt_internal_android_sanitize_target_name(sanitized_target ${target})
++ _qt_internal_android_staging_dir(android_staging_dir)
++ set(stamp "${android_staging_dir}/${sanitized_target}_copy_extra_plugins.stamp")
++ add_custom_command(OUTPUT "${stamp}"
++ COMMAND ${CMAKE_COMMAND} -E make_directory "${extra_plugins_dst_dir}"
++ ${copy_commands}
++ COMMAND ${CMAKE_COMMAND} -E touch "${stamp}"
++ DEPENDS ${copy_depends} ${target} ${extra_plugin_targets}
++ COMMENT "Copying extra plugins for ${target}"
++ VERBATIM
++ )
++ add_custom_target(${target}_copy_extra_plugins DEPENDS "${stamp}")
++ _qt_internal_android_add_deploy_libraries_dependency(${target} ${target}_copy_extra_plugins)
++ _qt_internal_android_register_deploy_files(${target} "${stamp}")
++ endfunction()
++
++ # Copy the QML plugin targets discovered by qmlimportscanner.
++ function(_qt_internal_android_copy_qml_plugins target deployment_dir)
++ get_target_property(no_deploy_qt_libs ${target} QT_ANDROID_NO_DEPLOY_QT_LIBS)
++ if(no_deploy_qt_libs)
++ return()
++ endif()
++
++ if(TARGET ${target}_copy_qml_plugins)
++ return()
++ endif()
++
++ get_target_property(plugin_targets ${target} _qt_android_qml_plugins)
++ if(NOT plugin_targets)
++ return()
++ endif()
++
++ set(libs_abi_dir "${deployment_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}")
++ set(copy_commands "")
++ set(copy_depends "")
++
++ foreach(plugin_target IN LISTS plugin_targets)
++ if(NOT TARGET "${plugin_target}")
++ continue()
++ endif()
++ set(plugin_filename "$<TARGET_FILE_NAME:${plugin_target}>")
++ _qt_internal_android_append_to_libs_xml_section(${target} qt_libs "${plugin_filename}")
++ _qt_internal_android_get_deploy_command(deploy_cmd
++ "$<TARGET_FILE:${plugin_target}>" "${libs_abi_dir}/${plugin_filename}")
++ list(APPEND copy_commands COMMAND ${deploy_cmd})
++ list(APPEND copy_depends "${plugin_target}")
++ endforeach()
++
++ if(NOT copy_commands)
++ return()
++ endif()
++
++ _qt_internal_android_sanitize_target_name(sanitized_target ${target})
++ _qt_internal_android_staging_dir(android_staging_dir)
++ set(stamp "${android_staging_dir}/${sanitized_target}_copy_qml_plugins.stamp")
++ add_custom_command(OUTPUT "${stamp}"
++ COMMAND ${CMAKE_COMMAND} -E make_directory "${libs_abi_dir}"
++ ${copy_commands}
++ COMMAND ${CMAKE_COMMAND} -E touch "${stamp}"
++ DEPENDS ${copy_depends}
++ COMMENT "Copying QML plugin targets for ${target}"
++ VERBATIM
++ )
++ add_custom_target(${target}_copy_qml_plugins DEPENDS "${stamp}")
++ _qt_internal_android_add_deploy_libraries_dependency(${target} ${target}_copy_qml_plugins)
++ _qt_internal_android_register_deploy_files(${target} "${stamp}")
++ endfunction()
++
++ # Copies non-Qt shared libraries linked to the target.
++ function(_qt_internal_android_copy_non_qt_linked_libs target deployment_dir)
++ if(QT_NO_COLLECT_BUILD_TREE_APK_DEPS)
++ return()
++ endif()
++
++ if(TARGET ${target}_copy_non_qt_linked_libs)
++ return()
++ endif()
++
++ set(queue "${target}")
++ set(processed "")
++ set(linked_libs "")
++
++ # Queue project plugin targets so that non-Qt libs they link against are deployed.
++ get_target_property(qml_plugin_targets ${target} _qt_android_qml_plugins)
++ if(qml_plugin_targets)
++ list(APPEND queue ${qml_plugin_targets})
++ endif()
++
++ get_target_property(plugin_targets ${target} _qt_android_qt_plugins)
++ if(plugin_targets)
++ list(APPEND queue ${plugin_targets})
++ endif()
++
++ while(queue)
++ list(POP_FRONT queue current_target)
++ get_target_property(current_alias "${current_target}" ALIASED_TARGET)
++ if(current_alias)
++ set(current_target "${current_alias}")
++ endif()
++
++ if(current_target IN_LIST processed)
++ continue()
++ endif()
++ list(APPEND processed "${current_target}")
++
++ _qt_internal_android_extract_link_libraries_targets("${current_target}" link_targets)
++ foreach(entry IN LISTS link_targets)
++ if(NOT entry IN_LIST processed AND NOT entry IN_LIST queue)
++ list(APPEND queue "${entry}")
++ endif()
++
++ get_target_property(entry_type "${entry}" TYPE)
++ if(NOT entry_type OR NOT entry_type MATCHES "^(SHARED|MODULE)_LIBRARY$")
++ continue()
++ endif()
++
++ # Skip if it's a Qt library.
++ get_target_property(entry_qt_package_version "${entry}" _qt_package_version)
++ if(entry_qt_package_version)
++ continue()
++ endif()
++
++ list(APPEND linked_libs "${entry}")
++ endforeach()
++ endwhile()
++
++ list(REMOVE_DUPLICATES linked_libs)
++
++ if(NOT linked_libs)
++ return()
++ endif()
++
++ set(libs_abi_dir "${deployment_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}")
++ set(linked_libs_copy_commands COMMAND ${CMAKE_COMMAND} -E make_directory "${libs_abi_dir}")
++ foreach(lib IN LISTS linked_libs)
++ _qt_internal_android_get_deploy_command(deploy_cmd
++ "$<TARGET_FILE:${lib}>" "${libs_abi_dir}/$<TARGET_FILE_NAME:${lib}>")
++ list(APPEND linked_libs_copy_commands COMMAND ${deploy_cmd})
++ _qt_internal_android_append_to_libs_xml_section(${target}
++ extra_libs "$<TARGET_FILE_NAME:${lib}>")
++ endforeach()
++
++ _qt_internal_android_sanitize_target_name(sanitized_target ${target})
++ _qt_internal_android_staging_dir(android_staging_dir)
++ set(stamp "${android_staging_dir}/${sanitized_target}_copy_non_qt_linked_libs.stamp")
++ add_custom_command(OUTPUT "${stamp}"
++ ${linked_libs_copy_commands}
++ COMMAND ${CMAKE_COMMAND} -E touch "${stamp}"
++ DEPENDS ${linked_libs}
++ COMMENT "Copying linked shared libraries for ${target}"
++ VERBATIM
++ )
++ add_custom_target(${target}_copy_non_qt_linked_libs DEPENDS "${stamp}")
++ _qt_internal_android_add_deploy_libraries_dependency(${target}
++ ${target}_copy_non_qt_linked_libs)
++ _qt_internal_android_register_deploy_files(${target} "${stamp}")
++ endfunction()
++
++ # Copies (or symlinks) the app's binary file to the deployment dir.
++ function(_qt_internal_android_copy_app_binary target deployment_dir)
++ set(libs_abi_dir "${deployment_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}")
++ set(target_file_dst "${libs_abi_dir}/$<TARGET_FILE_NAME:${target}>")
++
++ _qt_internal_android_get_use_terminal_for_deployment(uses_terminal)
++
++ _qt_internal_android_get_deploy_command(deploy_command
++ "$<TARGET_FILE:${target}>" "${target_file_dst}")
++ if(QT_ANDROID_CREATE_SYMLINKS_ONLY)
++ set(deploy_comment "Symlinking ${target} binary to apk folder")
++ else()
++ set(deploy_comment "Copying ${target} binary to apk folder")
++ endif()
++
++ _qt_internal_android_sanitize_target_name(sanitized_target ${target})
++ _qt_internal_android_staging_dir(android_staging_dir)
++ set(stamp "${android_staging_dir}/${sanitized_target}_copy_app_binary.stamp")
++ add_custom_command(OUTPUT "${stamp}"
++ COMMAND ${CMAKE_COMMAND} -E make_directory "${libs_abi_dir}"
++ COMMAND ${deploy_command}
++ COMMAND ${CMAKE_COMMAND} -E touch "${stamp}"
++ DEPENDS ${target}
++ COMMENT "${deploy_comment}"
++ VERBATIM
++ ${uses_terminal}
++ )
++ add_custom_target(${target}_copy_app_binary ALL DEPENDS "${stamp}")
++ _qt_internal_android_add_deploy_libraries_dependency(${target} ${target}_copy_app_binary)
++ _qt_internal_android_register_deploy_files(${target} "${stamp}")
++ endfunction()
++
++ # Returns command to deploy a file or create a symlink to the deployment dir.
++ function(_qt_internal_android_get_deploy_command out_cmd src dst)
++ if(QT_ANDROID_CREATE_SYMLINKS_ONLY)
++ set(${out_cmd} ${CMAKE_COMMAND} -E create_symlink "${src}" "${dst}" PARENT_SCOPE)
++ else()
++ _qt_internal_copy_file_if_different_command(${out_cmd} "${src}" "${dst}")
++ set(${out_cmd} "${${out_cmd}}" PARENT_SCOPE)
++ endif()
++ endfunction()
++
++ # Warns once that ${missing} is not an imported target and so cannot be deployed.
++ function(_qt_internal_android_warn_unresolved_dependency dependent missing)
++ get_property(warned GLOBAL PROPERTY _qt_internal_android_warned_undeployable_deps)
++ if(missing IN_LIST warned)
++ return()
++ endif()
++ set_property(GLOBAL APPEND PROPERTY _qt_internal_android_warned_undeployable_deps "${missing}")
++
++ string(REGEX REPLACE "^${QT_CMAKE_EXPORT_NAMESPACE}::" "" component "${missing}")
++ message(WARNING
++ "The target \"${dependent}\" depends on \"${missing}\", but it is not "
++ "an imported target, so its backing library cannot be deployed and "
++ "will be missing from the Android bundle. Import it using:\n"
++ " find_package(${QT_CMAKE_EXPORT_NAMESPACE} COMPONENTS ${component})")
++ endfunction()
++
++ # Returns the list of valid CMake targets from the link library properties of the given target.
++ function(_qt_internal_android_extract_link_libraries_targets target out_targets)
++ string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type_upper)
++ set(result "")
++ foreach(property_name IN ITEMS
++ LINK_LIBRARIES
++ INTERFACE_LINK_LIBRARIES
++ IMPORTED_LINK_DEPENDENT_LIBRARIES
++ "IMPORTED_LINK_DEPENDENT_LIBRARIES_${build_type_upper}")
++ get_target_property(link_entries "${target}" ${property_name})
++ if(NOT link_entries)
++ continue()
++ endif()
++ foreach(raw_entry IN LISTS link_entries)
++ # Unwrap genex wrappers (e.g. $<LINK_ONLY:Qt6::Core>) to get the target name.
++ if(raw_entry MATCHES "^\\$<[^:]+:(.+)>$")
++ set(entry "${CMAKE_MATCH_1}")
++ else()
++ set(entry "${raw_entry}")
++ endif()
++ if(TARGET "${entry}")
++ get_target_property(entry_alias "${entry}" ALIASED_TARGET)
++ if(entry_alias)
++ set(entry "${entry_alias}")
++ endif()
++ list(APPEND result "${entry}")
++ elseif(entry MATCHES "^${QT_CMAKE_EXPORT_NAMESPACE}::")
++ _qt_internal_android_warn_unresolved_dependency("${target}" "${entry}")
++ endif()
++ endforeach()
++ endforeach()
++ list(REMOVE_DUPLICATES result)
++ set(${out_targets} "${result}" PARENT_SCOPE)
++ endfunction()
++
++ # Resolves a QML's module backing target
++ function(_qt_internal_android_resolve_backing_target target out_var)
++ set(${out_var} "" PARENT_SCOPE)
++ get_target_property(qml_backing "${target}" _qt_qml_module_backing_target)
++ if(NOT qml_backing)
++ return()
++ endif()
++
++ set (qt_ns "${QT_CMAKE_EXPORT_NAMESPACE}")
++ if(TARGET "${qml_backing}")
++ set(${out_var} "${qml_backing}" PARENT_SCOPE)
++ elseif(TARGET "${qt_ns}::${qml_backing}")
++ set(${out_var} "${qt_ns}::${qml_backing}" PARENT_SCOPE)
++ else()
++ _qt_internal_android_warn_unresolved_dependency("${target}" "${qt_ns}::${qml_backing}")
++ endif()
++ endfunction()
++
++ # Collects Qt modules that a target depends on and their associated plugins.
++ function(_qt_internal_android_collect_qt_modules_and_plugins target)
++ set(pending_stack "${target}")
++ set(visited "")
++ set(collected_modules "")
++ set(collected_plugins "")
++
++ get_target_property(qml_plugins ${target} _qt_android_qml_plugins)
++ if(qml_plugins)
++ list(APPEND pending_stack ${qml_plugins})
++ endif()
++
++ set(qt_ns ${QT_CMAKE_EXPORT_NAMESPACE})
++ while(pending_stack)
++ list(GET pending_stack -1 current_target)
++
++ if(current_target IN_LIST visited)
++ list(POP_BACK pending_stack)
++ get_target_property(target_type "${current_target}" TYPE)
++ get_target_property(is_qml_plugin "${current_target}" _qt_qml_module_is_plugin_target)
++ if (is_qml_plugin OR NOT target_type MATCHES "^(SHARED|MODULE)_LIBRARY$")
++ continue()
++ endif()
++ if(current_target MATCHES "^${qt_ns}::" OR TARGET "${qt_ns}::${current_target}")
++ if(NOT current_target IN_LIST collected_modules)
++ list(APPEND collected_modules "${current_target}")
++ endif()
++ endif()
++ continue()
++ endif()
++ list(APPEND visited "${current_target}")
++
++ set(direct_deps "")
++ _qt_internal_android_resolve_backing_target("${current_target}" backing)
++ list(APPEND direct_deps "${backing}")
++
++ _qt_internal_android_list_module_plugins("${current_target}" module_plugins)
++ foreach(plugin_target IN LISTS module_plugins)
++ if(NOT plugin_target IN_LIST collected_plugins)
++ list(APPEND collected_plugins "${plugin_target}")
++ endif()
++ endforeach()
++
++ foreach(dep_source IN ITEMS "${current_target}" ${module_plugins})
++ _qt_internal_android_list_plugin_modules("${dep_source}" plugin_module_deps)
++ list(APPEND direct_deps ${plugin_module_deps})
++ endforeach()
++
++ _qt_internal_android_extract_link_libraries_targets("${current_target}" link_targets)
++ list(APPEND direct_deps ${link_targets})
++
++ list(FILTER direct_deps EXCLUDE REGEX "^$")
++ list(REMOVE_DUPLICATES direct_deps)
++ list(REMOVE_ITEM direct_deps "${current_target}")
++ list(APPEND pending_stack ${direct_deps})
++ endwhile()
++
++ list(REMOVE_DUPLICATES collected_modules)
++ list(REMOVE_DUPLICATES collected_plugins)
++
++ set_property(TARGET ${target} PROPERTY _qt_android_qt_modules "${collected_modules}")
++ set_property(TARGET ${target} PROPERTY _qt_android_qt_plugins "${collected_plugins}")
++ endfunction()
++
++ # Adds a deploy command into commands/depends lists in the caller's scope, skipping duplicates.
++ function(_qt_internal_android_add_dependency_deploy_step)
++ set(one_value_args
++ SOURCE
++ DESTINATION
++ DEPENDS_ITEM
++ SEEN_DESTINATIONS_VAR
++ COPY_COMMANDS_VAR
++ COPY_DEPENDS_VAR
++ )
++ cmake_parse_arguments(PARSE_ARGV 0 arg "" "${one_value_args}" "")
++
++ if("${arg_DESTINATION}" IN_LIST ${arg_SEEN_DESTINATIONS_VAR})
++ return()
++ endif()
++ _qt_internal_android_get_deploy_command(cmd "${arg_SOURCE}" "${arg_DESTINATION}")
++ get_filename_component(dst_dir "${arg_DESTINATION}" DIRECTORY)
++ list(APPEND ${arg_COPY_COMMANDS_VAR} COMMAND ${CMAKE_COMMAND} -E make_directory "${dst_dir}")
++ list(APPEND ${arg_SEEN_DESTINATIONS_VAR} "${arg_DESTINATION}")
++ list(APPEND ${arg_COPY_COMMANDS_VAR} COMMAND ${cmd})
++ list(APPEND ${arg_COPY_DEPENDS_VAR} "${arg_DEPENDS_ITEM}")
++ set(${arg_SEEN_DESTINATIONS_VAR} "${${arg_SEEN_DESTINATIONS_VAR}}" PARENT_SCOPE)
++ set(${arg_COPY_COMMANDS_VAR} "${${arg_COPY_COMMANDS_VAR}}" PARENT_SCOPE)
++ set(${arg_COPY_DEPENDS_VAR} "${${arg_COPY_DEPENDS_VAR}}" PARENT_SCOPE)
++ endfunction()
++
++ # Deploys QT_ANDROID_BUNDLED_JAR_DEPENDENCIES declared by dep.
++ function(_qt_internal_android_process_bundled_jars dep libs_root_dir
++ inout_seen_destinations inout_copy_commands inout_copy_depends)
++ get_target_property(jar_deps "${dep}" QT_ANDROID_BUNDLED_JAR_DEPENDENCIES)
++ if(NOT jar_deps)
++ return()
++ endif()
++
++ _qt_internal_get_android_abi_prefix_path(qt_prefix ${CMAKE_ANDROID_ARCH_ABI})
++ _qt_internal_get_android_abi_subdir_path(qt_data_dir QT6_INSTALL_DATA ${CMAKE_ANDROID_ARCH_ABI})
++ _qt_internal_path_join(qt_data_dir "${qt_prefix}" "${qt_data_dir}")
++
++ foreach(jar IN LISTS jar_deps)
++ if(IS_ABSOLUTE "${jar}")
++ set(jar_absolute "${jar}")
++ else()
++ _qt_internal_path_join(jar_absolute "${qt_data_dir}" "${jar}")
++ endif()
++ if(NOT EXISTS "${jar_absolute}")
++ message(WARNING "The JAR dependency '${jar_absolute}' is missing for ${dep}.")
++ continue()
++ endif()
++
++ string(REGEX REPLACE "^jar/" "" jar_relative "${jar}")
++ _qt_internal_path_join(destination "${libs_root_dir}" "${jar_relative}")
++ _qt_internal_android_add_dependency_deploy_step(
++ SOURCE "${jar_absolute}"
++ DESTINATION "${destination}"
++ DEPENDS_ITEM "${jar_absolute}"
++ SEEN_DESTINATIONS_VAR ${inout_seen_destinations}
++ COPY_COMMANDS_VAR ${inout_copy_commands}
++ COPY_DEPENDS_VAR ${inout_copy_depends})
++ endforeach()
++
++ set(${inout_seen_destinations} "${${inout_seen_destinations}}" PARENT_SCOPE)
++ set(${inout_copy_commands} "${${inout_copy_commands}}" PARENT_SCOPE)
++ set(${inout_copy_depends} "${${inout_copy_depends}}" PARENT_SCOPE)
++ endfunction()
++
++ # Deploys the dep's own .so and registers it in libs.xml qt_libs, unless dep
++ # has QT_PLUGIN_TYPE set (plugins are handled by the Qt plugin loader).
++ function(_qt_internal_android_deploy_qt_dependency)
++ set(one_value_args
++ TARGET
++ DEPENDENCY_TARGET
++ LIBS_ABI_DIR
++ SEEN_DESTINATIONS_VAR
++ COPY_COMMANDS_VAR
++ COPY_DEPENDS_VAR
++ )
++ cmake_parse_arguments(PARSE_ARGV 0 arg "" "${one_value_args}" "")
++
++ if(NOT TARGET "${arg_DEPENDENCY_TARGET}")
++ return()
++ endif()
++
++ set(destination "${arg_LIBS_ABI_DIR}/$<TARGET_FILE_NAME:${arg_DEPENDENCY_TARGET}>")
++ if("${destination}" IN_LIST ${arg_SEEN_DESTINATIONS_VAR})
++ return()
++ endif()
++
++ get_target_property(plugin_type "${arg_DEPENDENCY_TARGET}" QT_PLUGIN_TYPE)
++ if(NOT plugin_type)
++ get_target_property(iface_name "${arg_DEPENDENCY_TARGET}" _qt_module_interface_name)
++ if(iface_name)
++ set(lib_name "${QT_CMAKE_EXPORT_NAMESPACE}${iface_name}_${CMAKE_ANDROID_ARCH_ABI}")
++ else()
++ set(lib_name "$<TARGET_FILE_NAME:${arg_DEPENDENCY_TARGET}>")
++ endif()
++ _qt_internal_android_append_to_libs_xml_section(${arg_TARGET} qt_libs "${lib_name}")
++ endif()
++
++ _qt_internal_android_add_dependency_deploy_step(
++ SOURCE "$<TARGET_FILE:${arg_DEPENDENCY_TARGET}>"
++ DESTINATION "${destination}"
++ DEPENDS_ITEM "${arg_DEPENDENCY_TARGET}"
++ SEEN_DESTINATIONS_VAR ${arg_SEEN_DESTINATIONS_VAR}
++ COPY_COMMANDS_VAR ${arg_COPY_COMMANDS_VAR}
++ COPY_DEPENDS_VAR ${arg_COPY_DEPENDS_VAR})
++
++ set(${arg_SEEN_DESTINATIONS_VAR} "${${arg_SEEN_DESTINATIONS_VAR}}" PARENT_SCOPE)
++ set(${arg_COPY_COMMANDS_VAR} "${${arg_COPY_COMMANDS_VAR}}" PARENT_SCOPE)
++ set(${arg_COPY_DEPENDS_VAR} "${${arg_COPY_DEPENDS_VAR}}" PARENT_SCOPE)
++ endfunction()
++
++ # Deploys QT_ANDROID_LIB_DEPENDENCIES declared by dep (module or plugin),
++ # registering each in the libs.xml local_libs section for JNI_OnLoad().
++ function(_qt_internal_android_process_lib_deps)
++ set(one_value_args
++ TARGET
++ DEPENDENCY_TARGET
++ LIBS_ABI_DIR
++ SEEN_DESTINATIONS_VAR
++ COPY_COMMANDS_VAR
++ COPY_DEPENDS_VAR
++ )
++ cmake_parse_arguments(PARSE_ARGV 0 arg "" "${one_value_args}" "")
++
++ get_target_property(lib_deps "${arg_DEPENDENCY_TARGET}" QT_ANDROID_LIB_DEPENDENCIES)
++ if(NOT lib_deps)
++ return()
++ endif()
++
++ _qt_internal_get_android_abi_prefix_path(qt_prefix ${CMAKE_ANDROID_ARCH_ABI})
++ set(abi_so_suffix "_${CMAKE_ANDROID_ARCH_ABI}.so")
++
++ foreach(lib IN LISTS lib_deps)
++ if(IS_ABSOLUTE "${lib}")
++ set(lib_absolute "${lib}")
++ else()
++ _qt_internal_path_join(lib_absolute "${qt_prefix}" "${lib}")
++ endif()
++
++ if(NOT lib_absolute MATCHES "${abi_so_suffix}$")
++ string(REGEX REPLACE "\\.so$" "${abi_so_suffix}" lib_abi "${lib_absolute}")
++ if(EXISTS "${lib_abi}")
++ set(lib_absolute "${lib_abi}")
++ endif()
++ endif()
++
++ if(NOT EXISTS "${lib_absolute}")
++ message(WARNING
++ "The library dependency '${lib_absolute}' is missing for ${arg_DEPENDENCY_TARGET}.")
++ continue()
++ endif()
++
++ get_filename_component(filename "${lib_absolute}" NAME)
++ _qt_internal_android_append_to_libs_xml_section(${arg_TARGET} local_libs "${filename}")
++
++ _qt_internal_path_join(destination "${arg_LIBS_ABI_DIR}" "${filename}")
++ _qt_internal_android_add_dependency_deploy_step(
++ SOURCE "${lib_absolute}"
++ DESTINATION "${destination}"
++ DEPENDS_ITEM "${lib_absolute}"
++ SEEN_DESTINATIONS_VAR ${arg_SEEN_DESTINATIONS_VAR}
++ COPY_COMMANDS_VAR ${arg_COPY_COMMANDS_VAR}
++ COPY_DEPENDS_VAR ${arg_COPY_DEPENDS_VAR})
++ endforeach()
++
++ set(${arg_SEEN_DESTINATIONS_VAR} "${${arg_SEEN_DESTINATIONS_VAR}}" PARENT_SCOPE)
++ set(${arg_COPY_COMMANDS_VAR} "${${arg_COPY_COMMANDS_VAR}}" PARENT_SCOPE)
++ set(${arg_COPY_DEPENDS_VAR} "${${arg_COPY_DEPENDS_VAR}}" PARENT_SCOPE)
++ endfunction()
++
++ # Resolves plugin paths for a module using the _qt_plugins property.
++ function(_qt_internal_android_list_module_plugins module out_plugin_paths)
++ set(result "")
++
++ get_target_property(qt_plugins "${module}" _qt_plugins)
++ if(NOT qt_plugins)
++ set(qt_plugins "")
++ endif()
++ foreach(qt_plugin IN LISTS qt_plugins)
++ set(plugin_target "${QT_CMAKE_EXPORT_NAMESPACE}::${qt_plugin}")
++ if(NOT TARGET "${plugin_target}")
++ message(WARNING
++ "Skipping the deployment scanning of ${plugin_target} plugin "
++ "for ${module} module because it's an invalid target.")
++ continue()
++ endif()
++ get_target_property(plugin_type "${plugin_target}" TYPE)
++ if(plugin_type MATCHES "^(SHARED|MODULE)_LIBRARY$")
++ list(APPEND result "${plugin_target}")
++ endif()
++ endforeach()
++
++ list(REMOVE_DUPLICATES result)
++ set(${out_plugin_paths} "${result}" PARENT_SCOPE)
++ endfunction()
++
++ # Returns the shared Qt module targets declared as dependencies of a plugin via
++ # _qt_plugin_qt_module_dependencies, filtered to shared libraries only.
++ function(_qt_internal_android_list_plugin_modules plugin_target out_module_deps)
++ get_target_property(plugin_module_deps "${plugin_target}" _qt_plugin_qt_module_dependencies)
++ if(NOT plugin_module_deps)
++ set(${out_module_deps} "" PARENT_SCOPE)
++ return()
++ endif()
++
++ set(result "")
++ foreach(dep_target IN LISTS plugin_module_deps)
++ if(NOT TARGET "${dep_target}")
++ _qt_internal_android_warn_unresolved_dependency("${plugin_target}" "${dep_target}")
++ continue()
++ endif()
++ get_target_property(type "${dep_target}" TYPE)
++ if(type STREQUAL "SHARED_LIBRARY")
++ list(APPEND result "${dep_target}")
++ endif()
++ endforeach()
++ set(${out_module_deps} "${result}" PARENT_SCOPE)
++ endfunction()
++
++ # Copy Qt dependencies (libs, jars, plugins) to the deployment dir.
++ function(_qt_internal_android_copy_qt_dependencies target deployment_dir)
++ set(copy_commands "")
++ set(copy_depends "")
++ set(seen_destinations "")
++
++ set(libs_root_dir "${deployment_dir}/libs")
++ set(libs_abi_dir "${libs_root_dir}/${CMAKE_ANDROID_ARCH_ABI}")
++ list(APPEND copy_commands COMMAND ${CMAKE_COMMAND} -E make_directory "${libs_abi_dir}")
++
++ get_target_property(no_deploy_qt_libs ${target} QT_ANDROID_NO_DEPLOY_QT_LIBS)
++ get_target_property(qt_modules ${target} _qt_android_qt_modules)
++ get_target_property(qt_plugins ${target} _qt_android_qt_plugins)
++
++ foreach(dep IN LISTS qt_modules qt_plugins)
++ _qt_internal_android_process_bundled_jars("${dep}" "${libs_root_dir}"
++ seen_destinations copy_commands copy_depends)
++ if(NOT no_deploy_qt_libs)
++ _qt_internal_android_deploy_qt_dependency(
++ TARGET "${target}"
++ DEPENDENCY_TARGET "${dep}"
++ LIBS_ABI_DIR "${libs_abi_dir}"
++ SEEN_DESTINATIONS_VAR seen_destinations
++ COPY_COMMANDS_VAR copy_commands
++ COPY_DEPENDS_VAR copy_depends)
++ _qt_internal_android_process_lib_deps(
++ TARGET "${target}"
++ DEPENDENCY_TARGET "${dep}"
++ LIBS_ABI_DIR "${libs_abi_dir}"
++ SEEN_DESTINATIONS_VAR seen_destinations
++ COPY_COMMANDS_VAR copy_commands
++ COPY_DEPENDS_VAR copy_depends)
++ endif()
++ endforeach()
++
++ # Plugins aren't linked, so their permissions aren't transitive like modules.
++ _qt_internal_android_collect_permissions(${target} SOURCE_TARGETS ${qt_plugins})
++
++ list(REMOVE_DUPLICATES copy_depends)
++ list(FILTER copy_depends EXCLUDE REGEX "^$")
++
++ if(NOT copy_commands)
++ return()
++ endif()
++
++ _qt_internal_android_sanitize_target_name(sanitized_target ${target})
++ _qt_internal_android_staging_dir(android_staging_dir)
++ set(stamp "${android_staging_dir}/${sanitized_target}_copy_qt_files.stamp")
++ add_custom_command(OUTPUT "${stamp}"
++ ${copy_commands}
++ COMMAND ${CMAKE_COMMAND} -E touch "${stamp}"
++ DEPENDS ${copy_depends}
++ COMMENT "Copying Qt deployment files for ${target}"
++ VERBATIM
++ )
++ add_custom_target(${target}_copy_qt_files DEPENDS "${stamp}")
++ _qt_internal_android_add_deploy_libraries_dependency(${target} ${target}_copy_qt_files)
++ _qt_internal_android_register_deploy_files(${target} "${stamp}")
++ endfunction()
++
++ # Appends a unique lib name for the target to the libs.xml section.
++ function(_qt_internal_android_append_to_libs_xml_section target section_name lib_name)
++ if(NOT lib_name)
++ return()
++ endif()
++
++ set(normalized_lib_name "${lib_name}")
++ # qt_libs are loaded by base name; other sections keep the full file name.
++ if(section_name STREQUAL "qt_libs" AND NOT lib_name MATCHES "^[$]<")
++ get_filename_component(file_name "${normalized_lib_name}" NAME)
++ if(file_name MATCHES "^lib(.+)\\.so$")
++ set(normalized_lib_name "${CMAKE_MATCH_1}")
++ else()
++ string(REGEX REPLACE "\\.so$" "" normalized_lib_name "${file_name}")
++ endif()
++ endif()
++
++ set(full_section_name "_android_libs_xml_${section_name}")
++ get_target_property(current_libs ${target} ${full_section_name})
++ if(NOT current_libs)
++ set(current_libs "")
++ endif()
++
++ list(FIND current_libs "${normalized_lib_name}" _qt_append_index)
++ if(_qt_append_index EQUAL -1)
++ list(APPEND current_libs "${normalized_lib_name}")
++ set_target_properties(${target} PROPERTIES ${full_section_name} "${current_libs}")
++ endif()
++ endfunction()
++
++ # Collects the target's libs.xml section and returns the XML string.
++ function(_qt_internal_android_assemble_libs_xml_section target section_name out_section)
++ set(property_name "_android_libs_xml_${section_name}")
++ get_target_property(libs ${target} ${property_name})
++ if(NOT libs)
++ set(libs "")
++ endif()
++
++ list(REMOVE_ITEM libs "")
++ list(REMOVE_DUPLICATES libs)
++ set(entries "")
++ foreach(lib IN LISTS libs)
++ string(APPEND entries "
++ <item>${abi};${lib}</item>")
++ endforeach()
++ string(REGEX REPLACE "^
++ " "" entries "${entries}") # fix indentation of first item
++
++ set(${out_section} "${entries}" PARENT_SCOPE)
++ endfunction()
++
++ # Generate a populated libs.xml file.
++ function(_qt_internal_android_generate_libs_xml target deployment_dir)
++ set(abi "${CMAKE_ANDROID_ARCH_ABI}")
++ _qt_internal_android_assemble_libs_xml_section(${target} "qt_libs" qt_libs)
++ _qt_internal_android_assemble_libs_xml_section(${target} "local_libs" local_libs)
++ _qt_internal_android_assemble_libs_xml_section(${target} "extra_libs" extra_libs)
++
++ _qt_internal_android_template_res_dir(template_res_dir)
++ set(libs_xml_template "${template_res_dir}/values/libs.xml")
++ if(NOT EXISTS "${libs_xml_template}")
++ message(FATAL_ERROR "Android libs.xml template file not found at '${libs_xml_template}'.")
++ endif()
++ file(READ "${libs_xml_template}" content)
++
++ string(REPLACE "<!-- %%INSERT_QT_LIBS%% -->" "${qt_libs}" content "${content}")
++ string(REPLACE "<!-- %%INSERT_LOCAL_LIBS%% -->" "${local_libs}" content "${content}")
++ string(REPLACE "<!-- %%INSERT_EXTRA_LIBS%% -->" "${extra_libs}" content "${content}")
++ string(REPLACE "<!-- %%USE_LOCAL_QT_LIBS%% -->" "1" content "${content}")
++ string(REPLACE "<!-- %%BUNDLE_LOCAL_QT_LIBS%% -->" "1" content "${content}")
++ string(REPLACE "<!-- %%SYSTEM_LIBS_PREFIX%% -->" "" content "${content}")
++
++ set(libs_xml_dst "${deployment_dir}/res/values/libs.xml")
++
++ _qt_internal_android_sanitize_target_name(sanitized_target ${target})
++ _qt_internal_android_staging_dir(android_staging_dir)
++ set(libs_xml_staged "${android_staging_dir}/${sanitized_target}_libs.xml")
++ file(GENERATE OUTPUT "${libs_xml_staged}" CONTENT "${content}")
++
++ add_custom_target(${target}_update_libs_xml
++ COMMAND ${CMAKE_COMMAND} -E copy_if_different "${libs_xml_staged}" "${libs_xml_dst}"
++ DEPENDS ${target}_copy_android_res_files
++ COMMENT "Updating libs.xml for ${target}"
++ VERBATIM
++ )
++
++ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${libs_xml_dst}")
++ endfunction()
++
++ function(_qt_internal_android_get_qml_root_paths target out_root_paths)
++ get_target_property(qml_root_paths ${target} QT_QML_ROOT_PATH)
++ if(NOT qml_root_paths)
++ get_target_property(qml_root_paths ${target} SOURCE_DIR)
++ get_target_property(target_binary_dir ${target} BINARY_DIR)
++ list(APPEND qml_root_paths "${target_binary_dir}")
++ endif()
++
++ get_target_property(extra_root_paths ${target} QT_QML_IMPORT_SCANNER_EXTRA_ROOT_PATHS)
++ if(extra_root_paths)
++ list(APPEND qml_root_paths ${extra_root_paths})
++ endif()
++ if(QT_QML_IMPORT_SCANNER_EXTRA_ROOT_PATHS)
++ list(APPEND qml_root_paths ${QT_QML_IMPORT_SCANNER_EXTRA_ROOT_PATHS})
++ endif()
++
++ set(${out_root_paths} "${qml_root_paths}" PARENT_SCOPE)
++ endfunction()
++
++ function(_qt_internal_android_get_qmlimportscanner_scan target qmlimportscanner_path out_qml_scan)
++ if(NOT qmlimportscanner_path)
++ set(${out_qml_scan} "" PARENT_SCOPE)
++ return()
++ endif()
++
++ _qt_internal_android_get_qml_root_paths(${target} qml_root_paths)
++ _qt_internal_collect_qml_import_paths(qml_import_paths ${target})
++
++ set(qmlimportscanner_command "${qmlimportscanner_path}")
++ foreach(root_path IN LISTS qml_root_paths)
++ list(APPEND qmlimportscanner_command "-rootPath" "${root_path}")
++ endforeach()
++ foreach(import_path IN LISTS qml_import_paths)
++ list(APPEND qmlimportscanner_command "-importPath" "${import_path}")
++ endforeach()
++
++ execute_process(
++ COMMAND ${qmlimportscanner_command}
++ RESULT_VARIABLE qml_scan_result
++ OUTPUT_VARIABLE qml_scan_output
++ ERROR_VARIABLE qml_scan_error
++ )
++ if(NOT qml_scan_result EQUAL 0)
++ message(WARNING "qmlimportscanner failed for ${target}: ${qml_scan_error}")
++ set(${out_qml_scan} "" PARENT_SCOPE)
++ return()
++ endif()
++
++ string(STRIP "${qml_scan_output}" qml_scan_output)
++ set(${out_qml_scan} "${qml_scan_output}" PARENT_SCOPE)
++ endfunction()
++
++ function(_qt_internal_android_json_get_string json index key out_value)
++ string(JSON value_type ERROR_VARIABLE type_error TYPE "${json}" ${index} ${key})
++ if(type_error OR NOT value_type STREQUAL "STRING")
++ set(${out_value} "" PARENT_SCOPE)
++ return()
++ endif()
++ string(JSON value ERROR_VARIABLE value_error GET "${json}" ${index} ${key})
++ if(value_error OR value STREQUAL "")
++ set(${out_value} "" PARENT_SCOPE)
++ return()
++ endif()
++
++ set(${out_value} "${value}" PARENT_SCOPE)
++ endfunction()
++
++ function(_qt_internal_android_json_get_bool json index key out_value)
++ string(JSON value_type ERROR_VARIABLE type_error TYPE "${json}" ${index} ${key})
++ if(type_error OR NOT value_type STREQUAL "BOOL")
++ set(${out_value} FALSE PARENT_SCOPE)
++ return()
++ endif()
++ string(JSON value ERROR_VARIABLE value_error GET "${json}" ${index} ${key})
++ if(value_error)
++ set(${out_value} FALSE PARENT_SCOPE)
++ return()
++ endif()
++ string(TOLOWER "${value}" value_lower)
++ if(value_lower STREQUAL "true")
++ set(${out_value} TRUE PARENT_SCOPE)
++ else()
++ set(${out_value} FALSE PARENT_SCOPE)
++ endif()
++ endfunction()
++
++ # Reconfigures CMake within a single ninja build when QML imports change.
++ function(_qt_internal_android_setup_qml_imports_reconfigure_trigger target)
++ if(NOT TARGET ${QT_CMAKE_EXPORT_NAMESPACE}::Qml OR QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT)
++ return()
++ endif()
++
++ _qt_internal_android_staging_dir(android_staging_dir)
++ set(qml_scan_script "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/QtAndroidScanQmlImports.cmake")
++
++ _qt_internal_android_sanitize_target_name(sanitized_target ${target})
++ set(snapshot_file "${android_staging_dir}/${sanitized_target}_qml_imports.snapshot")
++ set(stamp_file "${android_staging_dir}/${sanitized_target}_qml_imports.stamp")
++
++ set(source_dirs_arg "")
++ _qt_internal_android_get_qml_root_paths(${target} qml_root_paths)
++ foreach(path IN LISTS qml_root_paths)
++ if(source_dirs_arg)
++ string(APPEND source_dirs_arg ";")
++ endif()
++ string(APPEND source_dirs_arg "${path}")
++ endforeach()
++
++ set(qml_scan_cmd "${CMAKE_COMMAND}"
++ "-DSOURCE_DIRS=${source_dirs_arg}"
++ "-DSNAPSHOT=${snapshot_file}"
++ "-DSTAMP=${stamp_file}"
++ -P "${qml_scan_script}")
++
++ # Seed the snapshot once so the first build doesn't regen on a missing snapshot.
++ if(NOT EXISTS "${snapshot_file}")
++ execute_process(COMMAND ${qml_scan_cmd})
++ endif()
++
++ # CONFIGURE_DEPENDS catches file add/remove, same list feeds the scan rule's DEPENDS.
++ set(qml_sources "")
++ foreach(path IN LISTS qml_root_paths)
++ if(IS_DIRECTORY "${path}")
++ file(GLOB_RECURSE found CONFIGURE_DEPENDS LIST_DIRECTORIES false
++ "${path}/*.qml" "${path}/*.js" "${path}/*.mjs")
++ list(APPEND qml_sources ${found})
++ endif()
++ endforeach()
++ list(REMOVE_DUPLICATES qml_sources)
++
++ # FIXME: This relies on a mid-build regen, which only ninja does. Makefiles
++ # check configure dependencies at startup, so a fresh import needs two builds.
++ add_custom_command(
++ OUTPUT "${stamp_file}"
++ BYPRODUCTS "${snapshot_file}"
++ COMMAND ${qml_scan_cmd}
++ DEPENDS ${qml_sources}
++ COMMENT "Checking QML imports for ${target}"
++ VERBATIM
++ )
++ add_custom_target(${target}_qml_imports_check ALL DEPENDS "${stamp_file}")
++ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${snapshot_file}")
++
++ foreach(pkg_target ${target}_make_apk ${target}_make_aab)
++ if(TARGET ${pkg_target})
++ add_dependencies(${pkg_target} ${target}_qml_imports_check)
++ endif()
++ endforeach()
++ endfunction()
++
++ function(_qt_internal_android_parse_qmlimportscanner_output target)
++ if(NOT TARGET ${QT_CMAKE_EXPORT_NAMESPACE}::Qml)
++ return()
++ endif()
++
++ __qt_internal_get_tool_imported_location(qmlimportscanner_path "qmlimportscanner")
++ if(NOT qmlimportscanner_path)
++ message(WARNING
++ "qmlimportscanner not found. Skipping QML dependency scanning for ${target}.")
++ return()
++ endif()
++
++ _qt_internal_android_get_qmlimportscanner_scan(${target} "${qmlimportscanner_path}" qml_scan)
++ if(qml_scan STREQUAL "")
++ return()
++ endif()
++
++ set(qml_modules "")
++ set(qml_plugins "")
++
++ string(JSON module_count LENGTH "${qml_scan}")
++ if(NOT module_count GREATER 0)
++ return()
++ endif()
++
++ math(EXPR module_last_index "${module_count} - 1")
++ foreach(mod_index RANGE 0 ${module_last_index})
++ _qt_internal_android_json_get_string("${qml_scan}" ${mod_index} path module_path)
++ if(NOT module_path)
++ continue()
++ endif()
++
++ set(skip_module FALSE)
++ _qt_internal_android_json_get_string("${qml_scan}" ${mod_index} plugin plugin_name)
++ if(NOT plugin_name)
++ continue()
++ endif()
++
++ _qt_internal_android_json_get_string("${qml_scan}" ${mod_index} linkTarget link_target)
++ if(TARGET "${link_target}")
++ get_property(plugin_target TARGET "${link_target}"
++ PROPERTY _qt_qml_module_installed_plugin_target)
++ if(NOT plugin_target)
++ get_property(plugin_target TARGET "${link_target}"
++ PROPERTY _qt_qml_module_plugin_target)
++ endif()
++ if(NOT plugin_target)
++ set(plugin_target "${link_target}")
++ endif()
++ # Don't pass STATIC targets to the Android loader.
++ get_target_property(plugin_type "${plugin_target}" TYPE)
++ if(NOT plugin_type MATCHES "^(SHARED|MODULE)_LIBRARY$")
++ continue()
++ endif()
++ list(APPEND qml_plugins "${plugin_target}")
++ else()
++ _qt_internal_android_json_get_bool("${qml_scan}" ${mod_index} pluginIsOptional optional)
++ if(NOT optional AND NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
++ message(WARNING "QML plugin '${plugin_name}' not found for ${target}.")
++ set(skip_module TRUE)
++ endif()
++ endif()
++
++ if(NOT skip_module)
++ get_filename_component(module_abs "${module_path}" ABSOLUTE)
++ _qt_internal_android_json_get_string("${qml_scan}" ${mod_index} relativePath module_rel)
++ list(APPEND qml_modules "${module_abs}::${module_rel}")
++ endif()
++ endforeach()
++
++ list(REMOVE_DUPLICATES qml_modules)
++ list(REMOVE_DUPLICATES qml_plugins)
++
++ set_property(TARGET ${target} PROPERTY _qt_android_qml_modules "${qml_modules}")
++ set_property(TARGET ${target} PROPERTY _qt_android_qml_plugins "${qml_plugins}")
++ endfunction()
++
++ function(_qt_internal_android_create_rcc_bundle target deployment_dir)
++ get_target_property(qml_modules ${target} _qt_android_qml_modules)
++ if(NOT qml_modules)
++ return()
++ endif()
++
++ __qt_internal_get_tool_imported_location(rcc_path "rcc")
++ if(NOT rcc_path)
++ message(WARNING "rcc not found. Skipping QML dependency bundling for ${target}.")
++ return()
++ endif()
++
++ # Stage outside deployment_dir so the rcc bundle cleanup can't invalidate the stamp.
++ _qt_internal_android_sanitize_target_name(sanitized_target ${target})
++ _qt_internal_android_staging_dir(android_staging_dir)
++ set(qml_bundle_dir "${android_staging_dir}/${sanitized_target}-qml-bundle")
++
++ set(commands "")
++ set(qmldir_inputs "")
++ foreach(module_entry IN LISTS qml_modules)
++ string(REPLACE "::" ";" module_parts "${module_entry}")
++ list(GET module_parts 0 module_abs)
++ list(GET module_parts 1 module_rel)
++ if(NOT module_abs OR NOT module_rel)
++ continue()
++ endif()
++
++ if(NOT EXISTS "${module_abs}/qmldir")
++ continue()
++ endif()
++
++ set(destination_dir "${qml_bundle_dir}/qml/${module_rel}")
++ list(APPEND commands COMMAND ${CMAKE_COMMAND} -E make_directory "${destination_dir}")
++ list(APPEND commands COMMAND ${CMAKE_COMMAND} -E copy_if_different
++ "${module_abs}/qmldir" "${destination_dir}/qmldir")
++ list(APPEND qmldir_inputs "${module_abs}/qmldir")
++ endforeach()
++
++ if(NOT commands)
++ return()
++ endif()
++
++ set(qml_modules_stamp "${android_staging_dir}/${sanitized_target}_copy_qml_modules.stamp")
++ add_custom_command(OUTPUT "${qml_modules_stamp}"
++ ${commands}
++ COMMAND ${CMAKE_COMMAND} -E touch "${qml_modules_stamp}"
++ DEPENDS ${qmldir_inputs}
++ COMMENT "Copying QML modules for ${target}"
++ VERBATIM
++ )
++ add_custom_target(${target}_copy_qml_modules DEPENDS "${qml_modules_stamp}")
++ _qt_internal_android_register_deploy_files(${target} "${qml_modules_stamp}")
++
++ set(extra_args "")
++ if(NOT QT_FEATURE_zstd)
++ list(APPEND extra_args "--no-zstd")
++ endif()
++
++ set(bundle_rcc "${deployment_dir}/assets/android_rcc_bundle.rcc")
++ set(bundle_qrc "${qml_bundle_dir}/android_rcc_bundle.qrc")
++ get_filename_component(bundle_rcc_dir "${bundle_rcc}" DIRECTORY)
++ add_custom_command(OUTPUT "${bundle_rcc}"
++ COMMAND ${CMAKE_COMMAND} -E make_directory "${bundle_rcc_dir}"
++ COMMAND ${CMAKE_COMMAND} -E chdir "${qml_bundle_dir}"
++ "${rcc_path}" --project -o "${bundle_qrc}"
++ COMMAND "${rcc_path}" --binary ${extra_args}
++ --root=/android_rcc_bundle/ -o "${bundle_rcc}" "${bundle_qrc}"
++ DEPENDS "${qml_modules_stamp}"
++ COMMENT "Generating QML resource bundle for ${target}"
++ VERBATIM
++ )
++
++ set_property(TARGET ${target} APPEND PROPERTY _qt_android_deployment_files "${bundle_rcc}")
++ add_custom_target(${target}_build_qml_bundle DEPENDS "${bundle_rcc}")
++ endfunction()