xref: /aosp_15_r20/external/armnn/BuildGuideAndroidNDK.md (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1# How to use the Android NDK to build Arm NN
2
3- [Introduction](#introduction)
4- [Initial Setup](#initial-setup)
5- [Download the Android NDK and make a standalone toolchain](#download-the-android-ndk-and-make-a-standalone-toolchain)
6- [Install Cmake](#install-cmake)
7- [Build Flatbuffers](#build-flatbuffers)
8- [Download Arm NN](#download-arm-nn)
9- [Get And Build TFLite](#get-and-build-tflite)
10- [Build Arm Compute Library](#build-arm-compute-library)
11- [Build Arm NN](#build-arm-nn)
12- [Build Standalone Sample Dynamic Backend](#build-standalone-sample-dynamic-backend)
13- [Run the Arm NN unit tests on an Android device](#run-the-arm-nn-unit-tests-on-an-android-device)
14
15
16## Introduction
17These are step-by-step instructions for using the Android NDK to build Arm NN.
18They have been tested on a clean installation of Ubuntu 18.04 and 20.04, and should also work with other OS versions.
19The instructions show how to build the Arm NN core library and its dependencies.
20
21For ease of use there is a shell script version of this guide located in the scripts directory called [build_android_ndk_guide.sh](scripts/build_android_ndk_guide.sh).
22Run the script with a -h flag to see the command line parameters.
23
24## Initial Setup
25
26First, we need to specify the Android version and the directories you want to build armnn in and to install some applications required to build Arm NN and its dependencies.
27
28```bash
29export ANDROID_API=30
30export WORKING_DIR=$HOME/armnn-devenv
31export NDK_DIR=$WORKING_DIR/android-ndk-r25
32export NDK_TOOLCHAIN_ROOT=$NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64
33export PATH=$NDK_TOOLCHAIN_ROOT/bin/:$PATH
34```
35You may want to append the above export variables commands to your `~/.bashrc` (or `~/.bash_profile` in macOS).
36
37The ANDROID_API variable should be set to the Android API version number you are using. For example, "30" for Android R. The WORKING_DIR can be any directory you have write permissions to.
38
39### Required Applications
40Git is required to obtain Arm NN. If this has not been already installed then install it using:
41```bash
42sudo apt install git
43```
44
45Arm Compute Library requires SCons. If this has not been already installed then install it using:
46```bash
47sudo apt install scons
48```
49
50CMake is required to build Arm NN and its dependencies. If this has not been already installed then install it using:
51```bash
52sudo apt install cmake
53```
54
55## Download the Android NDK and make a standalone toolchain
56
57Download the Android NDK from [the official website](https://developer.android.com/ndk/downloads/index.html):
58```bash
59mkdir -p $WORKING_DIR
60cd $WORKING_DIR
61# For Mac OS, change the NDK download link accordingly.
62wget https://dl.google.com/android/repository/android-ndk-r25-linux.zip
63unzip android-ndk-r25-linux.zip
64```
65With Android NDK-25, you no longer 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.
66
67## Install Cmake
68Cmake 3.19rc3 or later is required to build Arm NN. If you are using Ubuntu 20.04 the command given in [Initial Setup](#initial-setup) should install a usable version. If you're using Ubuntu 18.04 you may need to compile cmake yourself.
69
70```bash
71cd $WORKING_DIR
72sudo apt-get install libssl-dev
73wget https://github.com/Kitware/CMake/releases/download/v3.19.0-rc3/cmake-3.19.0-rc3.tar.gz
74tar -zxvf cmake-3.19.0-rc3.tar.gz
75cd cmake-3.19.0-rc3
76./bootstrap --prefix=$WORKING_DIR/cmake/install
77make all install
78cd..
79```
80
81## Build Flatbuffers
82
83Download Flatbuffers:
84```bash
85cd $WORKING_DIR
86wget https://github.com/google/flatbuffers/archive/v2.0.6.tar.gz
87tar xf v2.0.6.tar.gz
88```
89
90Build Flatbuffers for x86:
91```bash
92cd $WORKING_DIR/flatbuffers-2.0.6
93
94rm -f CMakeCache.txt
95
96rm -rf build-x86
97mkdir build-x86
98cd build-x86
99
100rm -rf $WORKING_DIR/flatbuffers-x86
101mkdir $WORKING_DIR/flatbuffers-x86
102
103CXXFLAGS="-fPIC" $CMAKE .. \
104    -DFLATBUFFERS_BUILD_FLATC=1 \
105    -DCMAKE_INSTALL_PREFIX:PATH=$WORKING_DIR/flatbuffers-x86
106
107make all install -j16
108```
109Note: -fPIC is added to allow users to use the libraries in shared objects.
110
111Build Flatbuffers for Android:
112```bash
113cd $WORKING_DIR/flatbuffers-2.0.6
114
115rm -f CMakeCache.txt
116
117rm -rf build-android
118mkdir build-android
119cd build-android
120
121rm -rf $WORKING_DIR/flatbuffers-android
122mkdir $WORKING_DIR/flatbuffers-android
123
124CC=/usr/bin/aarch64-linux-gnu-gcc CXX=/usr/bin/aarch64-linux-gnu-g++ \
125CXXFLAGS="-fPIC" \
126cmake .. \
127    -DCMAKE_ANDROID_NDK=$NDK_DIR \
128    -DCMAKE_SYSTEM_NAME=Android \
129    -DCMAKE_SYSTEM_VERSION=27 \
130    -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
131    -DCMAKE_CXX_FLAGS=--std=c++14 \
132    -DFLATBUFFERS_BUILD_FLATC=OFF \
133    -DCMAKE_BUILD_TYPE=Release \
134    -DFLATBUFFERS_BUILD_TESTS=OFF \
135    -DCMAKE_INSTALL_PREFIX=$WORKING_DIR/flatbuffers-android
136
137make all install -j16
138```
139
140## Download Arm NN
141Clone Arm NN:
142
143```bash
144cd $WORKING_DIR
145git clone https://github.com/ARM-software/armnn.git
146```
147
148Checkout the Arm NN branch:
149```bash
150cd armnn
151git checkout <branch_name>
152git pull
153```
154
155For example, if you want to check out the 23.02 release branch:
156```bash
157cd armnn
158git checkout branches/armnn_23_02
159git pull
160```
161
162## Get And Build TFLite
163This optional step is only required if you intend to build the TFLite delegate or parser for Arm NN.
164
165First clone tensorflow:
166```bash
167cd $WORKING_DIR
168git clone https://github.com/tensorflow/tensorflow.git
169cd tensorflow
170git fetch && git checkout "tags/v2.10.0"
171```
172Arm NN provides a script that downloads the version of Tensorflow that Arm NN was tested with:
173```bash
174git fetch && git checkout $(../armnn/scripts/get_tensorflow.sh -p)
175```
176Next build Tensorflow Lite:
177```bash
178cd $WORKING_DIR
179mkdir -p tflite-out/android
180cd tflite-out/android
181
182CMARGS="-DCMAKE_TOOLCHAIN_FILE=$NDK_DIR/build/cmake/android.toolchain.cmake \
183    -DANDROID_ABI=arm64-v8a \
184    -DANDROID_PLATFORM=$ANDROID_API"
185
186cmake $CMARGS $WORKING_DIR/tensorflow/tensorflow/lite
187
188cd $WORKING_DIR
189cmake --build tflite-out/android -j 16
190```
191Now generate the Tensorflow Lite Schema for the TFLite parser:
192```bash
193cd $WORKING_DIR
194mkdir -p $WORKING_DIR/tflite-out/tensorflow/tensorflow/lite/schema
195
196SCHEMA_LOCATION=$WORKING_DIR/tensorflow/tensorflow/lite/schema/schema.fbs
197cp $SCHEMA_LOCATION $WORKING_DIR/tflite-out/tensorflow/tensorflow/lite/schema
198
199cd $WORKING_DIR/tflite-out/tensorflow/tensorflow/lite/schema
200$WORKING_DIR/flatbuffers-x86/bin/flatc -c --gen-object-api --reflect-types --reflect-names schema.fbs
201```
202
203## Build Arm Compute Library
204Clone Arm Compute Library:
205
206```bash
207cd $WORKING_DIR
208git clone https://github.com/ARM-software/ComputeLibrary.git
209```
210Checkout Arm Compute Library release tag:
211```bash
212cd ComputeLibrary
213git checkout <tag_name>
214```
215For example, if you want to check out the 23.02 release tag:
216```bash
217cd ComputeLibrary
218git checkout v23.02
219```
220
221Arm NN and Arm Compute Library are developed closely together. To use a particular version of Arm NN you will need a compatible version of ACL.
222Arm NN provides a script that downloads the version of Arm Compute Library that Arm NN was tested with:
223```bash
224git checkout $(../armnn/scripts/get_compute_library.sh -p)
225```
226Build the Arm Compute Library:
227```bash
228scons arch=arm64-v8a os=android toolchain_prefix=llvm- compiler_prefix=aarch64-linux-android$ANDROID_API- \
229    neon=1 opencl=1 embed_kernels=1 extra_cxx_flags="-fPIC" \
230    benchmark_tests=0 validation_tests=0 -j16
231```
232
233## Build Arm NN
234
235Build Arm NN:
236
237```bash
238mkdir $WORKING_DIR/armnn/build
239cd $WORKING_DIR/armnn/build
240CXX=aarch64-linux-android$ANDROID_API-clang++ \
241CC=aarch64-linux-android$ANDROID_API-clang \
242CXX_FLAGS="-fPIE -fPIC" \
243cmake .. \
244    -DCMAKE_BUILD_TYPE=Release \
245    -DCMAKE_ANDROID_NDK=$NDK_DIR \
246    -DNDK_VERSION=r25 \
247    -DCMAKE_SYSTEM_NAME=Android \
248    -DCMAKE_SYSTEM_VERSION=$ANDROID_API \
249    -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
250    -DCMAKE_SYSROOT=$WORKING_DIR/android-ndk-r25/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
251    -DARMCOMPUTE_ROOT=$WORKING_DIR/ComputeLibrary \
252    -DARMCOMPUTE_BUILD_DIR=$WORKING_DIR/ComputeLibrary/build \
253    -DARMCOMPUTENEON=1 -DARMCOMPUTECL=1 -DARMNNREF=1 \
254    -DFLATBUFFERS_INCLUDE_PATH=$WORKING_DIR/flatbuffers-x86/include \
255    -DFLATBUFFERS_ROOT=$WORKING_DIR/flatbuffers-android \
256    -DFLATC_DIR=$WORKING_DIR/flatbuffers-x86 \
257    -DBUILD_UNIT_TESTS=1 \
258    -DBUILD_TESTS=1 \
259    -fexception \
260```
261
262To include the Arm NN TFLite delegate add these arguments to the above list:
263
264```bash
265    -DBUILD_ARMNN_TFLITE_DELEGATE=1 \
266    -DTENSORFLOW_ROOT=$WORKING_DIR/tensorflow \
267    -DTFLITE_LIB_ROOT=$WORKING_DIR/tflite-out/android \
268    -DTFLITE_ROOT_DIR=$WORKING_DIR/tensorflow/tensorflow/lite \
269```
270
271To include the Arm NN TFLite Parser add these arguments to the above list:
272
273```bash
274    -DBUILD_TF_LITE_PARSER=1 \
275    -DTF_LITE_GENERATED_PATH=$WORKING_DIR/tflite-out/tensorflow/tensorflow/lite/schema \
276    -DTENSORFLOW_ROOT=$WORKING_DIR/tensorflow \
277    -DTFLITE_LIB_ROOT=$WORKING_DIR/tflite-out/android \
278```
279
280To include standalone sample dynamic backend tests, add these arguments to enable the tests and the dynamic backend path to the CMake command:
281
282```bash
283    -DSAMPLE_DYNAMIC_BACKEND=1 \
284    -DDYNAMIC_BACKEND_PATHS=$SAMPLE_DYNAMIC_BACKEND_PATH
285# Where $SAMPLE_DYNAMIC_BACKEND_PATH is the path where libArm_SampleDynamic_backend.so library file is pushed
286```
287
288 * Run the build
289```bash
290make -j16
291```
292
293## Build Standalone Sample Dynamic Backend
294This step is optional. The sample dynamic backend is located in armnn/src/dynamic/sample
295```bash
296mkdir build
297cd build
298```
299
300* 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:
301```bash
302#!/bin/bash
303CXX=aarch64-linux-android$ANDROID_API-clang++ \
304CC=aarch64-linux-android$ANDROID_API-clang \
305CXX_FLAGS="-fPIE -fPIC" \
306cmake \
307    -DCMAKE_C_COMPILER_WORKS=TRUE \
308    -DCMAKE_CXX_COMPILER_WORKS=TRUE \
309    -DCMAKE_ANDROID_NDK=$NDK_DIR \
310    -DCMAKE_SYSTEM_NAME=Android \
311    -DCMAKE_SYSTEM_VERSION=$ANDROID_API \
312    -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
313    -DCMAKE_SYSROOT=$WORKING_DIR/android-ndk-r25/toolchains/llvm/prebuilt/linux-x86_64/sysroot \
314    -DCMAKE_CXX_FLAGS=--std=c++14 \
315    -DCMAKE_EXE_LINKER_FLAGS="-pie -llog" \
316    -DCMAKE_MODULE_LINKER_FLAGS="-llog" \
317    -DARMNN_PATH=$WORKING_DIR/armnn/build/libarmnn.so ..
318```
319
320* Run the build
321```bash
322make
323```
324
325## Run the Arm NN unit tests on an Android device
326
327
328* Push the build results to an Android device and make symbolic links for shared libraries:
329  Currently adb version we have used for testing is 1.0.41.
330```bash
331adb push libarmnn.so /data/local/tmp/
332    adb push libtimelineDecoder.so /data/local/tmp/
333adb push UnitTests /data/local/tmp/
334adb push $NDK_DIR/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so /data/local/tmp/
335```
336
337* Push the files needed for the unit tests (they are a mix of files, directories and symbolic links):
338```bash
339adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/testSharedObject
340adb push -p $WORKING_DIR/armnn/build/src/backends/backendsCommon/test/testSharedObject/* /data/local/tmp/src/backends/backendsCommon/test/testSharedObject/
341
342adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/testDynamicBackend
343adb push -p $WORKING_DIR/armnn/build/src/backends/backendsCommon/test/testDynamicBackend/* /data/local/tmp/src/backends/backendsCommon/test/testDynamicBackend/
344
345adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath1
346adb push -p $WORKING_DIR/armnn/build/src/backends/backendsCommon/test/backendsTestPath1/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath1/
347
348adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2
349adb push -p $WORKING_DIR/armnn/build/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/
350adb shell ln -s Arm_CpuAcc_backend.so /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so.1
351adb shell ln -s Arm_CpuAcc_backend.so.1 /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so.1.2
352adb shell ln -s Arm_CpuAcc_backend.so.1.2 /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so.1.2.3
353adb push -p $WORKING_DIR/armnn/build/src/backends/backendsCommon/test/backendsTestPath2/Arm_GpuAcc_backend.so /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/
354adb shell ln -s nothing /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_no_backend.so
355
356adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath3
357
358adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath5
359adb push -p $WORKING_DIR/armnn/build/src/backends/backendsCommon/test/backendsTestPath5/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath5/
360
361adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath6
362adb push -p $WORKING_DIR/armnn/build/src/backends/backendsCommon/test/backendsTestPath6/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath6/
363
364adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath7
365
366adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath9
367adb push -p $WORKING_DIR/armnn/build/src/backends/backendsCommon/test/backendsTestPath9/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath9/
368
369adb shell mkdir -p /data/local/tmp/src/backends/dynamic/reference
370adb push -p $WORKING_DIR/armnn/build/src/backends/dynamic/reference/Arm_CpuRef_backend.so /data/local/tmp/src/backends/dynamic/reference/
371```
372
373If 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.
374This is the example when $SAMPLE_DYNAMIC_BACKEND_PATH is specified as /data/local/tmp/dynamic/sample/:
375
376```bash
377adb shell mkdir -p /data/local/tmp/dynamic/sample/
378adb push -p $WORKING_DIR/armnn/src/dynamic/sample/build/libArm_SampleDynamic_backend.so /data/local/tmp/dynamic/sample/
379```
380If the delegate was built, push the delegate unit tests too.
381```bash
382adb push $WORKING_DIR/armnn/build/delegate/DelegateUnitTests /data/local/tmp/
383adb push $WORKING_DIR/armnn/build/delegate/libarmnnDelegate.so /data/local/tmp/
384```
385Run Arm NN unit tests:
386```bash
387adb shell 'LD_LIBRARY_PATH=/data/local/tmp:/vendor/lib64:/vendor/lib64/egl /data/local/tmp/UnitTests'
388```
389If the delegate was built run Arm Delegate NN unit tests:
390```bash
391adb shell 'LD_LIBRARY_PATH=/data/local/tmp:/vendor/lib64:/vendor/lib64/egl /data/local/tmp/DelegateUnitTests'
392```
393If libarmnnUtils.a is present in `$WORKING_DIR/armnn/build/` and the unit tests run without failure then the build was successful.
394