diff options
author | Aleix Pol <aleixpol@kde.org> | 2015-02-06 01:24:23 +0100 |
---|---|---|
committer | Aleix Pol <aleixpol@kde.org> | 2015-02-06 01:24:23 +0100 |
commit | 5b39c909baeb3e4c247a43b91a884d5990c99092 (patch) | |
tree | 6b2c21fe67bcfc7c803c065ff27cbfcbc4d621f8 /toolchain | |
parent | b03e287f9abe95372b0bc1b1917a006447280c95 (diff) | |
download | extra-cmake-modules-5b39c909baeb3e4c247a43b91a884d5990c99092.tar.gz extra-cmake-modules-5b39c909baeb3e4c247a43b91a884d5990c99092.tar.bz2 |
Move Android toolchain module to ECM
Introduces the new Android toolchain file for being able to easily compile
our cmake projects in Android, with an emphasis on Qt projects.
CHANGELOG: New Android toolchain support module.
REVIEW: 121545
Diffstat (limited to 'toolchain')
-rw-r--r-- | toolchain/Android.cmake | 183 | ||||
-rw-r--r-- | toolchain/deployment-file.json.in | 15 |
2 files changed, 198 insertions, 0 deletions
diff --git a/toolchain/Android.cmake b/toolchain/Android.cmake new file mode 100644 index 00000000..8272ef9d --- /dev/null +++ b/toolchain/Android.cmake @@ -0,0 +1,183 @@ +#.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 <ndk>/toolchains/ directory. +# - ANDROID_ABI: Specifies the ABI to be used. Defaults to "armeabi-v7a". See +# <ndk>/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-<target_name> will process this +# input and generate an apk that can be found inside the build directory: +# ${CMAKE_BINARY_DIR}/<target_name>_build_apk/bin/QtApp-*.apk. +# +# ============================================================================= +# Copyright 2014 Aleix Pol i Gonzalez <aleixpol@kde.org> +# +# 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 + "<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>" +) + +######### 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=<path>. 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 $<TARGET_NAME:${QTANDROID_EXPORTED_TARGET}> with ${ANDROID_DEPLOY_QT}" + COMMAND cmake -E copy_directory "${ANDROID_APK_DIR}" "${EXPORT_DIR}" + COMMAND cmake -E copy "$<TARGET_FILE:${QTANDROID_EXPORTED_TARGET}>" "${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=<targetname>") +endif() diff --git a/toolchain/deployment-file.json.in b/toolchain/deployment-file.json.in new file mode 100644 index 00000000..e662795a --- /dev/null +++ b/toolchain/deployment-file.json.in @@ -0,0 +1,15 @@ +{ + "qt": "@QTDIR@", + "sdk": "@ANDROID_SDK_ROOT@", + "ndk": "@ANDROID_NDK@", + "toolchain-prefix": "@ANDROID_TOOLCHAIN@", + "tool-prefix": "@ANDROID_TOOLCHAIN@", + "toolchain-version": "@ANDROID_GCC_VERSION@", + "ndk-host": "@_HOST@", + "target-architecture": "@ANDROID_ABI@", + "application-binary": "@EXECUTABLE_DESTINATION_PATH@", + "android-extra-libs": "@_DEPS@", + "android-extra-plugins": "@CMAKE_PREFIX_PATH@/share,@CMAKE_PREFIX_PATH@/lib/qml", + "android-package-source-directory": "@ANDROID_APK_DIR@", + "sdkBuildToolsRevision": "@ANDROID_SDK_BUILD_TOOLS_REVISION@" +} |