diff options
Diffstat (limited to 'cmake/QtPlatformAndroid.cmake')
-rw-r--r-- | cmake/QtPlatformAndroid.cmake | 371 |
1 files changed, 98 insertions, 273 deletions
diff --git a/cmake/QtPlatformAndroid.cmake b/cmake/QtPlatformAndroid.cmake index dd76b1e81e..e4253b75d7 100644 --- a/cmake/QtPlatformAndroid.cmake +++ b/cmake/QtPlatformAndroid.cmake @@ -1,26 +1,22 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + # # Self contained Platform Settings for Android # -# Note: This file is used both by the internal and public builds. +# Note: This file is used by the internal builds. # # -# Public variables: +# Variables: # QT_ANDROID_JAR # Location of the adroid sdk jar for java code -# QT_ANDROID_APIVERSION +# QT_ANDROID_API_VERSION # Android API version -# QT_ANDROID_SDK_BUILD_TOOLS_VERSION -# Detected Android sdk build tools version -# -# Public functions: -# -# qt_android_generate_deployment_settings() -# Generate the deployment settings json file for a cmake target. # if (NOT DEFINED ANDROID_SDK_ROOT) - message(FATAL_ERROR "Please provide the location of the Android SDK directory via -DANDROID_SDK_ROOT=<path to Adndroid SDK>") + message(FATAL_ERROR "Please provide the location of the Android SDK directory via -DANDROID_SDK_ROOT=<path to Android SDK>") endif() if (NOT IS_DIRECTORY "${ANDROID_SDK_ROOT}") @@ -40,28 +36,66 @@ function(qt_get_android_sdk_jar_for_api api out_jar_location) endfunction() # Minimum recommend android SDK api version -set(QT_ANDROID_API_VERSION "android-28") +set(QT_ANDROID_API_VERSION "android-33") -# Locate android.jar -set(QT_ANDROID_JAR "${ANDROID_SDK_ROOT}/platforms/${QT_ANDROID_API_VERSION}/android.jar") -if(NOT EXISTS "${QT_ANDROID_JAR}") - # Locate the highest available platform - file(GLOB android_platforms - LIST_DIRECTORIES true - RELATIVE "${ANDROID_SDK_ROOT}/platforms" - "${ANDROID_SDK_ROOT}/platforms/*") - # If list is not empty - if(android_platforms) - list(SORT android_platforms) - list(REVERSE android_platforms) - list(GET android_platforms 0 android_platform_latest) +function(qt_internal_sort_android_platforms out_var) + if(CMAKE_VERSION GREATER_EQUAL 3.18) + set(platforms ${ARGN}) + list(SORT platforms COMPARE NATURAL) + else() + # Simulate natural sorting: + # - prepend every platform with its version as three digits, zero-padded + # - regular sort + # - remove the padded version prefix + set(platforms) + foreach(platform IN LISTS ARGN) + set(version "000") + if(platform MATCHES ".*-([0-9]+)$") + set(version ${CMAKE_MATCH_1}) + string(LENGTH "${version}" version_length) + math(EXPR padding_length "3 - ${version_length}") + string(REPEAT "0" ${padding_length} padding) + string(PREPEND version ${padding}) + endif() + list(APPEND platforms "${version}~${platform}") + endforeach() + list(SORT platforms) + list(TRANSFORM platforms REPLACE "^.*~" "") + endif() + set("${out_var}" "${platforms}" PARENT_SCOPE) +endfunction() + +macro(qt_internal_get_android_platform_version out_var android_platform) + string(REGEX REPLACE ".*-([0-9]+)$" "\\1" ${out_var} "${android_platform}") +endmacro() + +# Locate the highest available platform +file(GLOB android_platforms + LIST_DIRECTORIES true + RELATIVE "${ANDROID_SDK_ROOT}/platforms" + "${ANDROID_SDK_ROOT}/platforms/*") +# If list is not empty +if(android_platforms) + qt_internal_sort_android_platforms(android_platforms ${android_platforms}) + list(REVERSE android_platforms) + list(GET android_platforms 0 android_platform_latest) + + qt_internal_get_android_platform_version(latest_platform_version + "${android_platform_latest}") + qt_internal_get_android_platform_version(required_platform_version + "${QT_ANDROID_API_VERSION}") + + if("${latest_platform_version}" VERSION_GREATER "${required_platform_version}") set(QT_ANDROID_API_VERSION ${android_platform_latest}) - set(QT_ANDROID_JAR "${ANDROID_SDK_ROOT}/platforms/${QT_ANDROID_API_VERSION}/android.jar") endif() endif() +set(QT_ANDROID_JAR "${ANDROID_SDK_ROOT}/platforms/${QT_ANDROID_API_VERSION}/android.jar") if(NOT EXISTS "${QT_ANDROID_JAR}") - message(FATAL_ERROR "No suitable Android SDK platform found. Minimum version is ${QT_ANDROID_API_VERSION}") + message(FATAL_ERROR + "No suitable Android SDK platform found in '${ANDROID_SDK_ROOT}/platforms'." + " Minimum version is ${QT_ANDROID_API_VERSION}" + ) endif() message(STATUS "Using Android SDK API ${QT_ANDROID_API_VERSION} from ${ANDROID_SDK_ROOT}/platforms") @@ -72,21 +106,6 @@ include(UseJava) # Find JDK 8.0 find_package(Java 1.8 COMPONENTS Development REQUIRED) -# Locate newest android sdk build tools -if (NOT QT_ANDROID_SDK_BUILD_TOOLS_VERSION) - file(GLOB android_build_tools - LIST_DIRECTORIES true - RELATIVE "${ANDROID_SDK_ROOT}/build-tools" - "${ANDROID_SDK_ROOT}/build-tools/*") - if (NOT android_build_tools) - message(FATAL_ERROR "Could not locate Android SDK build tools under \"${ANDROID_SDK}/build-tools\"") - endif() - list(SORT android_build_tools) - list(REVERSE android_build_tools) - list(GET android_build_tools 0 android_build_tools_latest) - set(QT_ANDROID_SDK_BUILD_TOOLS_VERSION ${android_build_tools_latest}) -endif() - # Ensure we are using the shared version of libc++ if(NOT ANDROID_STL STREQUAL c++_shared) message(FATAL_ERROR "The Qt libraries on Android only supports the shared library configuration of stl. Please use -DANDROID_STL=\"c++_shared\" as configuration argument.") @@ -142,231 +161,33 @@ define_property(TARGET PROPERTY QT_ANDROID_DEPLOYMENT_SETTINGS_FILE BRIEF_DOCS - " " + "This variable is used to specify the deployment settings JSON file for androiddeployqt." FULL_DOCS - " " + "This variable points to the path of the deployment settings JSON file, which holds properties required by androiddeployqt to package the Android app." ) -# Generate deployment tool json -function(qt_android_generate_deployment_settings target) - # Information extracted from mkspecs/features/android/android_deployment_settings.prf - if (NOT TARGET ${target}) - message(SEND_ERROR "${target} is not a cmake target") - return() - endif() - - get_target_property(target_type ${target} TYPE) - - if (NOT "${target_type}" STREQUAL "MODULE_LIBRARY") - message(SEND_ERROR "QT_ANDROID_GENERATE_DEPLOYMENT_SETTINGS only works on Module targets") - return() - endif() - - get_target_property(target_source_dir ${target} SOURCE_DIR) - get_target_property(target_binary_dir ${target} BINARY_DIR) - get_target_property(target_output_name ${target} OUTPUT_NAME) - if (NOT target_output_name) - set(target_output_name ${target}) - endif() - set(deploy_file "${target_binary_dir}/android-lib${target_output_name}.so-deployment-settings.json") - - set(file_contents "{\n") - # content begin - string(APPEND file_contents - " \"description\": \"This file is generated by cmake to be read by androiddeployqt and should not be modified by hand.\",\n") - - # Host Qt Android install path - if (NOT QT_BUILDING_QT) - set(file_check "${Qt6_DIR}/plugins/platforms/android/libqtforandroid_${CMAKE_ANDROID_ARCH_ABI}.so") - if (NOT EXISTS ${file_check}) - message(SEND_ERROR "Detected Qt installation does not contain libqtforandroid.so. This is most likely due to the installation not being a build of Qt for Android. Please update your settings.") - return() - endif() - set(qt_android_install_dir ${Qt6_Dir}) - else() - # Building from source, use the same install prefix - set(qt_android_install_dir ${CMAKE_INSTALL_PREFIX}) - endif() - - file(TO_NATIVE_PATH "${qt_android_install_dir}" qt_android_install_dir_native) - string(APPEND file_contents - " \"qt\": \"${qt_android_install_dir_native}\",\n") - - # Android SDK path - file(TO_NATIVE_PATH "${ANDROID_SDK_ROOT}" android_sdk_root_native) - string(APPEND file_contents - " \"sdk\": \"${android_sdk_root_native}\",\n") - - # Android SDK Build Tools Revision - string(APPEND file_contents - " \"sdkBuildToolsRevision\": \"${QT_ANDROID_SDK_BUILD_TOOLS_VERSION}\",\n") - - # Android NDK - file(TO_NATIVE_PATH "${ANDROID_NDK}" android_ndk_root_native) - string(APPEND file_contents - " \"ndk\": \"${android_ndk_root_native}\",\n") - - # Setup LLVM toolchain - string(APPEND file_contents - " \"toolchain-prefix\": \"llvm\",\n") - string(APPEND file_contents - " \"tool-prefix\": \"llvm\",\n") - string(APPEND file_contents - " \"useLLVM\": true,\n") - - # NDK Toolchain Version - string(APPEND file_contents - " \"toolchain-version\": \"${CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION}\",\n") - - # NDK Host - string(APPEND file_contents - " \"ndk-host\": \"${ANDROID_NDK_HOST_SYSTEM_NAME}\",\n") - - if (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86") - set(arch_value "i686-linux-android") - elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64") - set(arch_value "x86_64-linux-android") - elseif (CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a") - set(arch_value "aarch64-linux-android") - else() - set(arch_value "arm-linux-androideabi") - endif() - - # Architecture - string(APPEND file_contents - " \"architectures\": { \"${CMAKE_ANDROID_ARCH_ABI}\" : \"${arch_value}\" },\n") - - # deployment dependencies - get_target_property(android_deployment_dependencies - ${target} QT_ANDROID_DEPLOYMENT_DEPENDENCIES) - if (android_deployment_dependencies) - list(JOIN android_deployment_dependencies "," android_deployment_dependencies) - string(APPEND file_contents - " \"deployment-dependencies\": \"${android_deployment_dependencies}\",\n") - endif() - - # Extra plugins - get_target_property(android_extra_plugins - ${target} QT_ANDROID_EXTRA_PLUGINS) - if (android_extra_plugins) - list(JOIN android_extra_plugins "," android_extra_plugins) - string(APPEND file_contents - " \"android-extra-plugins\": \"${android_extra_plugins}\",\n") - endif() - - # Extra libs - get_target_property(android_extra_libs - ${target} QT_ANDROID_EXTRA_LIBS) - if (android_extra_libs) - list(JOIN android_extra_libs "," android_extra_libs) - string(APPEND file_contents - " \"android-extra-libs\": \"${android_extra_libs}\",\n") - endif() - - # package source dir - get_target_property(android_package_source_dir - ${target} QT_ANDROID_PACKAGE_SOURCE_DIR) - if (android_package_source_dir) - file(TO_NATIVE_PATH "${android_package_source_dir}" android_package_source_dir_native) - string(APPEND file_contents - " \"android-package-source-directory\": \"${android_package_source_dir_native}\",\n") -endif() - - #TODO: ANDROID_VERSION_NAME, doesn't seem to be used? - - #TODO: ANDROID_VERSION_CODE, doesn't seem to be used? - - get_target_property(qml_import_path ${target} QT_QML_IMPORT_PATH) - if (qml_import_path) - file(TO_NATIVE_PATH "${qml_import_path}" qml_import_path_native) - string(APPEND file_contents - " \"qml-import-path\": \"${qml_import_path_native}\",\n") - endif() - - get_target_property(qml_root_path ${target} QT_QML_ROOT_PATH) - if(NOT qml_root_path) - set(qml_root_path "${target_source_dir}") - endif() - file(TO_NATIVE_PATH "${qml_root_path}" qml_root_path_native) - string(APPEND file_contents - " \"qml-root-path\": \"${qml_root_path_native}\",\n") - - # App binary - string(APPEND file_contents - " \"application-binary\": \"${target_output_name}\",\n") - - # App command-line arguments - string(APPEND file_contents - " \"android-application-arguments\": \"${QT_ANDROID_APPLICATION_ARGUMENTS}\",\n") - - # Override qmlimportscanner binary path - set(qml_importscanner_binary_path "${QT_HOST_PATH}/bin/qmlimportscanner") - if (WIN32) - string(APPEND qml_importscanner_binary_path ".exe") - endif() - file(TO_NATIVE_PATH "${qml_importscanner_binary_path}" qml_importscanner_binary_path_native) - string(APPEND file_contents - " \"qml-importscanner-binary\" : \"${qml_importscanner_binary_path_native}\",\n") - - # Last item in json file - - # base location of stdlibc++, will be suffixed by androiddeploy qt - set(android_ndk_stdlib_base_path - "${ANDROID_NDK}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/" - ) - string(APPEND file_contents - " \"stdcpp-path\": \"${android_ndk_stdlib_base_path}\"\n") - - # content end - string(APPEND file_contents "}\n") - - file(WRITE ${deploy_file} ${file_contents}) - - set_target_properties(${target} - PROPERTIES - QT_ANDROID_DEPLOYMENT_SETTINGS_FILE ${deploy_file} - ) -endfunction() - -function(qt_android_apply_arch_suffix target) - get_target_property(target_type ${target} TYPE) - if (target_type STREQUAL "SHARED_LIBRARY" OR target_type STREQUAL "MODULE_LIBRARY") - set_property(TARGET "${target}" PROPERTY SUFFIX "_${CMAKE_ANDROID_ARCH_ABI}.so") - elseif (target_type STREQUAL "STATIC_LIBRARY") - set_property(TARGET "${target}" PROPERTY SUFFIX "_${CMAKE_ANDROID_ARCH_ABI}.a") - endif() -endfunction() - -# Add custom target to package the APK -function(qt_android_add_apk_target target) - get_target_property(deployment_file ${target} QT_ANDROID_DEPLOYMENT_SETTINGS_FILE) - if (NOT deployment_file) - message(FATAL_ERROR "Target ${target} is not a valid android executable target\n") - endif() - - set(deployment_tool "${QT_HOST_PATH}/bin/androiddeployqt") - set(apk_dir "$<TARGET_PROPERTY:${target},BINARY_DIR>/android-build") - add_custom_target(${target}_prepare_apk_dir - DEPENDS ${target} - COMMAND ${CMAKE_COMMAND} - -E copy $<TARGET_FILE:${target}> - "${apk_dir}/libs/${CMAKE_ANDROID_ARCH_ABI}/$<TARGET_FILE_NAME:${target}>" - COMMENT "Copying ${target} binarty to apk folder" - ) +define_property(TARGET + PROPERTY + QT_ANDROID_SYSTEM_LIBS_PREFIX + BRIEF_DOCS + "This variable is used to specify a path to Qt libraries on the target device in Android." + FULL_DOCS + "This variable can be used to provide a custom system library path to use for library loading lookup on Android. This is necessary when using Qt libraries installed outside an app's default native (JNI) library directory." +) - add_custom_target(${target}_make_apk - DEPENDS ${target}_prepare_apk_dir - COMMAND ${deployment_tool} - --input ${deployment_file} - --output ${apk_dir} - COMMENT "Creating APK for ${target}" - ) -endfunction() +define_property(TARGET + PROPERTY + QT_ANDROID_NO_DEPLOY_QT_LIBS + BRIEF_DOCS + "This variable is used to control whether Qt libraries should be deployed inside the APK on Android." + FULL_DOCS + "This variable can be used to exclude Qt shared libraries from being packaged inside the APK when deploying on Android. Not supported when deploying as Android Application Bundle." +) -# Add a test for Android which will be run by the android test runner tool -function(qt_android_add_test target) - set(deployment_tool "${QT_HOST_PATH}/bin/androiddeployqt") - set(test_runner "${QT_HOST_PATH}/bin/androidtestrunner") +# Returns test execution arguments for Android targets +function(qt_internal_android_test_arguments target timeout out_test_runner out_test_arguments) + set(${out_test_runner} "${QT_HOST_PATH}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}/androidtestrunner" PARENT_SCOPE) + set(deployment_tool "${QT_HOST_PATH}/${QT${PROJECT_VERSION_MAJOR}_HOST_INFO_BINDIR}/androiddeployqt") get_target_property(deployment_file ${target} QT_ANDROID_DEPLOYMENT_SETTINGS_FILE) if (NOT deployment_file) @@ -374,16 +195,20 @@ function(qt_android_add_test target) endif() set(target_binary_dir "$<TARGET_PROPERTY:${target},BINARY_DIR>") - set(apk_dir "${target_binary_dir}/android-build") - - add_test(NAME "${target}" - COMMAND "${test_runner}" - --androiddeployqt "${deployment_tool} --input ${deployment_file}" - --adb "${ANDROID_SDK_ROOT}/platform-tools/adb" - --path "${apk_dir}" - --skip-install-root - --make "${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${target}_make_apk" - --apk "${apk_dir}/${target}.apk" - --verbose + if(QT_USE_TARGET_ANDROID_BUILD_DIR) + set(apk_dir "${target_binary_dir}/android-build-${target}") + else() + set(apk_dir "${target_binary_dir}/android-build") + endif() + set(${out_test_arguments} + "--path" "${apk_dir}" + "--adb" "${ANDROID_SDK_ROOT}/platform-tools/adb" + "--skip-install-root" + "--make" "\"${CMAKE_COMMAND}\" --build ${CMAKE_BINARY_DIR} --target ${target}_make_apk" + "--apk" "${apk_dir}/${target}.apk" + "--ndk-stack" "${ANDROID_NDK_ROOT}/ndk-stack" + "--timeout" "${timeout}" + "--verbose" + PARENT_SCOPE ) endfunction() |