1 # How to use the Android NDK to build Arm NN
3 - [Introduction](#introduction)
4 - [Download the Android NDK and make a standalone toolchain](#download-the-android-ndk-and-make-a-standalone-toolchain)
5 - [Install Cmake](#install-cmake)
6 - [Build Google's Protobuf library](#build-google-s-protobuf-library)
7 - [Build Flatbuffers](#build-flatbuffers)
8 - [Download Arm NN](#download-arm-nn)
9 - [Build Arm Compute Library](#build-arm-compute-library)
10 - [Build Arm NN](#build-arm-nn)
11 - [Build Standalone Sample Dynamic Backend](#build-standalone-sample-dynamic-backend)
12 - [Run the Arm NN unit tests on an Android device](#run-the-armnn-unit-tests-on-an-android-device)
16 These are step by step instructions for using the Android NDK to build Arm NN.
17 They have been tested on a clean install of Ubuntu 18.04 and 20.04, and should also work with other OS versions.
18 The instructions show how to build the Arm NN core library.
19 Building protobuf is optional. We have given steps should the user wish to build it (i.e. as an Onnx dependency).
20 All downloaded or generated files will be saved inside the `$HOME/armnn-devenv` directory.
22 ## Download the Android NDK and make a standalone toolchain
24 * Download the Android NDK from [the official website](https://developer.android.com/ndk/downloads/index.html):
26 mkdir -p $HOME/armnn-devenv/
27 cd $HOME/armnn-devenv/
28 # For Mac OS, change the NDK download link accordingly.
29 wget https://dl.google.com/android/repository/android-ndk-r20b-linux-x86_64.zip
30 unzip android-ndk-r20b-linux-x86_64.zip
31 export NDK=$HOME/armnn-devenv/android-ndk-r20b
32 export NDK_TOOLCHAIN_ROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_64
33 export PATH=$NDK_TOOLCHAIN_ROOT/bin/:$PATH
35 # You may want to append the above export variables commands to your `~/.bashrc` (or `~/.bash_profile` in Mac OS).
38 * With the android ndk-20b, you don't need to use the make_standalone_toolchain script to create a toolchain for a specific version of android. Android's current preference is for you to just specify the architecture and operating system while setting the compiler and just use the ndk directory.
41 Cmake 3.19rc3 is required to build Arm NN.
45 sudo apt-get install libssl-dev
46 wget https://github.com/Kitware/CMake/releases/download/v3.19.0-rc3/cmake-3.19.0-rc3.tar.gz
47 tar -zxvf cmake-3.19.0-rc3.tar.gz
49 ./bootstrap --prefix=$HOME/armnn-devenv/cmake/install
54 ## Build Google's Protobuf library (Optional)
57 (Requires Git if not previously installed: `sudo apt install git`)
59 mkdir $HOME/armnn-devenv/google
60 cd $HOME/armnn-devenv/google
61 git clone https://github.com/google/protobuf.git
63 git checkout -b v3.12.0 v3.12.0
66 * Build a native (x86) version of the protobuf libraries and compiler (protoc):
67 (Requires cUrl, autoconf, llibtool, and other build dependencies if not previously installed: `sudo apt install curl autoconf libtool build-essential g++`)
72 ../configure --prefix=$HOME/armnn-devenv/google/x86_64_pb_install
77 * Build the arm64 version of the protobuf libraries:
81 CC=aarch64-linux-android<Android_API>-clang \
82 CXX=aarch64-linux-android<Android_API>-clang++ \
83 CFLAGS="-fPIE -fPIC" \
84 LDFLAGS="-llog -lz -lc++_static" \
85 ../configure --host=aarch64-linux-android \
86 --prefix=$HOME/armnn-devenv/google/arm64_pb_install \
87 --enable-cross-compile \
88 --with-protoc=$HOME/armnn-devenv/google/x86_64_pb_install/bin/protoc
93 Note: The ANDROID_API variable should be set to the Android API version number you are using. E.g. "30" for Android R.
97 * Download Flatbuffers
100 wget -O flatbuffers-1.12.0.tar.gz https://github.com/google/flatbuffers/archive/v1.12.0.tar.gz
101 tar xf flatbuffers-1.12.0.tar.gz
106 cd flatbuffers-1.12.0
111 CXXFLAGS="-fPIC" $CMAKE .. \
112 -DFLATBUFFERS_BUILD_FLATC=1 \
113 -DCMAKE_INSTALL_PREFIX:PATH=$WORKING_DIR/flatbuffers
117 Note: -fPIC is added to allow users to use the libraries in shared objects.
121 (Requires Git if not previously installed: `sudo apt install git`)
124 cd $HOME/armnn-devenv
125 git clone https://github.com/ARM-software/armnn.git
128 * Checkout Arm NN branch:
131 git checkout <branch_name>
135 For example, if you want to check out the 21.11 release branch:
137 git checkout branches/armnn_21_11
141 ## Build Arm Compute Library
142 * Clone Arm Compute Library:
145 cd $HOME/armnn-devenv
146 git clone https://github.com/ARM-software/ComputeLibrary.git
148 * Checkout Arm Compute Library release tag:
151 git checkout <tag_name>
153 For example, if you want to checkout the 21.11 release tag:
158 Arm NN and Arm Compute Library are developed closely together. If you would like to use a particular release of Arm NN you will need the same release tag of ACL too.
160 Arm NN provides a script that downloads the version of Arm Compute Library that Arm NN was tested with:
162 git checkout $(../armnn/scripts/get_compute_library.sh -p)
164 * the Arm Compute Library:
165 (Requires SCons if not previously installed: `sudo apt install scons`)
167 scons arch=arm64-v8a neon=1 opencl=1 embed_kernels=1 extra_cxx_flags="-fPIC" \
168 benchmark_tests=0 validation_tests=0 os=android -j16
174 (Requires CMake if not previously installed: `sudo apt install cmake`)
176 mkdir $HOME/armnn-devenv/armnn/build
177 cd $HOME/armnn-devenv/armnn/build
178 CXX=aarch64-linux-android<Android_API>-clang++ \
179 CC=aarch64-linux-android<Android_API>-clang \
180 CXX_FLAGS="-fPIE -fPIC" \
182 -DCMAKE_ANDROID_NDK=$NDK \
183 -DCMAKE_SYSTEM_NAME=Android \
184 -DCMAKE_SYSTEM_VERSION=<Android_API> \
185 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
186 -DCMAKE_EXE_LINKER_FLAGS="-pie -llog -lz" \
187 -DARMCOMPUTE_ROOT=$HOME/armnn-devenv/ComputeLibrary/ \
188 -DARMCOMPUTE_BUILD_DIR=$HOME/armnn-devenv/ComputeLibrary/build \
189 -DARMCOMPUTENEON=1 -DARMCOMPUTECL=1 -DARMNNREF=1 \
190 -DPROTOBUF_ROOT=$HOME/armnn-devenv/google/arm64_pb_install/
191 -DFLATBUFFERS_ROOT=$HOME/armnn-devenv/flatbuffers \
192 -DFLATC_DIR=$HOME/armnn-devenv/flatbuffers-1.12.0/build \
195 To include standalone sample dynamic backend tests, add the argument to enable the tests and the dynamic backend path to the CMake command:
198 -DSAMPLE_DYNAMIC_BACKEND=1 \
199 -DDYNAMIC_BACKEND_PATHS=$SAMPLE_DYNAMIC_BACKEND_PATH
200 # Where $SAMPLE_DYNAMIC_BACKEND_PATH is the path where libArm_SampleDynamic_backend.so library file is pushed
208 ## Build Standalone Sample Dynamic Backend
209 * The sample dynamic backend is located in armnn/src/dynamic/sample
215 * Use CMake to configure the build environment, update the following script and run it from the armnn/src/dynamic/sample/build directory to set up the Arm NN build:
218 CXX=aarch64-linux-android<Android_API>-clang++ \
219 CC=aarch64-linux-android<Android_API>-clang \
220 CXX_FLAGS="-fPIE -fPIC" \
222 -DCMAKE_C_COMPILER_WORKS=TRUE \
223 -DCMAKE_CXX_COMPILER_WORKS=TRUE \
224 -DCMAKE_ANDROID_NDK=$NDK \
225 -DCMAKE_SYSTEM_NAME=Android \
226 -DCMAKE_SYSTEM_VERSION=$ANDROID_API \
227 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
228 -DCMAKE_SYSROOT=$HOME/armnn-devenv/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
229 -DCMAKE_CXX_FLAGS=--std=c++14 \
230 -DCMAKE_EXE_LINKER_FLAGS="-pie -llog" \
231 -DCMAKE_MODULE_LINKER_FLAGS="-llog" \
232 -DARMNN_PATH=$HOME/armnn-devenv/armnn/build/libarmnn.so ..
240 ## Run the Arm NN unit tests on an Android device
243 * Push the build results to an Android device and make symbolic links for shared libraries:
244 Currently adb version we have used for testing is 1.0.41.
246 adb push libarmnn.so /data/local/tmp/
247 adb push libtimelineDecoder.so /data/local/tmp/
248 adb push UnitTests /data/local/tmp/
249 adb push $NDK/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so /data/local/tmp/
250 adb push $HOME/armnn-devenv/google/arm64_pb_install/lib/libprotobuf.so /data/local/tmp/libprotobuf.so.23.0.0
251 adb shell 'ln -s libprotobuf.so.23.0.0 /data/local/tmp/libprotobuf.so.23'
252 adb shell 'ln -s libprotobuf.so.23.0.0 /data/local/tmp/libprotobuf.so'
255 * Push the files needed for the unit tests (they are a mix of files, directories and symbolic links):
257 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/testSharedObject
258 adb push -p $HOME/armnn-devenv/armnn/build/src/backends/backendsCommon/test/testSharedObject/* /data/local/tmp/src/backends/backendsCommon/test/testSharedObject/
260 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/testDynamicBackend
261 adb push -p $HOME/armnn-devenv/armnn/build/src/backends/backendsCommon/test/testDynamicBackend/* /data/local/tmp/src/backends/backendsCommon/test/testDynamicBackend/
263 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath1
264 adb push -p $HOME/armnn-devenv/armnn/build/src/backends/backendsCommon/test/backendsTestPath1/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath1/
266 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2
267 adb push -p $HOME/armnn-devenv/armnn/build/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/
268 adb shell ln -s Arm_CpuAcc_backend.so /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so.1
269 adb shell ln -s Arm_CpuAcc_backend.so.1 /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so.1.2
270 adb shell ln -s Arm_CpuAcc_backend.so.1.2 /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so.1.2.3
271 adb push -p $HOME/armnn-devenv/armnn/build/src/backends/backendsCommon/test/backendsTestPath2/Arm_GpuAcc_backend.so /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/
272 adb shell ln -s nothing /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_no_backend.so
274 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath3
276 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath5
277 adb push -p $HOME/armnn-devenv/armnn/build/src/backends/backendsCommon/test/backendsTestPath5/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath5/
279 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath6
280 adb push -p $HOME/armnn-devenv/armnn/build/src/backends/backendsCommon/test/backendsTestPath6/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath6/
282 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath7
284 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath9
285 adb push -p $HOME/armnn-devenv/armnn/build/src/backends/backendsCommon/test/backendsTestPath9/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath9/
287 adb shell mkdir -p /data/local/tmp/src/backends/dynamic/reference
288 adb push -p $HOME/armnn-devenv/armnn/build/src/backends/dynamic/reference/Arm_CpuRef_backend.so /data/local/tmp/src/backends/dynamic/reference/
290 # If the standalone sample dynamic tests are enabled, also push libArm_SampleDynamic_backend.so library file to the folder specified as $SAMPLE_DYNAMIC_BACKEND_PATH when Arm NN is built.
291 # This is the example when $SAMPLE_DYNAMIC_BACKEND_PATH is specified as /data/local/tmp/dynamic/sample/:
293 adb shell mkdir -p /data/local/tmp/dynamic/sample/
294 adb push -p $HOME/armnn-devenv/armnn/src/dynamic/sample/build/libArm_SampleDynamic_backend.so /data/local/tmp/dynamic/sample/
297 * Run Arm NN unit tests:
299 adb shell 'LD_LIBRARY_PATH=/data/local/tmp:/vendor/lib64:/vendor/lib64/egl /data/local/tmp/UnitTests'
301 If libarmnnUtils.a is present in `$HOME/armnn-devenv/armnn/build/` and the unit tests run without failure then the build was successful.