How did I build Arm NN using Android NDK

Payal Jindal
5 min readSep 7, 2021

I was working on a project for which I had to build Arm NN on my laptop. Searching the Internet I found some articles on how to do it, but even then I encountered many errors that required a lot of effort and time to be resolved. I really want to thank Jhilik Bhattacharya Ma’am for helping me all along. I mainly referred these two articles — First and Second. So, I decided to write a detailed tutorial on how did I build it using Android NDK.

My Ubuntu version — 20.04

NOTE: If your operating system version is 16.04, it is preferable that you use version r17b of Android NDK. Rest all the process will remain same.

Let’s get started.

I saved everything that was downloaded or generated to the $HOME/armnn-devenv folder.

mkdir -p $HOME/armnn-devenv/

Step 1- Android NDK

I have downloaded version r20. You may modify the download link depending on which version you need or your operating system.

To download r17b use this. For this version, you also need to make a standalone toolchain(Refer this) which is not required for version r20b.

cd $HOME/armnn-devenv/wget https://dl.google.com/android/repository/android-ndk-r20b-linux-x86_64.zipunzip android-ndk-r20b-linux-x86_64.zipexport NDK=$HOME/armnn-devenv/android-ndk-r20bexport NDK_TOOLCHAIN_ROOT=$NDK/toolchains/llvm/prebuilt/linux-x86_644export PATH=$NDK_TOOLCHAIN_ROOT/bin/:$PATH

Also, add these variables in your $HOME/.bashrc file.

cd $HOMEsudo gedit .bashrc

Then, in your .bashrc file, add the following three lines at the end -

NDK="$HOME/armnn-devenv/android-ndk-r20b"
NDK_TOOLCHAIN_ROOT="$NDK/toolchains/llvm/prebuilt/linux-x86_64"
PATH="$NDK_TOOLCHAIN_ROOT/bin/:$PATH"

You must also create a hard link or a symlink for certain files(aarch64-linux-android27-clang++ and aarch64-linux-android27-clang) using the following command to avoid errors. You can see my Android API version is 27.

cd $HOME/armnn-devenv/android-ndk-r20b/toolchains/llvm/prebuilt/linux-x86_64/binln -s aarch64-linux-android27-clang++ aarch64-linux-android-clang++ln -s aarch64-linux-android27-clang aarch64-linux-android-clang

Step 2- Build Google’s Protobuf library

mkdir $HOME/armnn-devenv/googlecd $HOME/armnn-devenv/googlegit clone https://github.com/google/protobuf.gitcd protobuf./autogen.shmkdir x86_buildcd x86_build../configure --prefix=$HOME/armnn-devenv/google/x86_pb_installmake install -j16cd ..mkdir arm64_buildcd arm64_buildCC=aarch64-linux-android-clang \
CXX=aarch64-linux-android-clang++ \
CFLAGS="-fPIE -fPIC" \
LDFLAGS="-llog -lz -lc++_static" \
../configure --host=aarch64-linux-android \
--prefix=$HOME/armnn-devenv/google/arm64_pb_install \
--enable-cross-compile \
--with-protoc=$HOME/armnn-devenv/google/x86_pb_install/bin/protoc
make install -j16
cd ..

Step 3- Build ONNX

cd $HOME/armnn-devenv/export ONNX_ML=1 git clone --recursive https://github.com/onnx/onnx.gitunset ONNX_MLcd onnxgit checkout 553df22c67bee5f0fe6599cff60f1afc6748c635export LD_LIBRARY_PATH=$HOME/armnn-devenv/google/x86_pb_install/lib:$LD_LIBRARY_PATH$HOME/armnn-devenv/google/x86_pb_install/bin/protoc onnx/onnx.proto --proto_path=. --proto_path=../google/x86_pb_install/include --cpp_out $HOME/armnn-devenv/onnx

Step 4- Build Boost

Download boost_1_64_0.tar.gz from here in the armnn-devenv directory and proceed with the following commands.

cd $HOME/armnn-devenvtar -zxvf boost_1_64_0.tar.gzcd boost_1_64_0echo "using clang : arm : aarch64-linux-android27-clang++ ;" > $HOME/armnn-devenv/boost_1_64_0/user-config.jam./bootstrap.sh --prefix=$HOME/armnn-devenv/boost_1_64_0/install./b2 install --user-config=$HOME/armnn-devenv/boost_1_64_0/user-config.jam \
toolset=clang-arm link=static cxxflags=-fPIC --with-filesystem \
--with-test --with-log --with-program_options -j16

