QtAndroidcmaKE tool is a guide how to build CMake based Qt
applications for Android on Linux systems. It uses the toolchain file in
the Android NDK. The guide is tested to work with Qt 5.13 and NDK version 20,
which uses the clang 8.0 compiler with c++_shared
stl.
Before you start, you need to install some required tools.
- Install openjdk
- Download Android sdk
- Download Android ndk
- Qt with pre-built libraries for Android (armeabi)
sdk/tools/bin/sdkmanager "build-tools;28.0.3" "platform-tools" "platforms;android-23"
Ensure you accept the Android java sdk license.
sdk/tools/bin/sdkmanager --licenses
For this part, we rely on the androiddeplyqt
tool provided by Qt.
The usage of this tool is bundled in the create_apk.cmake
file.
Set these environment variables, preferably using an activation script.
export JAVA_HOME=<path to jdk>
export ANDROID_SDK=<path to sdk>
export ANDROID_NDK=<path to ndk>
export QAKE_DIR=<path to qaketool>
The toolchain file from the NDK sets the ANDROID
variable. Use this for
Android specific settings, e.g. that the executable must be built as a
shared library for the apk.
if (ANDROID)
add_library(${PROJECT_NAME} SHARED ...)
else()
add_executable(${PROJECT_NAME} ...)
endif()
Include the create_apk.cmake
file and use the create_apk()
macro to define
the apk build. This is a minimal example.
if(ANDROID)
include($ENV{QAKE_DIR}/create_apk.cmake)
create_apk(${PROJECT_NAME}
VERSION_NAME "1.1"
)
endif()
The first argument to create_apk
is the name of the target for the application.
A make target called apk
will be generated.
NAME - The name of the application, as shown on the Android device. If not provided, the name of the source target will be used.
PACKAGE_NAME - The name of the application package. If not provided, io.qt.${PROJECT_NAME}
is used.
VERSION_CODE - Version code used by Google Play. Must be incremented when new version is published. Set to 1 if omitted.
VERSION_NAME - Displayed version of the application.
QML_PATH - Path to qml files to parse for required imports to include in the apk.
DEPENDENCIES - List of paths to shared libraries, built for Android, to include in the apk.
MANIFEST - Optional path to a AndroidManifest.xml file to use. It could be
based on the provided AndroidManifest.xml.in
since the same CMake substitutions
will be applied. If not set, the provided manifest is used.
if(ANDROID)
include($ENV{QAKE_DIR}/create_apk.cmake)
create_apk(${PROJECT_NAME}
NAME "SuperApp"
PACKAGE_NAME "com.domain.${PROJECT_NAME}
VERSION_CODE 1
VERSION_NAME "1.1"
QML_PATH ${CMAKE_CURRENT_SOURCE_DIR}/qml
MANIFEST ${CMAKE_CURRENT_SOURCE_DIR}/AndroidManifest.xml.in
)
endif()
To cross compile for Android, it is enough to point out the toolchain
file in the NDK and define the Android Api level. For Qt applications we must also
set CMAKE_PREFIX_PATH
to indicate to CMake where to find the pre-built
Qt libraries. Since the toolchain file appends the sysroot to all find paths,
we must also set CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
to find the Qt modules.
In NDK v16 the toolchain file is setup to use clang as the default
compiler and the gnu version of stl. The gnu stl in the NDK does not
support all features in C++11 and if you need these, the best option is to
build with llvm libc++ stl instead. But since Qt versions 5.9-5.10 use shared
gnu stl, we need to statically link our library with libc++ by setting
ANDROID_STL=c++_static
. In future versions of the NDK, libc++ will be default
and other ports of STL will be removed.
Now run CMake
.
mkdir build
cd build
cmake -DCMAKE_TOOLCHAIN_FILE=<path>/android-ndk-r20/build/cmake/android.toolchain.cmake -DCMAKE_PREFIX_PATH=<path>/qt/5.13.1/android_armv7/lib/cmake -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ON -DANDROID_NATIVE_API_LEVEL=android-23 -DANDROID_STL=c++_shared..
This will setup a Makefile for armeabi-v7a using clang as compiler and a shared
libc++ STL.
These can be changed with ANDROID_ABI
and ANDROID_STL
.
Then build the library for Android.
make
If everything is correctly setup, creating the apk is as simple as:
make apk
To install the apk on a connected Android phone, just use adb
from the Android sdk.
<path>/sdk/platform-tools/adb install -r <buildFolder>/build/outputs/apk/<name>.apk
It is possible to compile third party library as described above but sometimes it is better to use the NDK to generate a dedicated standalone toolchain.
This will be obsolete from NDK v19, since only one compiler and stl will then be included in the NDK.
Select the Android api level and architecture and run make_standalone_toolchain.py
from the NDK.
<path_to_ndk>/build/tools/make_standalone_toolchain.py --api 19 --arch arm --install-dir=<outpath>/standalone-toolchain
This will create a toolchain using the default gnustl in <outpath>/standalone-toolchain
.
Use the --stl
option to use another stl implementation.
If you omit the --install-dir
option, a tarball including the toolchain is created.
Activate the toolchain and ensure target_host
matches the toolchain.
# Add the standalone toolchain to the search path.
export PATH=$PATH:<path>/standalone-toolchain/bin
# Tell configure what tools to use.
target_host=arm-linux-androideabi
export AR=$target_host-ar
export AS=$target_host-clang
export CC=$target_host-clang
export CXX=$target_host-clang++
export LD=$target_host-ld
export STRIP=$target_host-strip
# Tell configure what flags Android requires.
export CFLAGS="-fPIE -fPIC"
export LDFLAGS="-pie"
./configure --host=arm-linux-androideabi
make
Use the toolchain as described above.
To build with the library, add its include and link directories.
if(ANDROID)
include_directories(<mylib>/include)
link_directories(<mylib>/libs)
endif()
Then include it in the apk.
if(ANDROID)
include($ENV{QAKE_DIR}/create_apk.cmake)
create_apk(${PROJECT_NAME}
DEPENDENCIES "<mylib>/libs/libmylib.so"
)
endif()