Support deploying of libraries from a build tree when building android apk
If the project consists of an executable and multiple libraries that are linked to the executable, currently you need to specify them manually using QT_ANDROID_EXTRA_LIBS target property. This automates deploying of the libraries that are a part of the project build tree. _qt_internal_collect_target_apk_dependencies collects all the known non-imported shared libraries from the project build tree. When running androiddeployqt we specify extra library directories that point to the collected library locations in build tree, to help androiddeployqt resolve shared libraries that are build as a part of the project. The described procedure is running automatically if CMake version is greater than or equal to 3.18 is. For the CMake versions less than 3.18 users need to call a new public qt_finalize_project function at the end of project's top-level CMakeLists.txt Task-number: QTBUG-94714 Change-Id: I400ca4e49e940cfc25ae90d65372e79825bee55a Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
2b8a6d026d
commit
d20f4ae706
@ -19,6 +19,15 @@ endfunction()
|
|||||||
|
|
||||||
# Generate the deployment settings json file for a cmake target.
|
# Generate the deployment settings json file for a cmake target.
|
||||||
function(qt6_android_generate_deployment_settings target)
|
function(qt6_android_generate_deployment_settings target)
|
||||||
|
# Avoid calling the function twice
|
||||||
|
get_target_property(is_called ${target} _qt_is_android_generate_deployment_settings_called)
|
||||||
|
if(is_called)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set_target_properties(${target} PROPERTIES
|
||||||
|
_qt_is_android_generate_deployment_settings_called TRUE
|
||||||
|
)
|
||||||
|
|
||||||
# Information extracted from mkspecs/features/android/android_deployment_settings.prf
|
# Information extracted from mkspecs/features/android/android_deployment_settings.prf
|
||||||
if (NOT TARGET ${target})
|
if (NOT TARGET ${target})
|
||||||
message(SEND_ERROR "${target} is not a cmake target")
|
message(SEND_ERROR "${target} is not a cmake target")
|
||||||
@ -140,12 +149,12 @@ function(qt6_android_generate_deployment_settings target)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# package source dir
|
# package source dir
|
||||||
get_target_property(android_package_source_dir ${target} QT_ANDROID_PACKAGE_SOURCE_DIR)
|
set(android_package_source_dir_genex
|
||||||
if (android_package_source_dir)
|
"$<TARGET_PROPERTY:${target},QT_ANDROID_PACKAGE_SOURCE_DIR>")
|
||||||
file(TO_CMAKE_PATH "${android_package_source_dir}" android_package_source_dir_native)
|
string(APPEND file_contents
|
||||||
string(APPEND file_contents
|
"$<$<BOOL:${android_package_source_dir_genex}>:"
|
||||||
" \"android-package-source-directory\": \"${android_package_source_dir_native}\",\n")
|
" \"android-package-source-directory\": \"${android_package_source_dir_genex}\"\,\n"
|
||||||
endif()
|
">")
|
||||||
|
|
||||||
# version code
|
# version code
|
||||||
get_target_property(android_version_code ${target} QT_ANDROID_VERSION_CODE)
|
get_target_property(android_version_code ${target} QT_ANDROID_VERSION_CODE)
|
||||||
@ -235,13 +244,34 @@ function(qt6_android_generate_deployment_settings target)
|
|||||||
foreach(prefix IN LISTS CMAKE_FIND_ROOT_PATH)
|
foreach(prefix IN LISTS CMAKE_FIND_ROOT_PATH)
|
||||||
if (NOT "${prefix}" STREQUAL "${qt_android_install_dir_native}"
|
if (NOT "${prefix}" STREQUAL "${qt_android_install_dir_native}"
|
||||||
AND NOT "${prefix}" STREQUAL "${android_ndk_root_native}")
|
AND NOT "${prefix}" STREQUAL "${android_ndk_root_native}")
|
||||||
list(APPEND extra_prefix_list \"${prefix}\")
|
list(APPEND extra_prefix_list "\"${prefix}\"")
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
string (REPLACE ";" "," extra_prefix_list "${extra_prefix_list}")
|
string (REPLACE ";" "," extra_prefix_list "${extra_prefix_list}")
|
||||||
string(APPEND file_contents
|
string(APPEND file_contents
|
||||||
" \"extraPrefixDirs\" : [ ${extra_prefix_list} ],\n")
|
" \"extraPrefixDirs\" : [ ${extra_prefix_list} ],\n")
|
||||||
|
|
||||||
|
# Extra library paths that could be used as a dependency lookup path by androiddeployqt.
|
||||||
|
#
|
||||||
|
# Unlike 'extraPrefixDirs', the 'extraLibraryDirs' key doesn't expect the 'lib' subfolder
|
||||||
|
# when looking for dependencies.
|
||||||
|
set(extra_library_dirs_property_genex
|
||||||
|
"$<TARGET_PROPERTY:${target},_qt_android_extra_library_dirs>"
|
||||||
|
)
|
||||||
|
set(extra_library_dirs_add_quote_genex
|
||||||
|
"$<$<BOOL:${extra_library_dirs_property_genex}>:\">"
|
||||||
|
)
|
||||||
|
string(JOIN "" extra_library_dirs
|
||||||
|
"${extra_library_dirs_add_quote_genex}"
|
||||||
|
"$<JOIN:"
|
||||||
|
"$<GENEX_EVAL:${extra_library_dirs_property_genex}>,"
|
||||||
|
"\",\""
|
||||||
|
">"
|
||||||
|
"${extra_library_dirs_add_quote_genex}"
|
||||||
|
)
|
||||||
|
string(APPEND file_contents
|
||||||
|
" \"extraLibraryDirs\" : [ ${extra_library_dirs} ],\n")
|
||||||
|
|
||||||
if(QT_FEATURE_zstd)
|
if(QT_FEATURE_zstd)
|
||||||
set(is_zstd_enabled "true")
|
set(is_zstd_enabled "true")
|
||||||
else()
|
else()
|
||||||
@ -261,7 +291,7 @@ function(qt6_android_generate_deployment_settings target)
|
|||||||
# content end
|
# content end
|
||||||
string(APPEND file_contents "}\n")
|
string(APPEND file_contents "}\n")
|
||||||
|
|
||||||
file(WRITE ${deploy_file} ${file_contents})
|
file(GENERATE OUTPUT ${deploy_file} CONTENT ${file_contents})
|
||||||
|
|
||||||
set_target_properties(${target}
|
set_target_properties(${target}
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
@ -358,6 +388,8 @@ function(qt6_android_add_apk_target target)
|
|||||||
COMMENT "Creating APK for ${target}"
|
COMMENT "Creating APK for ${target}"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
set_property(GLOBAL APPEND PROPERTY _qt_apk_targets ${target})
|
||||||
|
_qt_internal_collect_target_apk_dependencies_defer(${target})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(_qt_internal_create_global_apk_target)
|
function(_qt_internal_create_global_apk_target)
|
||||||
@ -371,6 +403,89 @@ function(_qt_internal_create_global_apk_target)
|
|||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
# The function collects all known non-imported shared libraries that are created in the build tree.
|
||||||
|
# It uses the CMake DEFER CALL feature if the CMAKE_VERSION is greater
|
||||||
|
# than or equal to 3.18.
|
||||||
|
# Note: Users that use cmake version less that 3.18 need to call qt_finalize_project
|
||||||
|
# in the end of a project's top-level CMakeLists.txt.
|
||||||
|
function(_qt_internal_collect_target_apk_dependencies_defer target)
|
||||||
|
# User opted-out the functionality
|
||||||
|
if(QT_NO_COLLECT_BUILD_TREE_APK_DEPS)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_property(is_called GLOBAL PROPERTY _qt_is_collect_target_apk_dependencies_defer_called)
|
||||||
|
if(is_called) # Already scheduled
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set_property(GLOBAL PROPERTY _qt_is_collect_target_apk_dependencies_defer_called TRUE)
|
||||||
|
|
||||||
|
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
|
||||||
|
cmake_language(EVAL CODE "cmake_language(DEFER DIRECTORY \"${CMAKE_SOURCE_DIR}\"
|
||||||
|
CALL _qt_internal_collect_target_apk_dependencies ${target})")
|
||||||
|
else()
|
||||||
|
# User don't want to see the warning
|
||||||
|
if(NOT QT_NO_WARN_BUILD_TREE_APK_DEPS)
|
||||||
|
message(WARNING "CMake version you use is less than 3.18. APK dependencies, that are a"
|
||||||
|
" part of the project tree, might not be collected correctly."
|
||||||
|
" Please call qt_finalize_project in the end of a project's top-level"
|
||||||
|
" CMakeLists.txt file to make sure that all the APK dependencies are"
|
||||||
|
" collected correctly."
|
||||||
|
" You can pass -DQT_NO_WARN_BUILD_TREE_APK_DEPS=ON when configuring the project"
|
||||||
|
" to silence the warning.")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# The function collects shared libraries from the build system tree, that might be dependencies for
|
||||||
|
# the main apk targets.
|
||||||
|
function(_qt_internal_collect_target_apk_dependencies target)
|
||||||
|
# User opted-out the functionality
|
||||||
|
if(QT_NO_COLLECT_BUILD_TREE_APK_DEPS)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_property(is_called GLOBAL PROPERTY _qt_is_collect_target_apk_dependencies_called)
|
||||||
|
if(is_called)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set_property(GLOBAL PROPERTY _qt_is_collect_target_apk_dependencies_called TRUE)
|
||||||
|
|
||||||
|
get_property(apk_targets GLOBAL PROPERTY _qt_apk_targets)
|
||||||
|
|
||||||
|
_qt_internal_collect_buildsystem_shared_libraries(libs "${CMAKE_SOURCE_DIR}")
|
||||||
|
|
||||||
|
foreach(lib IN LISTS libs)
|
||||||
|
if(NOT lib IN_LIST apk_targets)
|
||||||
|
list(APPEND extra_prefix_dirs "$<TARGET_FILE_DIR:${lib}>")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set_target_properties(${target} PROPERTIES _qt_android_extra_library_dirs "${extra_prefix_dirs}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# The function recursively goes through the project subfolders and collects targets that supposed to
|
||||||
|
# be shared libraries of any kind.
|
||||||
|
function(_qt_internal_collect_buildsystem_shared_libraries out_var subdir)
|
||||||
|
set(result "")
|
||||||
|
get_directory_property(buildsystem_targets DIRECTORY ${subdir} BUILDSYSTEM_TARGETS)
|
||||||
|
foreach(buildsystem_target IN LISTS buildsystem_targets)
|
||||||
|
if(buildsystem_target AND TARGET ${buildsystem_target})
|
||||||
|
get_target_property(target_type ${buildsystem_target} TYPE)
|
||||||
|
if(target_type STREQUAL "SHARED_LIBRARY" OR target_type STREQUAL "MODULE_LIBRARY")
|
||||||
|
list(APPEND result ${buildsystem_target})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
get_directory_property(subdirs DIRECTORY "${subdir}" SUBDIRECTORIES)
|
||||||
|
foreach(dir IN LISTS subdirs)
|
||||||
|
_qt_internal_collect_buildsystem_shared_libraries(result_inner "${dir}")
|
||||||
|
endforeach()
|
||||||
|
list(APPEND result ${result_inner})
|
||||||
|
set(${out_var} "${result}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
# This function allows deciding whether apks should be built as part of the ALL target at first
|
# This function allows deciding whether apks should be built as part of the ALL target at first
|
||||||
# add_executable call point, rather than when the 'apk' target is created as part of the
|
# add_executable call point, rather than when the 'apk' target is created as part of the
|
||||||
# find_package(Core) call.
|
# find_package(Core) call.
|
||||||
|
@ -2238,7 +2238,28 @@ function(qt6_disable_unicode_defines target)
|
|||||||
set_target_properties(${target} PROPERTIES QT_NO_UNICODE_DEFINES TRUE)
|
set_target_properties(${target} PROPERTIES QT_NO_UNICODE_DEFINES TRUE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
# Finalizer function for the top-level user projects.
|
||||||
|
#
|
||||||
|
# This function is currently in Technical Preview.
|
||||||
|
# Its signature and behavior might change.
|
||||||
|
function(qt6_finalize_project)
|
||||||
|
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||||
|
message("qt6_finalize_project is called not in the top-level CMakeLists.txt.")
|
||||||
|
endif()
|
||||||
|
if(ANDROID)
|
||||||
|
_qt_internal_collect_target_apk_dependencies()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
|
||||||
|
function(qt_finalize_project)
|
||||||
|
if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
|
||||||
|
qt6_finalize_project()
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "qt_finalize_project() is only available in Qt 6.")
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
function(qt_disable_unicode_defines)
|
function(qt_disable_unicode_defines)
|
||||||
qt6_disable_unicode_defines(${ARGV})
|
qt6_disable_unicode_defines(${ARGV})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
@ -166,6 +166,9 @@ struct Options
|
|||||||
// Build paths
|
// Build paths
|
||||||
QString qtInstallDirectory;
|
QString qtInstallDirectory;
|
||||||
std::vector<QString> extraPrefixDirs;
|
std::vector<QString> extraPrefixDirs;
|
||||||
|
// Unlike 'extraPrefixDirs', the 'extraLibraryDirs' key doesn't expect the 'lib' subfolder
|
||||||
|
// when looking for dependencies.
|
||||||
|
std::vector<QString> extraLibraryDirs;
|
||||||
QString androidSourceDirectory;
|
QString androidSourceDirectory;
|
||||||
QString outputDirectory;
|
QString outputDirectory;
|
||||||
QString inputFileName;
|
QString inputFileName;
|
||||||
@ -921,6 +924,14 @@ bool readInputFile(Options *options)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto extraLibraryDirs = jsonObject.value(QLatin1String("extraLibraryDirs")).toArray();
|
||||||
|
options->extraLibraryDirs.reserve(extraLibraryDirs.size());
|
||||||
|
for (const QJsonValue path : extraLibraryDirs) {
|
||||||
|
options->extraLibraryDirs.push_back(path.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const QJsonValue androidSourcesDirectory = jsonObject.value(QLatin1String("android-package-source-directory"));
|
const QJsonValue androidSourcesDirectory = jsonObject.value(QLatin1String("android-package-source-directory"));
|
||||||
if (!androidSourcesDirectory.isUndefined())
|
if (!androidSourcesDirectory.isUndefined())
|
||||||
@ -1607,6 +1618,17 @@ bool updateAndroidFiles(Options &options)
|
|||||||
|
|
||||||
static QString absoluteFilePath(const Options *options, const QString &relativeFileName)
|
static QString absoluteFilePath(const Options *options, const QString &relativeFileName)
|
||||||
{
|
{
|
||||||
|
// Use extraLibraryDirs as the extra library lookup folder if it is expected to find a file in
|
||||||
|
// any $prefix/lib folder.
|
||||||
|
// Library directories from a build tree(extraLibraryDirs) have the higher priority.
|
||||||
|
if (relativeFileName.startsWith(QLatin1String("lib/"))) {
|
||||||
|
for (const auto &dir : options->extraLibraryDirs) {
|
||||||
|
const QString path = dir + QLatin1Char('/') + relativeFileName.mid(sizeof("lib/") - 1);
|
||||||
|
if (QFile::exists(path))
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &prefix : options->extraPrefixDirs) {
|
for (const auto &prefix : options->extraPrefixDirs) {
|
||||||
const QString path = prefix + QLatin1Char('/') + relativeFileName;
|
const QString path = prefix + QLatin1Char('/') + relativeFileName;
|
||||||
if (QFile::exists(path))
|
if (QFile::exists(path))
|
||||||
|
Loading…
Reference in New Issue
Block a user