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 (Qt 5 only). 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 5 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 # When building Qt6Base itself the check does not work, hence we have 0190 # ECM_THREADS_WORKAROUND for that case which set to OFF in the Craft blueprints. 0191 if (NOT DEFINED ECM_THREADS_WORKAROUND) 0192 set(ECM_THREADS_WORKAROUND TRUE) 0193 endif() 0194 get_property(_languages GLOBAL PROPERTY ENABLED_LANGUAGES) 0195 if (ECM_THREADS_WORKAROUND AND NOT TARGET Threads::Threads AND (NOT DEFINED __qt_chainload_toolchain_file OR NOT "C" IN_LIST _languages)) 0196 set(Threads_FOUND TRUE) 0197 set(CMAKE_THREAD_LIBS_INIT "-pthread") 0198 add_library(Threads::Threads INTERFACE IMPORTED) 0199 set_property(TARGET Threads::Threads PROPERTY INTERFACE_COMPILE_OPTIONS "-pthread") 0200 set_property(TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "-pthread") 0201 endif() 0202 0203 # let the Android NDK toolchain file do the actual work 0204 set(ANDROID_PLATFORM "android-${CMAKE_ANDROID_API}") 0205 set(ANDROID_STL ${CMAKE_ANDROID_STL_TYPE}) 0206 include(${CMAKE_ANDROID_NDK}/build/cmake/android.toolchain.cmake REQUIRED) 0207 0208 # Export configurable variables for the try_compile() command. 0209 list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES 0210 CMAKE_ANDROID_NDK 0211 CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION 0212 CMAKE_ANDROID_API 0213 CMAKE_ANDROID_ARCH 0214 CMAKE_ANDROID_ARCH_ABI 0215 ANDROID_SDK_ROOT 0216 ANDROID_SDK_COMPILE_API 0217 ) 0218 0219 # needed for androiddeployqt's stdcpp-path setting 0220 if (ANDROID_TOOLCHAIN_ROOT) 0221 set(ANDROID_SYSROOT_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/sysroot/usr") 0222 else() 0223 set(ANDROID_SYSROOT_PREFIX "${CMAKE_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr") 0224 endif() 0225 0226 ## HACK: Remove when we can depend on NDK r23 0227 # Workaround issue https://github.com/android/ndk/issues/929 0228 if(ANDROID_NDK_MAJOR VERSION_LESS 23) 0229 unset(CMAKE_SYSROOT) 0230 0231 list(APPEND CMAKE_SYSTEM_INCLUDE_PATH 0232 "${ANDROID_SYSROOT_PREFIX}/include/${CMAKE_LIBRARY_ARCHITECTURE}") 0233 list(APPEND CMAKE_SYSTEM_INCLUDE_PATH "${ANDROID_SYSROOT_PREFIX}/include") 0234 0235 # Prepend in reverse order 0236 list(PREPEND CMAKE_SYSTEM_LIBRARY_PATH 0237 "${ANDROID_SYSROOT_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}") 0238 list(PREPEND CMAKE_SYSTEM_LIBRARY_PATH 0239 "${ANDROID_SYSROOT_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}/${ANDROID_PLATFORM_LEVEL}") 0240 endif() 0241 0242 # Qt6 still expects ABI suffixes but only applies them in its own qt_add_[executable|library] macros 0243 # as we typically don't use those we need another way to get those 0244 if (DEFINED __qt_chainload_toolchain_file) # indicator for Qt6, see above 0245 set(CMAKE_MODULE_LIBRARY_SUFFIX_C "_${CMAKE_ANDROID_ARCH_ABI}.so") 0246 set(CMAKE_MODULE_LIBRARY_SUFFIX_CXX "_${CMAKE_ANDROID_ARCH_ABI}.so") 0247 set(CMAKE_SHARED_LIBRARY_SUFFIX_C "_${CMAKE_ANDROID_ARCH_ABI}.so") 0248 set(CMAKE_SHARED_LIBRARY_SUFFIX_CXX "_${CMAKE_ANDROID_ARCH_ABI}.so") 0249 endif() 0250 0251 # these aren't set yet at this point by the Android toolchain, but without 0252 # those the find_package() call in ECMAndroidDeployQt5 will fail 0253 set(CMAKE_FIND_LIBRARY_PREFIXES "lib") 0254 set(CMAKE_FIND_LIBRARY_SUFFIXES "_${CMAKE_ANDROID_ARCH_ABI}.so" ".so" ".a") 0255 0256 # Work around Qt messing with CMAKE_SHARED_LIBRARY_SUFFIX and thus breaking find_library() 0257 # Unfortunately, just setting CMAKE_FIND_LIBRARY_SUFFIXES here won't help, as this will 0258 # be subsequently overwritten. 0259 macro(addAbiSuffix _var _access) 0260 if (${_access} STREQUAL "MODIFIED_ACCESS") 0261 list(PREPEND CMAKE_FIND_LIBRARY_SUFFIXES "_${CMAKE_ANDROID_ARCH_ABI}.so") 0262 endif() 0263 endmacro() 0264 variable_watch(CMAKE_FIND_LIBRARY_SUFFIXES addAbiSuffix) 0265 0266 # determine STL architecture, which is using a different format than ANDROID_ARCH_ABI 0267 string(REGEX REPLACE "-(clang)?([0-9].[0-9])?$" "" ECM_ANDROID_STL_ARCH "${ANDROID_TOOLCHAIN_NAME}") 0268 0269 if (NOT DEFINED ECM_ADDITIONAL_FIND_ROOT_PATH) 0270 SET(ECM_ADDITIONAL_FIND_ROOT_PATH ${CMAKE_PREFIX_PATH}) 0271 endif() 0272 0273 LIST(APPEND CMAKE_FIND_ROOT_PATH ${ECM_ADDITIONAL_FIND_ROOT_PATH}) 0274 0275 #we want executables to be shared libraries, hooks will invoke the exported cmake function 0276 set(CMAKE_CXX_LINK_EXECUTABLE 0277 "<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>" 0278 ) 0279 0280 # As our executables are shared libraries, we also need them build with position independent code (PIC). 0281 # Qt 5 forces that anyway, but in Qt 6 that is no longer the case for exectuables (which we pretend to build here), 0282 # and so we end up with just PIE (coming from CMake). 0283 # And as subsequent steps overwrite that setting again, we have to watch for that and redo our change. 0284 set(CMAKE_CXX_COMPILE_OPTIONS_PIE "-fPIC") 0285 macro(resetPieOption _var _access) 0286 if (${_access} STREQUAL "MODIFIED_ACCESS") 0287 set(CMAKE_CXX_COMPILE_OPTIONS_PIE "-fPIC") 0288 endif() 0289 endmacro() 0290 variable_watch(CMAKE_CXX_COMPILE_OPTIONS_PIE resetPieOption) 0291 0292 set(ECM_DIR "${CMAKE_CURRENT_LIST_DIR}/../cmake" CACHE STRING "") 0293 0294 ######### generation (Qt 5 only) 0295 0296 # Need to ensure we only get in here once, as this file is included twice: 0297 # from CMakeDetermineSystem.cmake and from CMakeSystem.cmake generated within the 0298 # build directory. 0299 if(DEFINED QTANDROID_EXPORTED_TARGET AND NOT TARGET "create-apk" AND NOT __qt_chainload_toolchain_file) 0300 get_filename_component(_CMAKE_ANDROID_DIR "${CMAKE_TOOLCHAIN_FILE}" PATH) 0301 list(LENGTH QTANDROID_EXPORTED_TARGET targetsCount) 0302 include(${_CMAKE_ANDROID_DIR}/ECMAndroidDeployQt5.cmake) 0303 0304 math(EXPR last "${targetsCount}-1") 0305 foreach(idx RANGE 0 ${last}) 0306 list(GET QTANDROID_EXPORTED_TARGET ${idx} exportedTarget) 0307 list(GET ANDROID_APK_DIR ${idx} APK_DIR) 0308 if(APK_DIR AND NOT EXISTS "${ANDROID_APK_DIR}/AndroidManifest.xml" AND IS_ABSOLUTE ANDROID_APK_DIR) 0309 message(FATAL_ERROR "Cannot find ${APK_DIR}/AndroidManifest.xml according to ANDROID_APK_DIR. ${ANDROID_APK_DIR} ${exportedTarget}") 0310 elseif(NOT APK_DIR) 0311 get_filename_component(_qt5Core_install_prefix "${Qt5Core_DIR}/../../../" ABSOLUTE) 0312 set(APK_DIR "${_qt5Core_install_prefix}/src/android/templates/") 0313 endif() 0314 0315 ecm_androiddeployqt5("${exportedTarget}" "${ECM_ADDITIONAL_FIND_ROOT_PATH}") 0316 set_target_properties(create-apk-${exportedTarget} PROPERTIES ANDROID_APK_DIR "${APK_DIR}") 0317 endforeach() 0318 elseif (NOT __qt_chainload_toolchain_file) 0319 message(STATUS "You can export a target by specifying -DQTANDROID_EXPORTED_TARGET=<targetname> and -DANDROID_APK_DIR=<paths>") 0320 endif()