Warning, /frameworks/extra-cmake-modules/toolchain/Android.cmake is written in an unsupported language. File is not indexed.
0001 # SPDX-FileCopyrightText: 2014 Aleix Pol i Gonzalez <aleixpol@kde.org> 0002 # 0003 # SPDX-License-Identifier: BSD-3-Clause 0004 0005 #[=======================================================================[.rst: 0006 AndroidToolchain 0007 ---------------- 0008 0009 Enable easy compilation of cmake projects on Android. 0010 0011 By using this android toolchain, the projects will be set up to compile the 0012 specified project targeting an Android platform, depending on its input. 0013 Furthermore, if desired, an APK can be directly generated by using the 0014 `androiddeployqt <https://doc.qt.io/qt-5/deployment-android.html>`_ tool. 0015 0016 CMake upstream has Android support now. This module will still give us some 0017 useful features offering androiddeployqt integration and adequate executables 0018 format for our Android applications. 0019 0020 Since we are using CMake Android support, any information from CMake documentation 0021 still applies: 0022 https://cmake.org/cmake/help/v3.7/manual/cmake-toolchains.7.html#cross-compiling-for-android 0023 0024 .. note:: 0025 0026 This module requires CMake 3.18. 0027 0028 Since 1.7.0. 0029 0030 Usage 0031 ===== 0032 0033 To use this file, you need to set the ``CMAKE_TOOLCHAIN_FILE`` to point to 0034 ``Android.cmake`` on the command line:: 0035 0036 cmake -DCMAKE_TOOLCHAIN_FILE=/usr/share/ECM/toolchain/Android.cmake 0037 0038 You will also need to provide the locations of the Android NDK and SDK. This 0039 can be done on the commandline or with environment variables; in either case 0040 the variable names are: 0041 0042 ``CMAKE_ANDROID_NDK`` 0043 The NDK root path. 0044 ``ANDROID_SDK_ROOT`` 0045 The SDK root path. 0046 0047 Additional options are specified as cache variables (eg: on the command line): 0048 0049 ``ANDROID_ABI`` 0050 The ABI to use. See the ``sources/cxx-stl/gnu-libstdc++/*/libs`` 0051 directories in the NDK. Default: ``armeabi-v7a``. 0052 ``ANDROID_SDK_COMPILE_API`` 0053 The platform API level to compile against. May be different from the NDK 0054 target. Default: newest installed version (e.g. android-30). 0055 ``ANDROID_SDK_BUILD_TOOLS_REVISION`` 0056 The build tools version to use. 0057 Default: newest installed version (e.g. ``30.0.2``). 0058 ``ANDROID_EXTRA_LIBS`` 0059 The ";"-separated list of full paths to libs to include in resulting APK. 0060 0061 For integrating other libraries which are not part of the Android toolchain, 0062 like Qt5, and installed to a separate prefix on the host system, the install 0063 prefixes of those libraries would be passed as alternative roots as list via 0064 ``ECM_ADDITIONAL_FIND_ROOT_PATH``. Since 5.30.0. 0065 0066 For example, for integrating a Qt5 for Android present at 0067 ``~/Qt/5.14.2/android/`` and some other libraries installed to 0068 the prefix ``/opt/android/foo``, you would use:: 0069 0070 cmake \ 0071 -DCMAKE_TOOLCHAIN_FILE=/usr/share/ECM/toolchain/Android.cmake \ 0072 -DECM_ADDITIONAL_FIND_ROOT_PATH="~/Qt/5.14.2/android/;/opt/android/foo" 0073 0074 If your project uses ``find_package()`` to locate build tools on the host 0075 system, make sure to pass ``CMAKE_FIND_ROOT_PATH_BOTH`` or 0076 ``NO_CMAKE_FIND_ROOT_PATH`` as argument in the call. See the 0077 ``find_package()`` documentation for more details. 0078 0079 Deploying Qt Applications 0080 ========================= 0081 0082 After building the application, you will need to generate an APK that can be 0083 deployed to an Android device. This module integrates androiddeployqt support 0084 to help with this for Qt-based projects. To enable this, set the 0085 ``QTANDROID_EXPORTED_TARGET`` variable to the targets you wish to export as an 0086 APK (in a ;-separed list), as well as ``ANDROID_APK_DIR`` to a directory 0087 containing some basic information. This will create a ``create-apk-<target>`` 0088 target that will generate the APK file. See the `Qt on Android deployment 0089 documentation <https://doc.qt.io/qt-5/deployment-android.html>`_ for more 0090 information. 0091 0092 For example, you could do:: 0093 0094 cmake \ 0095 -DCMAKE_TOOLCHAIN_FILE=/usr/share/ECM/toolchain/Android.cmake \ 0096 -DQTANDROID_EXPORTED_TARGET=myapp \ 0097 -DANDROID_APK_DIR=myapp-apk 0098 make 0099 make create-apk-myapp 0100 0101 You can specify the APK output directory by setting ``ANDROID_APK_OUTPUT_DIR``. 0102 Otherwise the APK can be found in ``myapp_build_apk/`` in the build directory. 0103 0104 The create-apk-myapp target will be able to take an ARGS parameter with further 0105 arguments for androiddeployqt. For example, one can use:: 0106 0107 make create-apk-myapp ARGS="--install" 0108 0109 To install the apk to test. To generate a signed apk, one can do it with the 0110 following syntax:: 0111 0112 make create-apk-myapp ARGS="--sign ~/my.keystore alias_name" 0113 0114 In case it's needed for your application to set the APK directory from cmake 0115 scripting you can also set the directory as the ANDROID_APK_DIR property of 0116 the create-apk-myapp target. 0117 0118 See Android documentation on how to create a keystore to use 0119 0120 Advanced Options 0121 ================ 0122 0123 The following packaging options are mainly interesting for automation or integration 0124 with CI/CD pipelines: 0125 0126 ``ANDROID_APK_OUTPUT_DIR`` 0127 Specifies a folder where the generated APK files should be placed. 0128 ``ANDROID_FASTLANE_METADATA_OUTPUT_DIR`` 0129 Specifies a folder where the generated metadata for the F-Droid store 0130 should be placed. 0131 ``ANDROIDDEPLOYQT_EXTRA_ARGS`` 0132 Allows to pass additional arguments to `androiddeployqt`. This is an alternative to 0133 the `ARGS=` argument for `make` and unlike that works with all CMake generators. 0134 #]=======================================================================] 0135 0136 cmake_minimum_required(VERSION "3.18") 0137 0138 macro(set_deprecated_variable actual_variable deprecated_variable default_value) 0139 set(${deprecated_variable} "${default_value}" CACHE STRING "Deprecated. Use ${actual_variable}") 0140 if (NOT DEFINED ${actual_variable}) 0141 set(${actual_variable} ${${deprecated_variable}}) 0142 endif() 0143 endmacro() 0144 0145 set_deprecated_variable(CMAKE_ANDROID_NDK ANDROID_NDK "$ENV{ANDROID_NDK}") 0146 set_deprecated_variable(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION ANDROID_GCC_VERSION "clang") 0147 set_deprecated_variable(CMAKE_ANDROID_API ANDROID_API_LEVEL "21") 0148 if(NOT DEFINED ENV{ANDROID_ARCH}) 0149 set(ENV{ANDROID_ARCH} "arm") 0150 endif() 0151 set_deprecated_variable(CMAKE_ANDROID_ARCH ANDROID_ARCHITECTURE $ENV{ANDROID_ARCH}) 0152 if(NOT DEFINED ENV{ANDROID_ARCH_ABI}) 0153 set(ENV{ANDROID_ARCH_ABI} "armeabi-v7a") 0154 endif() 0155 set_deprecated_variable(CMAKE_ANDROID_ARCH_ABI ANDROID_ABI "$ENV{ANDROID_ARCH_ABI}") 0156 0157 set(ANDROID_SDK_ROOT "$ENV{ANDROID_SDK_ROOT}" CACHE PATH "Android SDK path") 0158 0159 file(GLOB platforms LIST_DIRECTORIES TRUE RELATIVE ${ANDROID_SDK_ROOT}/platforms ${ANDROID_SDK_ROOT}/platforms/*) 0160 list(SORT platforms COMPARE NATURAL) 0161 list(GET platforms -1 _default_platform) 0162 set(ANDROID_SDK_COMPILE_API "${_default_platform}" CACHE STRING "Android API Level") 0163 if(ANDROID_SDK_COMPILE_API MATCHES "^android-([0-9]+)$") 0164 set(ANDROID_SDK_COMPILE_API ${CMAKE_MATCH_1}) 0165 endif() 0166 0167 file(GLOB build-tools LIST_DIRECTORIES TRUE RELATIVE ${ANDROID_SDK_ROOT}/build-tools ${ANDROID_SDK_ROOT}/build-tools/*) 0168 list(SORT build-tools COMPARE NATURAL) 0169 list(GET build-tools -1 _default_sdk) 0170 set(ANDROID_SDK_BUILD_TOOLS_REVISION "${_default_sdk}" CACHE STRING "Android Build Tools version") 0171 0172 set(CMAKE_SYSTEM_VERSION ${CMAKE_ANDROID_API}) 0173 set(CMAKE_SYSTEM_NAME Android) 0174 if (NOT CMAKE_ANDROID_STL_TYPE) 0175 set(CMAKE_ANDROID_STL_TYPE c++_shared) 0176 endif() 0177 0178 # Workaround link failure at FindThreads in CXX-only mode, 0179 # armv7 really doesn't like mixing PIC/PIE code. 0180 # Since we only have to care about a single compiler, 0181 # hard-code the values here. 0182 # Qt6 fixes this and breaks in nested CMake calls (e.g. try_compile) if we 0183 # define Threads::Threads here, at least if the "C" language is enabled. In 0184 # CXX-only projects we still need to do this unconditionally... 0185 # 0186 # We cannot use our usual Qt version check at this point though yet, 0187 # se check whether we are chainloaded by the Qt toolchain as an indicator 0188 # for Qt6. 0189 get_property(_languages GLOBAL PROPERTY ENABLED_LANGUAGES) 0190 if (NOT TARGET Threads::Threads AND (NOT DEFINED __qt_chainload_toolchain_file OR NOT "C" IN_LIST _languages)) 0191 set(Threads_FOUND TRUE) 0192 set(CMAKE_THREAD_LIBS_INIT "-pthread") 0193 add_library(Threads::Threads INTERFACE IMPORTED) 0194 set_property(TARGET Threads::Threads PROPERTY INTERFACE_COMPILE_OPTIONS "-pthread") 0195 set_property(TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "-pthread") 0196 endif() 0197 0198 # let the Android NDK toolchain file do the actual work 0199 set(ANDROID_PLATFORM "android-${CMAKE_ANDROID_API}") 0200 set(ANDROID_STL ${CMAKE_ANDROID_STL_TYPE}) 0201 include(${CMAKE_ANDROID_NDK}/build/cmake/android.toolchain.cmake REQUIRED) 0202 0203 # Export configurable variables for the try_compile() command. 0204 list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES 0205 CMAKE_ANDROID_NDK 0206 CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION 0207 CMAKE_ANDROID_API 0208 CMAKE_ANDROID_ARCH 0209 CMAKE_ANDROID_ARCH_ABI 0210 ANDROID_SDK_ROOT 0211 ANDROID_SDK_COMPILE_API 0212 ) 0213 0214 ## HACK: Remove when we can depend on NDK r23 0215 # Workaround issue https://github.com/android/ndk/issues/929 0216 if(ANDROID_NDK_MAJOR VERSION_LESS 23) 0217 unset(CMAKE_SYSROOT) 0218 set(ANDROID_SYSROOT_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/sysroot/usr") 0219 0220 list(APPEND CMAKE_SYSTEM_INCLUDE_PATH 0221 "${ANDROID_SYSROOT_PREFIX}/include/${CMAKE_LIBRARY_ARCHITECTURE}") 0222 list(APPEND CMAKE_SYSTEM_INCLUDE_PATH "${ANDROID_SYSROOT_PREFIX}/include") 0223 0224 # Prepend in reverse order 0225 list(PREPEND CMAKE_SYSTEM_LIBRARY_PATH 0226 "${ANDROID_SYSROOT_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}") 0227 list(PREPEND CMAKE_SYSTEM_LIBRARY_PATH 0228 "${ANDROID_SYSROOT_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}/${ANDROID_PLATFORM_LEVEL}") 0229 endif() 0230 0231 # these aren't set yet at this point by the Android toolchain, but without 0232 # those the find_package() call in ECMAndroidDeployQt will fail 0233 set(CMAKE_FIND_LIBRARY_PREFIXES "lib") 0234 set(CMAKE_FIND_LIBRARY_SUFFIXES "_${CMAKE_ANDROID_ARCH_ABI}.so" ".so" ".a") 0235 0236 # Work around Qt messing with CMAKE_SHARED_LIBRARY_SUFFIX and thus breaking find_library() 0237 # Unfortunately, just setting CMAKE_FIND_LIBRARY_SUFFIXES here won't help, as this will 0238 # be subsequently overwritten. 0239 macro(addAbiSuffix _var _access) 0240 if (${_access} STREQUAL "MODIFIED_ACCESS") 0241 list(PREPEND CMAKE_FIND_LIBRARY_SUFFIXES "_${CMAKE_ANDROID_ARCH_ABI}.so") 0242 endif() 0243 endmacro() 0244 variable_watch(CMAKE_FIND_LIBRARY_SUFFIXES addAbiSuffix) 0245 0246 # determine STL architecture, which is using a different format than ANDROID_ARCH_ABI 0247 string(REGEX REPLACE "-(clang)?([0-9].[0-9])?$" "" ECM_ANDROID_STL_ARCH ${ANDROID_TOOLCHAIN_NAME}) 0248 0249 if (NOT DEFINED ECM_ADDITIONAL_FIND_ROOT_PATH) 0250 SET(ECM_ADDITIONAL_FIND_ROOT_PATH ${CMAKE_PREFIX_PATH}) 0251 endif() 0252 0253 LIST(APPEND CMAKE_FIND_ROOT_PATH ${ECM_ADDITIONAL_FIND_ROOT_PATH}) 0254 0255 #we want executables to be shared libraries, hooks will invoke the exported cmake function 0256 set(CMAKE_CXX_LINK_EXECUTABLE 0257 "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>" 0258 ) 0259 0260 # As our executables are shared libraries, we also need them build with position independent code (PIC). 0261 # Qt 5 forces that anyway, but in Qt 6 that is no longer the case for exectuables (which we pretend to build here), 0262 # and so we end up with just PIE (coming from CMake). 0263 # And as subsequent steps overwrite that setting again, we have to watch for that and redo our change. 0264 set(CMAKE_CXX_COMPILE_OPTIONS_PIE "-fPIC") 0265 macro(resetPieOption _var _access) 0266 if (${_access} STREQUAL "MODIFIED_ACCESS") 0267 set(CMAKE_CXX_COMPILE_OPTIONS_PIE "-fPIC") 0268 endif() 0269 endmacro() 0270 variable_watch(CMAKE_CXX_COMPILE_OPTIONS_PIE resetPieOption) 0271 0272 set(ECM_DIR "${CMAKE_CURRENT_LIST_DIR}/../cmake" CACHE STRING "") 0273 0274 ######### generation 0275 0276 # Need to ensure we only get in here once, as this file is included twice: 0277 # from CMakeDetermineSystem.cmake and from CMakeSystem.cmake generated within the 0278 # build directory. 0279 if(DEFINED QTANDROID_EXPORTED_TARGET AND NOT TARGET "create-apk") 0280 get_filename_component(_CMAKE_ANDROID_DIR "${CMAKE_TOOLCHAIN_FILE}" PATH) 0281 list(LENGTH QTANDROID_EXPORTED_TARGET targetsCount) 0282 include(${_CMAKE_ANDROID_DIR}/ECMAndroidDeployQt.cmake) 0283 0284 math(EXPR last "${targetsCount}-1") 0285 foreach(idx RANGE 0 ${last}) 0286 list(GET QTANDROID_EXPORTED_TARGET ${idx} exportedTarget) 0287 list(GET ANDROID_APK_DIR ${idx} APK_DIR) 0288 if(APK_DIR AND NOT EXISTS "${ANDROID_APK_DIR}/AndroidManifest.xml" AND IS_ABSOLUTE ANDROID_APK_DIR) 0289 message(FATAL_ERROR "Cannot find ${APK_DIR}/AndroidManifest.xml according to ANDROID_APK_DIR. ${ANDROID_APK_DIR} ${exportedTarget}") 0290 elseif(NOT APK_DIR) 0291 get_filename_component(_qt5Core_install_prefix "${Qt5Core_DIR}/../../../" ABSOLUTE) 0292 set(APK_DIR "${_qt5Core_install_prefix}/src/android/templates/") 0293 endif() 0294 0295 ecm_androiddeployqt("${exportedTarget}" "${ECM_ADDITIONAL_FIND_ROOT_PATH}") 0296 set_target_properties(create-apk-${exportedTarget} PROPERTIES ANDROID_APK_DIR "${APK_DIR}") 0297 endforeach() 0298 else() 0299 message(STATUS "You can export a target by specifying -DQTANDROID_EXPORTED_TARGET=<targetname> and -DANDROID_APK_DIR=<paths>") 0300 endif()