Step 5- Build Flatbuffers

cd $HOME/armnn-devenvwget -O flatbuffers-1.12.0.tar.gz https://github.com/google/flatbuffers/archive/v1.12.0.tar.gztar xf flatbuffers-1.12.0.tar.gzcd flatbuffers-1.12.0rm -f CMakeCache.txtmkdir buildcd buildcmake .. -DFLATBUFFERS_BUILD_FLATC=1 \
-DCMAKE_INSTALL_PREFIX:PATH=$HOME/armnn-devenv/flatbuffers \
-DFLATBUFFERS_BUILD_TESTS=0
make all installcd ..mkdir build-arm64cd build-arm64CC=aarch64-linux-android-clang \
CXX=aarch64-linux-android-clang++ \
CFLAGS="-fPIE -fPIC" \
cmake .. -DFLATBUFFERS_BUILD_FLATC=1 \
-DCMAKE_INSTALL_PREFIX:PATH=$HOME/armnn-devenv/flatbuffers-arm64 \
-DFLATBUFFERS_BUILD_TESTS=0
make all install

Step 6- Clone Armnn

I built the 21.05 version because 21.08 was producing errors.

cd $HOME/armnn-devenv/git clone https://github.com/ARM-software/armnn.gitcd armnngit checkout v21.05

Step 7- Build Tensorflow

cd $HOME/armnn-devenv/google/git clone https://github.com/tensorflow/tensorflow.gitcd tensorflow/git checkout 590d6eef7e91a6a7392c8ffffb7b58f2e0c8bc6b$HOME/armnn-devenv/armnn/scripts/generate_tensorflow_protobuf.sh \
$HOME/armnn-devenv/google/tf_pb $HOME/armnn-devenv/google/x86_pb_install

Step 8- Build Tflite

cd $HOME/armnn-devenvmkdir tflitecd tflitecp $HOME/armnn-devenv/google/tensorflow/tensorflow/lite/schema/schema.fbs .$HOME/armnn-devenv/flatbuffers-1.12.0/build/flatc -c --gen-object-api --reflect-types --reflect-names schema.fbs

Make sure this generates 2 files in your tflite directory- schema.fbs and schema_generated.h

Step 9- Build Compute Library

Be very careful about the version of Compute Library. It should match with the one mentioned in get_compute_library.sh file. To check the version, follow the below steps-

cd $HOME/armnn-devenv/armnn/scripts/nano get_compute_library.sh 

This file will have these lines, which will give you the version.

# For pinning to a ref use this:
DEFAULT_CLFRAMEWORKREVISION=”branches/arm_compute_21_05" # Release 21.05

As you can see here, the version is 21.05. Remember the version.

Now, building Compute Library.

cd $HOME/armnn-devenvgit clone https://github.com/ARM-software/ComputeLibrary.gitcd ComputeLibrary

Now, you need to switch to that version(21.05). Use the following command to see the history of this repository and the sha value for that version.

git log .

Copy the sha. For me, it’s c66f0e08bacd1041a4e5a7fda0eadbd868521a18. Follow the commands below to build it-

git checkout c66f0e08bacd1041a4e5a7fda0eadbd868521a18scons arch=arm64-v8a neon=1 opencl=1 embed_kernels=1 extra_cxx_flags="-fPIC" \
benchmark_tests=0 validation_tests=0 os=android -j16

Step 10- Build Arm NN

Now that you have everything set, check if FileSystem.hpp and Threads.hpp are present in $HOME/armnn-devenv/armnn/src/armnnUtils/. If these are not present, move them from $HOME/armnn-devenv/armnn/include/armnnUtils/ to $HOME/armnn-devenv/armnn/src/armnnUtils/.

Also, if you want to build UnitTests, Onnx parser, Tflite parser etc., you need to ON these build options in your $HOME/armnn-devenv/armnn/cmake/GlobalConfig.cmake file which are OFF by default.

Now, building, the final step-

