# Build PaddlePaddle for Android There are two approaches to build PaddlePaddle for Android: using Docker and on Linux without Docker. ## Cross-Compiling Using Docker Docker-based cross-compiling is the recommended approach because Docker runs on all major operating systems, including Linux, Mac OS X, and Windows. ### Build the Docker Image The following steps pack all the tools that we need to build PaddlePaddle into a Docker image. ```bash $ git clone https://github.com/PaddlePaddle/Paddle.git $ cd Paddle $ docker build -t paddle:dev-android . -f Dockerfile.android ``` ### Build the Inference Library We can run the Docker image we just created to build the inference library of PaddlePaddle for Android using the command below: ```bash $ docker run -it --rm -v $PWD:/paddle -e "ANDROID_ABI=armeabi-v7a" -e "ANDROID_API=21" paddle:dev-android ``` The Docker image accepts two arguments `ANDROID_ABI` and `ANDROID_API`: | Argument | Optional Values | Default | |-----------------|-------------------------|---------| |`ANDROID_ABI` |`armeabi-v7a, arm64-v8a` | `armeabi-v7a` | |`ANDROID_API` |`>= 21` | `21` | The ARM-64 architecture (`arm64-v8a`) requires at least level 21 of Android API. The default entry-point of the Docker image, [`paddle/scripts/docker/build_android.sh`](https://github.com/PaddlePaddle/Paddle/blob/develop/paddle/scripts/docker/build_android.sh) generates the [Android cross-compiling standalone toolchain](https://developer.android.com/ndk/guides/standalone_toolchain.html) based on the argument: `ANDROID_ABI` or `ANDROID_API`. For information about other configuration arguments, please continue reading. The above command generates and outputs the inference library in `$PWD/install_android` and puts third-party libraries in `$PWD/install_android/third_party`. ## Cross-Compiling on Linux The Linux-base approach to cross-compile is to run steps in `Dockerfile.android` manually on a Linux x64 computer. ### Setup the Environment To build for Android's, we need [Android NDK]( https://developer.android.com/ndk/downloads/index.html): ```bash wget -q https://dl.google.com/android/repository/android-ndk-r14b-linux-x86_64.zip unzip -q android-ndk-r14b-linux-x86_64.zip ``` Android NDK includes everything we need to build the [*standalone toolchain*](https://developer.android.com/ndk/guides/standalone_toolchain.html), which in then used to build PaddlePaddle for Android. (We plan to remove the intermediate stage of building the standalone toolchain in the near future.) - To build the standalone toolchain for `armeabi-v7a` and Android API level 21: ```bash your/path/to/android-ndk-r14b-linux-x86_64/build/tools/make-standalone-toolchain.sh \ --arch=arm --platform=android-21 --install-dir=your/path/to/arm_standalone_toolchain ``` The generated standalone toolchain will be in `your/path/to/arm_standalone_toolchain`. - To build the standalone toolchain for `arm64-v8a` and Android API level 21: ```bash your/path/to/android-ndk-r14b-linux-x86_64/build/tools/make-standalone-toolchain.sh \ --arch=arm64 --platform=android-21 --install-dir=your/path/to/arm64_standalone_toolchain ``` The generated standalone toolchain will be in `your/path/to/arm64_standalone_toolchain`. **Please be aware that the minimum level of Android API required by PaddlePaddle is 21.** ### Cross-Compiling Arguments CMake supports [choosing the toolchain](https://cmake.org/cmake/help/v3.0/manual/cmake-toolchains.7.html#cross-compiling). PaddlePaddle provides [`android.cmake`](https://github.com/PaddlePaddle/Paddle/blob/develop/cmake/cross_compiling/android.cmake), which configures the Android cross-compiling toolchain for CMake. `android.cmake` is not required for CMake >= 3.7, which support Android cross-compiling. PaddlePaddle detects the CMake version, for those newer than 3.7, it uses [the official version](https://cmake.org/cmake/help/v3.7/manual/cmake-toolchains.7.html#cross-compiling). Some other CMake arguments you need to know: - `CMAKE_SYSTEM_NAME` must be `Android`. This tells PaddlePaddle's CMake system to cross-compile third-party dependencies. This also changes some other CMake arguments like `WITH_GPU=OFF`, `WITH_AVX=OFF`, `WITH_PYTHON=OFF`, and `WITH_RDMA=OFF`. - `WITH_C_API` must be `ON`, to build the C-based inference library for Android. - `WITH_SWIG_PY` must be `OFF` because the Android platform doesn't support SWIG-based API. Some Android-specific arguments: - `ANDROID_STANDALONE_TOOLCHAIN`: the absolute path of the Android standalone toolchain, or the path relative to the CMake build directory. PaddlePaddle's CMake extensions would derive the cross-compiler, sysroot and Android API level from this argument. - `ANDROID_TOOLCHAIN`: could be `gcc` or `clang`. The default value is `clang`. - For CMake >= 3.7, it should anyway be `clang`. For older versions, it could be `gcc`. - Android's official `clang` requires `glibc` >= 2.15. - `ANDROID_ABI`: could be `armeabi-v7a` or `arm64-v8a`. The default value is `armeabi-v7a`. - `ANDROID_NATIVE_API_LEVEL`: could be derived from the value of `ANDROID_STANDALONE_TOOLCHAIN`. - `ANROID_ARM_MODE`: - could be `ON` or `OFF`, and defaults to `ON`, when `ANDROID_ABI=armeabi-v7a`; - no need to specify when `ANDROID_ABI=arm64-v8a`. - `ANDROID_ARM_NEON`: indicates if to use NEON instructions. - could be `ON` or `OFF`, and defaults to `ON`, when `ANDROID_ABI=armeabi-v7a`; - no need to specify when `ANDROID_ABI=arm64-v8a`. Other useful arguments: - `USE_EIGEN_FOR_BLAS`: indicates if using Eigen. Could be `ON` or `OFF`, defaults to `OFF`. - `HOST_C/CXX_COMPILER`: specifies the host compiler, which is used to build the host-specific protoc and target-specific OpenBLAS. It defaults to the value of the environment variable `CC`, or `cc`. Some frequent configurations for your reference: ```bash cmake -DCMAKE_SYSTEM_NAME=Android \ -DANDROID_STANDALONE_TOOLCHAIN=your/path/to/arm_standalone_toolchain \ -DANDROID_ABI=armeabi-v7a \ -DANDROID_ARM_NEON=ON \ -DANDROID_ARM_MODE=ON \ -DUSE_EIGEN_FOR_BLAS=ON \ -DCMAKE_INSTALL_PREFIX=your/path/to/install \ -DWITH_C_API=ON \ -DWITH_SWIG_PY=OFF \ .. ``` ``` cmake -DCMAKE_SYSTEM_NAME=Android \ -DANDROID_STANDALONE_TOOLCHAIN=your/path/to/arm64_standalone_toolchain \ -DANDROID_ABI=arm64-v8a \ -DUSE_EIGEN_FOR_BLAS=OFF \ -DCMAKE_INSTALL_PREFIX=your/path/to/install \ -DWITH_C_API=ON \ -DWITH_SWIG_PY=OFF \ .. ``` There are some other arguments you might want to configure. - `CMAKE_BUILD_TYPE=MinSizeRel` minimizes the size of library. - `CMAKE_BUILD_TYPE-Release` optimizes the runtime performance. Our own tip for performance optimization to use clang and Eigen or OpenBLAS: - `CMAKE_BUILD_TYPE=Release` - `ANDROID_TOOLCHAIN=clang` - `USE_EIGEN_BLAS=ON` for `armeabi-v7a`, or `USE_EIGEN_FOR_BLAS=OFF` for `arm64-v8a`. ### Build and Install After running `cmake`, we can run `make; make install` to build and install. Before building, you might want to remove the `third_party` and `build` directories including pre-built libraries for other architectures. After building,in the directory `CMAKE_INSTALL_PREFIX`, you will find three sub-directories: - `include`: the header file of the inference library, - `lib`: the inference library built for various Android ABIs, - `third_party`: dependent third-party libraries built for Android.