Change the external projects approach for multi-abi builds
Instead of generating external projects that build the project tree for each target, this creates a single project for each ABI that have the common for all targets configure steps. Each executable target then adds additional build step to each ABI-specific external project, that builds and copies dependencies to the "main" project build tree. To resolve dependencies from the build tree, when building multi-abi apk instead of scanning the build directories of external projects for dependencies, it makes sense to run androiddeployqt for each ABI-specific external project to copy all necessary libraries. This is done by adding --copy-dependencies-only flag to androiddeployqt that only copies the apk dependencies, but avoids creating apk and all the essential steps. The ABI-specific external project now handles the deploying of the build artifacts to the end-point apk deployment directory and the "main" project assembles the apk using collected artifacts. The ABI-specific external project uses the qt_internal_${target}_copy_apk_dependencies target to run androiddeployqt with the introduced --copy-dependencies-only flag. TODO: Build steps that build and copy the ABI-specific apk dependencies are non-skipable and will run each time top-level build is triggered. This behavior should be fixed by adding dependencies to the generated by androiddeployqt DEPFILES for each ABI in the top-level build. Task-number: QTBUG-88841 Tash-number: QTBUG-94714 Change-Id: Id442a9fbd589f58b70f4204c5215645056b379a2 Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
parent
0062f5a208
commit
87db26bdfe
@ -92,13 +92,14 @@ function(qt6_android_generate_deployment_settings target)
|
||||
|
||||
set(abi_records "")
|
||||
get_target_property(qt_android_abis ${target} _qt_android_abis)
|
||||
if(qt_android_abis)
|
||||
foreach(abi IN LISTS qt_android_abis)
|
||||
_qt_internal_get_android_abi_path(qt_abi_path ${abi})
|
||||
file(TO_CMAKE_PATH "${qt_abi_path}" qt_android_install_dir_native)
|
||||
list(APPEND abi_records "\"${abi}\": \"${qt_android_install_dir_native}\"")
|
||||
endforeach()
|
||||
if(NOT qt_android_abis)
|
||||
set(qt_android_abis "")
|
||||
endif()
|
||||
foreach(abi IN LISTS qt_android_abis)
|
||||
_qt_internal_get_android_abi_path(qt_abi_path ${abi})
|
||||
file(TO_CMAKE_PATH "${qt_abi_path}" qt_android_install_dir_native)
|
||||
list(APPEND abi_records "\"${abi}\": \"${qt_android_install_dir_native}\"")
|
||||
endforeach()
|
||||
|
||||
# Required to build unit tests in developer build
|
||||
if(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX)
|
||||
@ -336,14 +337,8 @@ function(qt6_android_add_apk_target target)
|
||||
set(dep_file_name "${target}.d")
|
||||
set(apk_final_file_path "${apk_final_dir}/${apk_file_name}")
|
||||
set(dep_file_path "${apk_final_dir}/${dep_file_name}")
|
||||
|
||||
# Temporary location of the library target file. If the library is built as an external project
|
||||
# inside multi-abi build the QT_ANDROID_ABI_TARGET_PATH variable will point to the ABI related
|
||||
# folder in the top-level build directory.
|
||||
set(copy_target_path "${apk_final_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}")
|
||||
if(QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT AND QT_ANDROID_ABI_TARGET_PATH)
|
||||
set(copy_target_path "${QT_ANDROID_ABI_TARGET_PATH}")
|
||||
endif()
|
||||
set(target_file_copy_relative_path
|
||||
"libs/${CMAKE_ANDROID_ARCH_ABI}/$<TARGET_FILE_NAME:${target}>")
|
||||
|
||||
set(extra_deps "")
|
||||
|
||||
@ -362,7 +357,7 @@ function(qt6_android_add_apk_target target)
|
||||
DEPENDS ${target} ${extra_deps}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-E copy_if_different $<TARGET_FILE:${target}>
|
||||
"${copy_target_path}/$<TARGET_FILE_NAME:${target}>"
|
||||
"${apk_final_dir}/$<TARGET_FILE_NAME:${target}>"
|
||||
COMMENT "Copying ${target} binary to apk folder"
|
||||
)
|
||||
|
||||
@ -394,7 +389,7 @@ function(qt6_android_add_apk_target target)
|
||||
add_custom_command(OUTPUT "${apk_final_file_path}"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-E copy "$<TARGET_FILE:${target}>"
|
||||
"${apk_final_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}/$<TARGET_FILE_NAME:${target}>"
|
||||
"${apk_final_dir}/${target_file_copy_relative_path}"
|
||||
COMMAND "${deployment_tool}"
|
||||
--input "${deployment_file}"
|
||||
--output "${apk_final_dir}"
|
||||
@ -436,6 +431,34 @@ function(qt6_android_add_apk_target target)
|
||||
COMMENT "Creating AAB for ${target}"
|
||||
)
|
||||
|
||||
if(QT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT)
|
||||
# When building per-ABI external projects we only need to copy ABI-specific libraries and
|
||||
# resources to the "main" ABI android build folder.
|
||||
|
||||
if("${QT_INTERNAL_ANDROID_MULTI_ABI_BINARY_DIR}" STREQUAL "")
|
||||
message(FATAL_ERROR "QT_INTERNAL_ANDROID_MULTI_ABI_BINARY_DIR is not set when building"
|
||||
" ABI specific external project. This should not happen and might mean an issue"
|
||||
" in Qt. Please report a bug with CMake traces attached.")
|
||||
endif()
|
||||
# Assume that external project mirrors build structure of the top-level ABI project and
|
||||
# replace the build root when specifying the output directory of androiddeployqt.
|
||||
file(RELATIVE_PATH androiddeployqt_output_path "${CMAKE_BINARY_DIR}" "${apk_final_dir}")
|
||||
set(androiddeployqt_output_path
|
||||
"${QT_INTERNAL_ANDROID_MULTI_ABI_BINARY_DIR}/${androiddeployqt_output_path}")
|
||||
add_custom_target(qt_internal_${target}_copy_apk_dependencies
|
||||
DEPENDS ${target} ${extra_deps}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-E copy_if_different $<TARGET_FILE:${target}>
|
||||
"${androiddeployqt_output_path}/${target_file_copy_relative_path}"
|
||||
COMMAND ${deployment_tool}
|
||||
--input ${deployment_file}
|
||||
--output ${androiddeployqt_output_path}
|
||||
--copy-dependencies-only
|
||||
${extra_args}
|
||||
COMMENT "Resolving ${CMAKE_ANDROID_ARCH_ABI} dependencies for the ${target} APK"
|
||||
)
|
||||
endif()
|
||||
|
||||
set_property(GLOBAL APPEND PROPERTY _qt_apk_targets ${target})
|
||||
_qt_internal_collect_target_apk_dependencies_defer(${target})
|
||||
endfunction()
|
||||
|
@ -597,25 +597,42 @@ function(_qt_internal_create_executable target)
|
||||
else()
|
||||
set(config_arg "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
_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")
|
||||
set(abi_copy_target_path "${CMAKE_CURRENT_BINARY_DIR}/android-build/libs/${abi}")
|
||||
ExternalProject_Add("${target}_${abi}"
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${target}_${abi}"
|
||||
CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${qt_abi_toolchain_path}"
|
||||
"-DQT_IS_ANDROID_MULTI_ABI_EXTERNAL_PROJECT=ON"
|
||||
"-DQT_ANDROID_ABI_TARGET_PATH=${abi_copy_target_path}"
|
||||
"${config_arg}"
|
||||
STEP_TARGETS build
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
BUILD_COMMAND "${CMAKE_COMMAND}"
|
||||
"--build" "${CMAKE_CURRENT_BINARY_DIR}/${target}_${abi}"
|
||||
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" "${target}_prepare_apk_dir"
|
||||
"--target" "qt_internal_${target}_copy_apk_dependencies"
|
||||
)
|
||||
add_dependencies(${target} "${target}_${abi}-build")
|
||||
ExternalProject_Add_StepTargets("qt_internal_android_${abi}"
|
||||
"${target}_build")
|
||||
add_dependencies(${target} "qt_internal_android_${abi}-${target}_build")
|
||||
endforeach()
|
||||
|
||||
if(missing_qt_abi_toolchains)
|
||||
|
@ -135,6 +135,7 @@ struct Options
|
||||
bool build;
|
||||
bool auxMode;
|
||||
bool noRccBundleCleanup = false;
|
||||
bool copyDependenciesOnly = false;
|
||||
QElapsedTimer timer;
|
||||
|
||||
// External tools
|
||||
@ -563,6 +564,9 @@ Options parseOptions()
|
||||
} else if (argument.compare(QLatin1String("--no-rcc-bundle-cleanup"),
|
||||
Qt::CaseInsensitive) == 0) {
|
||||
options.noRccBundleCleanup = true;
|
||||
} else if (argument.compare(QLatin1String("--copy-dependencies-only"),
|
||||
Qt::CaseInsensitive) == 0) {
|
||||
options.copyDependenciesOnly = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -687,6 +691,10 @@ void printHelp()
|
||||
" the resource bundle content, but it should not be used when deploying\n"
|
||||
" a project, since it litters the 'assets' directory.\n"
|
||||
"\n"
|
||||
" --copy-dependencies-only: resolve application dependencies and stop\n"
|
||||
" deploying process after all libraries and resources that the\n"
|
||||
" application depends on have been copied.\n"
|
||||
"\n"
|
||||
" --help: Displays this information.\n",
|
||||
qPrintable(QCoreApplication::arguments().at(0))
|
||||
);
|
||||
@ -2347,7 +2355,7 @@ bool copyQtFiles(Options *options)
|
||||
if (options->verbose) {
|
||||
switch (options->deploymentMechanism) {
|
||||
case Options::Bundled:
|
||||
fprintf(stdout, "Copying %zd dependencies from Qt into package.\n", size_t(options->qtDependencies.size()));
|
||||
fprintf(stdout, "Copying %zd dependencies from Qt into package.\n", size_t(options->qtDependencies[options->currentArchitecture].size()));
|
||||
break;
|
||||
};
|
||||
}
|
||||
@ -3163,7 +3171,7 @@ int main(int argc, char *argv[])
|
||||
options.setCurrentQtArchitecture(it.key(), it.value().qtInstallDirectory);
|
||||
|
||||
// All architectures have a copy of the gradle files but only one set needs to be copied.
|
||||
if (!androidTemplatetCopied && options.build && !options.auxMode) {
|
||||
if (!androidTemplatetCopied && options.build && !options.auxMode && !options.copyDependenciesOnly) {
|
||||
cleanAndroidFiles(options);
|
||||
if (Q_UNLIKELY(options.timing))
|
||||
fprintf(stdout, "[TIMING] %lld ns: Cleaned Android file\n", options.timer.nsecsElapsed());
|
||||
@ -3218,6 +3226,10 @@ int main(int argc, char *argv[])
|
||||
fprintf(stdout, "[TIMING] %lld ns: Bundled Qt libs\n", options.timer.nsecsElapsed());
|
||||
}
|
||||
|
||||
if (options.copyDependenciesOnly) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!createRcc(options))
|
||||
return CannotCreateRcc;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user