Replace ANDROID_ABI argument with the QT_ANDROID_ABI target property

This change tries to make the API more user friendly and prevent wrong
use of multi-abi API. ANDROID_ABI argument of qt6_add_executable was
position-depend and needed to be placed after the executable 'sources'.
Using the target property we solve this problem and provide more
consistent and common way to enable multi-abi build for the single
target.

This meanwhile also requires to execute multi-abi build configuration
in the finalizer, since the property might be set at any point.

Also the priority of the QT_ANDROID_ABI target property now is higher
than the priority of the QT_ANDROID_BUILD_ALL_ABIS variable. So target
will only build packages with the ABIs specified in QT_ANDROID_ABI
property if both are set.

Pick-to: 6.3
Task-number: QTBUG-88841
Change-Id: I3515297ed267974498913c59619433dc234ec217
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Alexey Edelev 2021-12-17 13:02:04 +01:00
parent 612417ea70
commit f90221d8cd
4 changed files with 122 additions and 104 deletions

View File

@ -75,6 +75,15 @@ define_property(TARGET
"Qt Module android feature list."
)
define_property(TARGET
PROPERTY
QT_ANDROID_ABIS
BRIEF_DOCS
"List of ABIs that the target packages are built with."
FULL_DOCS
"List of ABIs that the target packages are built with."
)
function(qt_internal_android_dependencies_content target file_content_out)
get_target_property(arg_JAR_DEPENDENCIES ${target} QT_ANDROID_JAR_DEPENDENCIES)
get_target_property(arg_BUNDLED_JAR_DEPENDENCIES ${target} QT_ANDROID_BUNDLED_JAR_DEPENDENCIES)

View File

@ -21,6 +21,7 @@ function(qt_internal_add_executable name)
_qt_internal_create_executable(${name})
if (ANDROID)
_qt_internal_configure_android_multiabi_target("${name}")
qt_android_generate_deployment_settings("${name}")
qt_android_add_apk_target("${name}")
endif()

View File

