diff --git a/src/corelib/Qt6AndroidMacros.cmake b/src/corelib/Qt6AndroidMacros.cmake index 08366d89f7b..62fe1097b3b 100644 --- a/src/corelib/Qt6AndroidMacros.cmake +++ b/src/corelib/Qt6AndroidMacros.cmake @@ -576,7 +576,7 @@ function(qt6_android_add_apk_target target) "$" "${androiddeployqt_output_path}/${target_file_copy_relative_path}" ) - if(has_depfile_support AND FALSE) # TODO: It breaks multi-abi builds. See QTBUG-122838 + if(has_depfile_support) set(deploy_android_deps_dir "${apk_final_dir}/${target}_deploy_android") set(timestamp_file "${deploy_android_deps_dir}/timestamp") set(dep_file "${deploy_android_deps_dir}/${target}.d") @@ -1183,6 +1183,91 @@ function(_qt_internal_collect_default_android_abis) ) endfunction() +# Returns a path to the timestamp file for the specific step of the multi-ABI Android project +function(_qt_internal_get_android_abi_step_stampfile out project abi step) + get_target_property(build_dir ${project} _qt_android_build_directory) + get_property(is_multi GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi) + set(${out} "${build_dir}/$/${project}_${step}_stamp" PARENT_SCOPE) + else() + set(${out} "${build_dir}/${project}_${step}_stamp" PARENT_SCOPE) + endif() +endfunction() + +# Creates the multi-ABI Android projects and assigns the JOB_POOL to them if it's possible +function(_qt_internal_add_android_abi_project project abi) + add_custom_target(${project}) + + set(build_dir "${CMAKE_BINARY_DIR}/android_abi_builds/${abi}") + set_target_properties(${project} PROPERTIES + _qt_android_build_directory "${build_dir}" + ) + + file(MAKE_DIRECTORY "${build_dir}") + if(CMAKE_GENERATOR MATCHES "^Ninja") + set_property(GLOBAL APPEND PROPERTY JOB_POOLS _qt_android_${project}_pool=1) + endif() +endfunction() + +# Adds the custom build step to the multi-ABI Android project +function(_qt_internal_add_android_abi_step project abi step) + cmake_parse_arguments(arg "" "" "COMMAND;DEPENDS" ${ARGV}) + + if(NOT arg_COMMAND) + message(FATAL_ERROR "COMMAND is not set for ${project} step ${step} Android ABI ${abi}.") + endif() + + set(dep_stamps "") + foreach(dep ${arg_DEPENDS}) + _qt_internal_get_android_abi_step_stampfile(stamp ${project} ${abi} ${dep}) + list(APPEND dep_stamps "${stamp}") + endforeach() + + get_target_property(build_dir ${project} _qt_android_build_directory) + + if(CMAKE_GENERATOR MATCHES "^Ninja") + set(add_to_pool JOB_POOL _qt_android_${project}_pool) + else() + set(add_to_pool "") + endif() + + _qt_internal_get_android_abi_step_stampfile(stamp ${project} ${abi} ${step}) + add_custom_command(OUTPUT "${stamp}" + COMMAND ${arg_COMMAND} + COMMAND "${CMAKE_COMMAND}" -E touch "${stamp}" + ${add_to_pool} + DEPENDS + ${dep_stamps} + WORKING_DIRECTORY + "${build_dir}" + VERBATIM + ) + add_custom_target("${project}_${step}" DEPENDS "${stamp}") + + get_target_property(known_steps ${project} _qt_android_abi_steps) + if(NOT CMAKE_GENERATOR MATCHES "^Ninja") + if(NOT QT_NO_WARN_ANDROID_MULTI_ABI_GENERATOR) + get_property(is_warned GLOBAL PROPERTY _qt_internal_warn_android_multi_abi_generator) + if(NOT is_warned) + set_property(GLOBAL PROPERTY _qt_internal_warn_android_multi_abi_generator TRUE) + message(WARNING "Building Multi-ABI Qt projects with the '${CMAKE_GENERATOR}'" + " generator has limitations. All targets from non-main ABI will be built" + " unconditionally. Please use the 'Ninja' or 'Ninja Multi-config' generators" + " with ninja build instead. Set QT_NO_WARN_ANDROID_MULTI_ABI_GENERATOR to" + " 'TRUE' to suppress this warning." + ) + endif() + endif() + if(known_steps) + list(GET known_steps 0 first) + add_dependencies(${first} ${project}_${step}) + endif() + endif() + + list(PREPEND known_steps ${project}_${step}) + set_target_properties(${project} PROPERTIES _qt_android_abi_steps "${known_steps}") +endfunction() + # The function configures external projects for ABIs that target packages need to build with. # Each target adds build step to the external project that is linked to the # qt_internal_android_${abi}-${target}_build target in the primary ABI build tree. @@ -1292,7 +1377,6 @@ function(_qt_internal_configure_android_multiabi_target target) set(previous_copy_apk_dependencies_target ${target}) # Create external projects for each android ABI except the main one. list(REMOVE_ITEM android_abis "${CMAKE_ANDROID_ARCH_ABI}") - include(ExternalProject) foreach(abi IN ITEMS ${android_abis}) if(NOT "${abi}" IN_LIST QT_DEFAULT_ANDROID_ABIS) list(APPEND missing_qt_abi_toolchains ${abi}) @@ -1300,16 +1384,17 @@ function(_qt_internal_configure_android_multiabi_target target) continue() endif() - set(android_abi_build_dir "${CMAKE_BINARY_DIR}/android_abi_builds/${abi}") get_property(abi_external_projects GLOBAL PROPERTY _qt_internal_abi_external_projects) if(NOT abi_external_projects OR NOT "qt_internal_android_${abi}" IN_LIST abi_external_projects) + _qt_internal_add_android_abi_project(qt_internal_android_${abi} ${abi}) + + get_target_property(android_abi_build_dir qt_internal_android_${abi} + _qt_android_build_directory) _qt_internal_get_android_abi_toolchain_path(qt_abi_toolchain_path ${abi}) - ExternalProject_Add("qt_internal_android_${abi}" - SOURCE_DIR "${CMAKE_SOURCE_DIR}" - BINARY_DIR "${android_abi_build_dir}" - CONFIGURE_COMMAND + _qt_internal_add_android_abi_step(qt_internal_android_${abi} ${abi} configure + COMMAND "${CMAKE_COMMAND}" "-G${CMAKE_GENERATOR}" "-DCMAKE_TOOLCHAIN_FILE=${qt_abi_toolchain_path}" @@ -1321,44 +1406,36 @@ function(_qt_internal_configure_android_multiabi_target target) "${user_cmake_args}" "-B" "${android_abi_build_dir}" "-S" "${CMAKE_SOURCE_DIR}" - EXCLUDE_FROM_ALL TRUE - BUILD_COMMAND "" # avoid top-level build of external project ) set_property(GLOBAL APPEND PROPERTY _qt_internal_abi_external_projects "qt_internal_android_${abi}") endif() - ExternalProject_Add_Step("qt_internal_android_${abi}" - "${target}_build" - DEPENDEES configure - # TODO: Remove this when the step will depend on DEPFILE generated by - # androiddeployqt for the ${target}. - ALWAYS TRUE - EXCLUDE_FROM_MAIN TRUE - COMMAND "${CMAKE_COMMAND}" - "--build" "${android_abi_build_dir}" - "--config" "$" - "--target" "${target}" - ) - ExternalProject_Add_StepTargets("qt_internal_android_${abi}" - "${target}_build") - add_dependencies(${target} "qt_internal_android_${abi}-${target}_build") - ExternalProject_Add_Step("qt_internal_android_${abi}" - "${target}_copy_apk_dependencies" - DEPENDEES "${target}_build" - # TODO: Remove this when the step will depend on DEPFILE generated by - # androiddeployqt for the ${target}. - ALWAYS TRUE - EXCLUDE_FROM_MAIN TRUE - COMMAND "${CMAKE_COMMAND}" - "--build" "${android_abi_build_dir}" - "--config" "$" - "--target" "qt_internal_${target}_copy_apk_dependencies" + get_target_property(android_abi_build_dir qt_internal_android_${abi} + _qt_android_build_directory) + _qt_internal_add_android_abi_step(qt_internal_android_${abi} ${abi} ${target}_build + DEPENDS + configure + COMMAND + "${CMAKE_COMMAND}" + --build "${android_abi_build_dir}" + --config $ + --target ${target} + ) + add_dependencies(${target} "qt_internal_android_${abi}_${target}_build") + + _qt_internal_add_android_abi_step(qt_internal_android_${abi} ${abi} + ${target}_copy_apk_dependencies + DEPENDS + ${target}_build + COMMAND + "${CMAKE_COMMAND}" + --build "${android_abi_build_dir}" + --config $ + --target qt_internal_${target}_copy_apk_dependencies ) - ExternalProject_Add_StepTargets("qt_internal_android_${abi}" - "${target}_copy_apk_dependencies") set(external_project_copy_target - "qt_internal_android_${abi}-${target}_copy_apk_dependencies") + "qt_internal_android_${abi}_${target}_copy_apk_dependencies") # Need to build dependency chain between the # qt_internal_android_${abi}-${target}_copy_apk_dependencies targets for all ABI's, to