NOTE: If you want to include standalone sample dynamic backend tests, only then include these(-DSAMPLE_DYNAMIC_BACKEND=1 \
-DDYNAMIC_BACKEND_PATHS=/data/local/tmp/dynamic/sample/) in the following command, otherwise these are not required.

mkdir $HOME/armnn-devenv/armnn/buildcd $HOME/armnn-devenv/armnn/buildCXX=aarch64-linux-android-clang++ \
CC=aarch64-linux-android-clang \
CXX_FLAGS="-fPIE -fPIC" \
cmake .. \
-DCMAKE_ANDROID_NDK=$NDK \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_SYSTEM_VERSION=27 \
-DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \
-DCMAKE_EXE_LINKER_FLAGS="-pie -llog -lz" \
-DARMCOMPUTE_ROOT=$HOME/armnn-devenv/ComputeLibrary/ \
-DARMCOMPUTE_BUILD_DIR=$HOME/armnn-devenv/ComputeLibrary/build \
-DBOOST_ROOT=$HOME/armnn-devenv/boost_1_64_0/install \
-DBoost_INCLUDE_DIR=$HOME/armnn-devenv/boost_1_64_0/install/include \
-DBoost_LIBRARY_DIR=$HOME/armnn-devenv/boost_1_64_0/install/lib \
-DFLATBUFFERS_ROOT=$HOME/armnn-devenv/flatbuffers-arm64 \
-DFLATBUFFERS_INCLUDE_PATH=$HOME/armnn-devenv/flatbuffers-arm64/include \
-DFLATC_DIR=$HOME/armnn-devenv/flatbuffers-1.12.0/build/ \
-DTF_GENERATED_SOURCES=$HOME/armnn-devenv/google/tf_pb/ \
-DBUILD_TF_PARSER=1 \
-DTF_LITE_GENERATED_PATH=$HOME/armnn-devenv/tflite \
-DARMCOMPUTENEON=1 -DARMCOMPUTECL=1 -DARMNNREF=1 \
-DTF_LITE_SCHEMA_INCLUDE_PATH=$HOME/armnn-devenv/tflite \
-DBUILD_TF_LITE_PARSER=1 \
-DPROTOBUF_ROOT=$HOME/armnn-devenv/google/arm64_pb_install/ \
-DPROTOBUF_LIBRARY_DEBUG=$HOME/armnn-devenv/google/arm64_pb_install/lib/libprotobuf.so \
-DPROTOBUF_LIBRARY_RELEASE=$HOME/armnn-devenv/google/arm64_pb_install/lib/libprotobuf.so \
-DFLATBUFFERS_LIBRARY_RELEASE=$HOME/armnn-devenv/flatbuffers-arm64/lib/libflatbuffers.a \
-DFLATBUFFERS_LIBRARY_DEBUG=$HOME/armnn-devenv/flatbuffers-arm64/lib/libflatbuffers.a \
-DONNX_GENERATED_SOURCES=$HOME/armnn-devenv/onnx \
-DBUILD_ONNX_PARSER=1 \
-DSAMPLE_DYNAMIC_BACKEND=1 \
-DDYNAMIC_BACKEND_PATHS=/data/local/tmp/dynamic/sample/
make -j16

Step 11- Build Standalone Sample Dynamic Backend

cd $HOME/armnn-devenv/armnn/src/dynamic/samplemkdir buildcd buildCXX=aarch64-linux-android-clang++ CC=aarch64-linux-android-clang CXX_FLAGS="-fPIE -fPIC" cmake -DCMAKE_CXX_FLAGS=--std=c++14 -DCMAKE_EXE_LINKER_FLAGS="-pie -llog -lz -lc++_shared"-DCMAKE_MODULE_LINKER_FLAGS="-llog" -DBOOST_ROOT=$HOME/armnn-devenv/boost_arm64_install -DBoost_SYSTEM_LIBRARY=$HOME/armnn-devenv/boost_arm64_install/lib/libboost_system.a -DBoost_FILESYSTEM_LIBRARY=$HOME/armnn-devenv/boost_arm64_install/lib/libboost_filesystem.a -DARMNN_PATH=$HOME/armnn-devenv/armnn/build/libarmnn.so ..make

And, you’re done. I hope this helped you build your successful Arm NN environment.

Now, if you want to run UnitTests and any ONNX model. I have written the steps which are needed to be followed in this article. You can refer to that if you want.

Happy Learning.

--

--