@ -795,3 +795,111 @@ function(_qt_internal_collect_default_android_abis)
"Build project using the list of autodetected Qt for Android ABIs"
)
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.
function(_qt_internal_configure_android_multiabi_target target)
# Functionality is only applicable for the primary ABI
if(QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT)
return()
endif()
get_target_property(target_abis ${target} QT_ANDROID_ABIS)
if(target_abis)
# Use target-specific Qt for Android ABIs.
set(android_abis ${target_abis})
elseif(QT_ANDROID_BUILD_ALL_ABIS)
# Use autodetected Qt for Android ABIs.
set(android_abis ${QT_DEFAULT_ANDROID_ABIS})
elseif(QT_ANDROID_ABIS)
# Use project-wide Qt for Android ABIs.
set(android_abis ${QT_ANDROID_ABIS})
else()
# User have an empty list of Qt for Android ABIs.
message(FATAL_ERROR
"The list of Android ABIs is empty, when building ${target}.\n"
"You have the following options to select ABIs for a target:\n"
" - Set the QT_ANDROID_ABIS variable before calling qt6_add_executable\n"
" - Set the ANDROID_ABIS property for ${target}\n"
" - Set QT_ANDROID_BUILD_ALL_ABIS flag to try building with\n"
" the list of autodetected Qt for Android:\n ${QT_DEFAULT_ANDROID_ABIS}"
)
endif()
set(missing_qt_abi_toolchains "")
# 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})
list(REMOVE_ITEM android_abis "${abi}")
continue()
endif()
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
if(is_multi_config)
list(JOIN CMAKE_CONFIGURATION_TYPES "$<SEMICOLON>" escaped_configuration_types)
set(config_arg "-DCMAKE_CONFIGURATION_TYPES=${escaped_configuration_types}")
else()
set(config_arg "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
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_get_android_abi_path(qt_abi_path ${abi})
set(qt_abi_toolchain_path
"${qt_abi_path}/lib/cmake/${QT_CMAKE_EXPORT_NAMESPACE}/qt.toolchain.cmake")
ExternalProject_Add("qt_internal_android_${abi}"
SOURCE_DIR "${CMAKE_SOURCE_DIR}"
BINARY_DIR "${android_abi_build_dir}"
CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${qt_abi_toolchain_path}"
"-DQT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT=ON"
"-DQT_INTERNAL_ANDROID_MULTI_ABI_BINARY_DIR=${CMAKE_BINARY_DIR}"
"${config_arg}"
EXCLUDE_FROM_ALL TRUE
STETPS_TARGETS
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
COMMAND "${CMAKE_COMMAND}"
"--build" "${android_abi_build_dir}"
"--config" "$<CONFIG>"
"--target" "qt_internal_${target}_copy_apk_dependencies"
)
ExternalProject_Add_StepTargets("qt_internal_android_${abi}"
"${target}_build")
add_dependencies(${target} "qt_internal_android_${abi}-${target}_build")
endforeach()
if(missing_qt_abi_toolchains)
list(JOIN missing_qt_abi_toolchains ", " missing_qt_abi_toolchains_string)
message(FATAL_ERROR "Cannot find toolchain files for the manually specified Android"
" ABIs: ${missing_qt_abi_toolchains_string}"
"\nNote that you also may manually specify the path to the required Qt for"
" Android ABI using QT_PATH_ANDROID_ABI_<abi> CMake variable.\n")
endif()
list(JOIN android_abis ", " android_abis_string)
if(android_abis_string)
set(android_abis_string "${CMAKE_ANDROID_ARCH_ABI}(default), ${android_abis_string}")
else()
set(android_abis_string "${CMAKE_ANDROID_ARCH_ABI}(default)")
endif()
if(NOT QT_NO_ANDROID_ABI_STATUS_MESSAGE)
message(STATUS "Configuring '${target}' for the following Android ABIs:"
" ${android_abis_string}")
endif()
set_target_properties(${target} PROPERTIES _qt_android_abis "${android_abis}")
endfunction()

View File

@ -542,10 +542,9 @@ function(qt6_add_executable target)
endfunction()
function(_qt_internal_create_executable target)
cmake_parse_arguments(arg "" "" "ANDROID_ABIS" ${ARGN})
if(ANDROID)
list(REMOVE_ITEM arg_UNPARSED_ARGUMENTS "WIN32" "MACOSX_BUNDLE")
add_library("${target}" MODULE ${arg_UNPARSED_ARGUMENTS})
list(REMOVE_ITEM ARGN "WIN32" "MACOSX_BUNDLE")
add_library("${target}" MODULE ${ARGN})
# On our qmake builds we do don't compile the executables with
# visibility=hidden. Not having this flag set will cause the
# executable to have main() hidden and can then no longer be loaded
@ -556,108 +555,8 @@ function(_qt_internal_create_executable target)
set_property(TARGET "${target}" PROPERTY OBJCXX_VISIBILITY_PRESET default)
qt6_android_apply_arch_suffix("${target}")
set_property(TARGET "${target}" PROPERTY _qt_is_android_executable TRUE)
# Build per-abi binaries for android
if(NOT QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT)
if(QT_ANDROID_BUILD_ALL_ABIS)
# Use autodetected Qt for Android ABIs.
set(android_abis ${QT_DEFAULT_ANDROID_ABIS})
elseif(arg_ANDROID_ABIS)
# Use target-specific Qt for Android ABIs.
set(android_abis ${arg_ANDROID_ABIS})
elseif(QT_ANDROID_ABIS)
# Use project-wide Qt for Android ABIs.
set(android_abis ${QT_ANDROID_ABIS})
else()
# User have an empty list of Qt for Android ABIs.
message(FATAL_ERROR
"The list of Android ABIs is empty, when building ${target}.\n"
"You have the following options to select ABIs for a target:\n"
" - Set the QT_ANDROID_ABIS variable before calling qt6_add_executable\n"
" - Add the ANDROID_ABIS parameter to the qt6_add_executable call\n"
" - Set QT_ANDROID_BUILD_ALL_ABIS flag to try building with\n"
" the list of autodetected Qt for Android:\n ${QT_DEFAULT_ANDROID_ABIS}"
)
endif()
set(missing_qt_abi_toolchains "")
# 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})
list(REMOVE_ITEM android_abis "${abi}")
continue()
endif()
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
if(is_multi_config)
list(JOIN CMAKE_CONFIGURATION_TYPES "$<SEMICOLON>" escaped_configuration_types)
set(config_arg "-DCMAKE_CONFIGURATION_TYPES=${escaped_configuration_types}")
else()
set(config_arg "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
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_get_android_abi_path(qt_abi_path ${abi})
set(qt_abi_toolchain_path
"${qt_abi_path}/lib/cmake/${QT_CMAKE_EXPORT_NAMESPACE}/qt.toolchain.cmake")
ExternalProject_Add("qt_internal_android_${abi}"
SOURCE_DIR "${CMAKE_SOURCE_DIR}"
BINARY_DIR "${android_abi_build_dir}"
CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${qt_abi_toolchain_path}"
"-DQT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT=ON"
"-DQT_INTERNAL_ANDROID_MULTI_ABI_BINARY_DIR=${CMAKE_BINARY_DIR}"
"${config_arg}"
EXCLUDE_FROM_ALL TRUE
STETPS_TARGETS
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
COMMAND "${CMAKE_COMMAND}"
"--build" "${android_abi_build_dir}"
"--config" "$<CONFIG>"
"--target" "qt_internal_${target}_copy_apk_dependencies"
)
ExternalProject_Add_StepTargets("qt_internal_android_${abi}"
"${target}_build")
add_dependencies(${target} "qt_internal_android_${abi}-${target}_build")
endforeach()
if(missing_qt_abi_toolchains)
list(JOIN missing_qt_abi_toolchains ", " missing_qt_abi_toolchains_string)
message(FATAL_ERROR "Cannot find toolchain files for the manually specified Android"
" ABIs: ${missing_qt_abi_toolchains_string}"
"\nSkipping these ABIs."
"\nNote that you also may manually specify the path to the required Qt for"
" Android ABI using QT_PATH_ANDROID_ABI_<abi> CMake variable.\n")
endif()
list(JOIN android_abis ", " android_abis_string)
if(android_abis_string)
set(android_abis_string "${CMAKE_ANDROID_ARCH_ABI}(default), ${android_abis_string}")
else()
set(android_abis_string "${CMAKE_ANDROID_ARCH_ABI}(default)")
endif()
if(NOT QT_NO_ANDROID_ABI_STATUS_MESSAGE)
message(STATUS "Configuring '${target}' for the following Android ABIs:"
" ${android_abis_string}")
endif()
set_target_properties(${target} PROPERTIES _qt_android_abis "${android_abis}")
endif()
else()
add_executable("${target}" ${arg_UNPARSED_ARGUMENTS})
add_executable("${target}" ${ARGN})
endif()
_qt_internal_set_up_static_runtime_library("${target}")
@ -719,6 +618,7 @@ function(_qt_internal_finalize_executable target)
endif()
if(ANDROID)
_qt_internal_configure_android_multiabi_target("${target}")
qt6_android_generate_deployment_settings("${target}")
qt6_android_add_apk_target("${target}")
endif()