#.rst: # AndroidToolchain # ------------------- # # Enable easy compilation of cmake projects on Android # # By using this android toolchain, the projects will be set up to compile the # specified project targeting an Android platform, depending on its input. # Furthermore, if desired, an APK can be directly generated by using the # androiddeployqt tool. # # Note: Requires CMake 3.1 # # How to use it? # -------------- # First of all, to make use of this toolchain file it's required to specify the # CMAKE_TOOLCHAIN_FILE variable pointing to AndroidToolchain.cmake. # # Then, there's many settings that we may want to specify under what circumstances # the project will be built. This will be done through environment variables: # - ANDROID_NDK: points to the NDK root path # - ANDROID_SDK_ROOT: points to the SDK root path # # Also there's some cache variables we can pass as well to narrow down the # preferred settings: # - ANDROID_NDK: Points to the NDK root, defaults to the environment variable # with the same name. # - ANDROID_SDK_ROOT: Points to the Android SDK root, defaults to the environment # variable with the same name. # - ANDROID_ARCHITECTURE: Specifies the used architecture, "arm" by default. See # arch-* directory. # - ANDROID_TOOLCHAIN: Specifies the toolchain to be used. Defaults to # "arm-linux-androideabi". See /toolchains/ directory. # - ANDROID_ABI: Specifies the ABI to be used. Defaults to "armeabi-v7a". See # /sources/cxx-stl/gnu-libstdc++/*/libs/ directories. # - ANDROID_GCC_VERSION: Specifies the GCC version. Defaults to "4.9". # - ANDROID_API_LEVEL: Specifies the API level to require. Defaults to "14". See # http://developer.android.com/guide/topics/manifest/uses-sdk-element.html # - ANDROID_SDK_BUILD_TOOLS_REVISION: Specifies the build tools version to be used. # Defaults to "21.1.1". # # Once we have the application built, we will want to generate an APK that we # can run on an Android device. To this end we've integrated androiddeployqt so # this can be done easily. This won't work with non-qt projects. # To make use of the APK generation, we'll define QTANDROID_EXPORTED_TARGET with # the target we want to have exported. # Additionally, we'll need to specify a ANDROID_APK_DIR with the base information # to set the project up. For more information see: # https://qt-project.org/doc/qt-5-snapshot/deployment-android.html # # Once set up, after building, make create-apk- will process this # input and generate an apk that can be found inside the build directory: # ${CMAKE_BINARY_DIR}/_build_apk/bin/QtApp-*.apk. # # ============================================================================= # Copyright 2014 Aleix Pol i Gonzalez # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file COPYING-CMAKE-SCRIPTS for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of extra-cmake-modules, substitute the full # License text for the above reference.) cmake_minimum_required(VERSION "3.1") #input set(ANDROID_NDK "$ENV{ANDROID_NDK}" CACHE path "Android NDK path") set(ANDROID_SDK_ROOT "$ENV{ANDROID_SDK_ROOT}" CACHE path "Android SDK path") set(ANDROID_ARCHITECTURE "arm" CACHE string "Used Architecture, related to the ABI and TOOLCHAIN") set(ANDROID_TOOLCHAIN "arm-linux-androideabi" CACHE string "Used SDK") set(ANDROID_ABI "armeabi-v7a" CACHE string "Used ABI") set(ANDROID_GCC_VERSION "4.9" CACHE string "Used GCC version" ) set(ANDROID_API_LEVEL "14" CACHE string "Android API Level") set(ANDROID_SDK_BUILD_TOOLS_REVISION "21.1.1" CACHE string "Android API Level") set(_HOST "${CMAKE_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}") string(TOLOWER "${_HOST}" _HOST) get_filename_component(_CMAKE_ANDROID_DIR "${CMAKE_TOOLCHAIN_FILE}" PATH) cmake_policy(SET CMP0011 OLD) cmake_policy(SET CMP0017 OLD) set(CMAKE_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_API_LEVEL}/arch-${ANDROID_ARCHITECTURE}") if(NOT EXISTS ${CMAKE_SYSROOT}) message(FATAL_ERROR "Couldn't find the Android NDK Root in ${CMAKE_SYSROOT}") endif() #actual code SET(CMAKE_SYSTEM_NAME Android) SET(CMAKE_SYSTEM_VERSION 1) set(ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK}/toolchains/${ANDROID_TOOLCHAIN}-${ANDROID_GCC_VERSION}/prebuilt/${_HOST}/bin") set(ANDROID_LIBS_ROOT "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_GCC_VERSION}") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM "${ANDROID_TOOLCHAIN_ROOT}") set(ANDROID_LIBRARIES_PATH "${CMAKE_SYSROOT}/usr/lib") set(CMAKE_SYSTEM_LIBRARY_PATH ${ANDROID_LIBRARIES_PATH} "${ANDROID_LIBS_ROOT}/libs/${ANDROID_ABI}/" ) set(CMAKE_FIND_LIBRARY_SUFFIXES ".so") set(CMAKE_FIND_LIBRARY_PREFIXES "lib") find_library(GNUSTL_SHARED gnustl_shared) if(NOT GNUSTL_SHARED) message(FATAL_ERROR "you need gnustl_shared: ${CMAKE_SYSTEM_LIBRARY_PATH}") endif() include_directories(SYSTEM "${CMAKE_SYSROOT}/usr/include" "${ANDROID_LIBS_ROOT}/include/" "${ANDROID_LIBS_ROOT}/libs/${ANDROID_ABI}/include" ) link_directories(${CMAKE_SYSTEM_LIBRARY_PATH}) set(CMAKE_C_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN}-gcc") set(CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN}-g++") SET(CMAKE_FIND_ROOT_PATH ${ANDROID_NDK}) SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(CMAKE_EXE_LINKER_FLAGS "${GNUSTL_SHARED} -Wl,-rpath-link,${ANDROID_LIBRARIES_PATH} -llog -lz -lm -ldl -lc -lgcc" CACHE STRING "") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}" CACHE STRING "") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}" CACHE STRING "") #we want executables to be shared libraries, hooks will invoke the exported cmake function set(CMAKE_CXX_LINK_EXECUTABLE " -o " ) ######### generation set(CREATEAPK_TARGET_NAME "create-apk-${QTANDROID_EXPORTED_TARGET}") if(DEFINED QTANDROID_EXPORTED_TARGET AND NOT TARGET ${CREATEAPK_TARGET_NAME}) if(NOT EXISTS "${ANDROID_APK_DIR}/AndroidManifest.xml") message(FATAL_ERROR "Define an apk dir to initialize from using -DANDROID_APK_DIR=. The specified directory must contain the AndroidManifest.xml file.") endif() function(EOFHook) if(CMAKE_PARENT_LIST_FILE STREQUAL "") generate_deployment_file() endif() endfunction() function(generate_deployment_file) get_property(_DEPENDENCIES TARGET ${QTANDROID_EXPORTED_TARGET} PROPERTY INTERFACE_LINK_LIBRARIES) set(_DEPS_LIST) foreach(_DEP IN LISTS _DEPENDENCIES) if(NOT _DEP MATCHES "Qt5::.*") get_property(_DEP_LOCATION TARGET ${_DEP} PROPERTY "LOCATION_${CMAKE_BUILD_TYPE}") list(APPEND _DEPS_LIST ${_DEP_LOCATION}) endif() endforeach() string(REPLACE ";" "," _DEPS "${_DEPS_LIST}") configure_file("${_CMAKE_ANDROID_DIR}/deployment-file.json.in" "${QTANDROID_EXPORTED_TARGET}-deployment.json") endfunction() # Create the target that will eventually generate the apk get_filename_component(QTDIR "${Qt5Core_DIR}/../../../" ABSOLUTE) find_program(ANDROID_DEPLOY_QT androiddeployqt HINTS "${QTDIR}/bin") set(EXPORT_DIR "${CMAKE_BINARY_DIR}/${QTANDROID_EXPORTED_TARGET}_build_apk/") set(EXECUTABLE_DESTINATION_PATH "${EXPORT_DIR}/libs/${ANDROID_ABI}/lib${QTANDROID_EXPORTED_TARGET}.so") add_custom_target(${CREATEAPK_TARGET_NAME} COMMAND cmake -E echo "Generating $ with ${ANDROID_DEPLOY_QT}" COMMAND cmake -E copy_directory "${ANDROID_APK_DIR}" "${EXPORT_DIR}" COMMAND cmake -E copy "$" "${EXECUTABLE_DESTINATION_PATH}" COMMAND ${ANDROID_DEPLOY_QT} --input "${QTANDROID_EXPORTED_TARGET}-deployment.json" --output "${EXPORT_DIR}" --deployment bundled "\\$(ARGS)" ) #we want to call the function after the project has been set up variable_watch(CMAKE_PARENT_LIST_FILE EOFHook) else() message(STATUS "You can export a target by specifying -DQTANDROID_EXPORTED_TARGET=") endif()