1#!/bin/bash 2# 3# Copyright © 2023 Arm Ltd and Contributors. All rights reserved. 4# 5# SPDX-License-Identifier: MIT 6# 7 8function Usage() { 9 echo "This script builds Arm NN for Android using the Android NDK. The script builds" 10 echo "the Arm NN core library and its dependencies." 11 echo "" 12 echo "Usage: $CMD [options]" 13 echo "Options:" 14 echo " -l Use this copy of Arm NN and ComputeLibrary instead of cloning new copies" 15 echo " <1 or 0> defaults to 1" 16 echo " -a Override Arm NN branch (defaults to latest release branches/armnn_23_02)" 17 echo " -b Override ACL branch (defaults to latest release v23.02)" 18 echo " -A Android API level defaults to 30" 19 echo " -n Neon (CpuAcc backend) enabled <1 or 0> defaults to 1" 20 echo " -g CL (GpuAcc backend) enabled <1 or 0> defaults to 1" 21 echo " -r Reference (CpuRef backend) enabled <1 or 0> defaults to 1" 22 echo " -u Build tests and test applications <1 or 0> defaults to 1" 23 echo " -d TfLite Delegate enabled <1 or 0> defaults to 1" 24 echo " -p TfLite Parser enabled <1 or 0> defaults to 1" 25 echo " -s Dynamic Sample enabled <1 or 0> defaults to 0" 26 echo " -i Installation directory defaults to ~/armnn-devenv" 27 echo " -t Push to board and run tests <1 or 0> defaults to 0" 28 29 exit 1 30} 31 32function AssertZeroExitCode { 33 EXITCODE=$? 34 if [[ $EXITCODE -ne 0 ]]; then 35 echo -e "Previous command exited with code $EXITCODE" 36 exit 1 37 fi 38} 39 40THIS_FILE=$(readlink -f "$0") 41BASE_DIR=$(dirname "$THIS_FILE") 42 43# Set variables and working directory 44CREATE_LINKS=1 45ARMNN_BRANCH=branches/armnn_23_02 46ACL_BRANCH=v23.02 47ACL_NEON=1 48ACL_CL=1 49REFERENCE=1 50BUILD_TESTS=1 51DELEGATE=1 52TFLITE_PARSER=1 53DYNAMIC_SAMPLE=0 54CMAKE=$(which cmake) 55WORKING_DIR=$HOME/armnn-devenv 56 57ANDROID_API=30 58PUSH_TO_BOARD=0 59 60# Parse the command line arguments to get build type 61while getopts "hl:a:c:A:n:g:r:u:d:p:s:i:t:" opt; do 62 ((OPTION_COUNTER+=1)) 63 case "$opt" in 64 h|\?) Usage;; 65 l) CREATE_LINKS=$OPTARG;; 66 a) ARMNN_BRANCH=$OPTARG;; 67 c) ACL_BRANCH=$OPTARG;; 68 A) ANDROID_API=$OPTARG;; 69 n) ACL_NEON=$OPTARG;; 70 g) ACL_CL=$OPTARG;; 71 r) REFERENCE=$OPTARG;; 72 u) BUILD_TESTS=$OPTARG;; 73 d) DELEGATE=$OPTARG;; 74 p) TFLITE_PARSER=$OPTARG;; 75 s) DYNAMIC_SAMPLE=$OPTARG;; 76 i) WORKING_DIR=$OPTARG;; 77 t) PUSH_TO_BOARD=$OPTARG;; 78 esac 79done 80shift $((OPTIND - 1)) 81 82export NDK_DIR=$WORKING_DIR/android-ndk-r25 83export NDK_TOOLCHAIN_ROOT=$NDK_DIR/toolchains/llvm/prebuilt/linux-x86_64 84export PATH=$NDK_TOOLCHAIN_ROOT/bin/:$PATH 85 86pushd $WORKING_DIR 87 88function GetAndroidNDK { 89 cd $WORKING_DIR 90 if [[ ! -d android-ndk-r25 ]]; then 91 echo "+++ Getting Android NDK" 92 wget https://dl.google.com/android/repository/android-ndk-r25-linux.zip 93 unzip android-ndk-r25-linux.zip 94 fi 95} 96 97function GetAndBuildCmake319 { 98 echo "+++ Building Cmake 3.19rc3" 99 cd $WORKING_DIR 100 sudo apt-get install libssl-dev 101 wget https://github.com/Kitware/CMake/releases/download/v3.19.0-rc3/cmake-3.19.0-rc3.tar.gz 102 tar -zxf cmake-3.19.0-rc3.tar.gz 103 pushd cmake-3.19.0-rc3 104 ./bootstrap --prefix=$WORKING_DIR/cmake/install 105 make all install 106 popd 107} 108 109function GetAndBuildFlatbuffers { 110 cd $WORKING_DIR 111 112 if [[ ! -d flatbuffers-2.0.6 ]]; then 113 echo "+++ Getting Flatbuffers" 114 wget https://github.com/google/flatbuffers/archive/v2.0.6.tar.gz 115 tar xf v2.0.6.tar.gz 116 fi 117 #Build FlatBuffers 118 echo "+++ Building x86 Flatbuffers library" 119 cd $WORKING_DIR/flatbuffers-2.0.6 120 121 rm -f CMakeCache.txt 122 123 rm -rf build-x86 124 mkdir build-x86 125 cd build-x86 126 127 rm -rf $WORKING_DIR/flatbuffers-x86 128 mkdir $WORKING_DIR/flatbuffers-x86 129 130 CXXFLAGS="-fPIC" $CMAKE .. \ 131 -DFLATBUFFERS_BUILD_FLATC=1 \ 132 -DCMAKE_INSTALL_PREFIX:PATH=$WORKING_DIR/flatbuffers-x86 133 134 make all install -j16 135 136 echo "+++ Building Android Flatbuffers library" 137 cd $WORKING_DIR/flatbuffers-2.0.6 138 139 rm -f CMakeCache.txt 140 141 rm -rf build-android 142 mkdir build-android 143 cd build-android 144 145 rm -rf $WORKING_DIR/flatbuffers-android 146 mkdir $WORKING_DIR/flatbuffers-android 147 148 CC=/usr/bin/aarch64-linux-gnu-gcc CXX=/usr/bin/aarch64-linux-gnu-g++ \ 149 CXXFLAGS="-fPIC" $CMAKE .. \ 150 -DCMAKE_ANDROID_NDK=$NDK_DIR \ 151 -DCMAKE_SYSTEM_NAME=Android \ 152 -DCMAKE_SYSTEM_VERSION=$ANDROID_API \ 153 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \ 154 -DCMAKE_CXX_FLAGS=--std=c++14 \ 155 -DFLATBUFFERS_BUILD_FLATC=OFF \ 156 -DCMAKE_BUILD_TYPE=Release \ 157 -DFLATBUFFERS_BUILD_TESTS=OFF \ 158 -DCMAKE_INSTALL_PREFIX=$WORKING_DIR/flatbuffers-android 159 160 make all install -j16 161} 162 163function GetArmNN { 164 cd $WORKING_DIR 165 166 if [[ ! -d armnn ]]; then 167 if [[ $CREATE_LINKS = 1 && -d $BASE_DIR/../../armnn ]]; then 168 echo "+++ Linking Arm NN" 169 ln -s $BASE_DIR/../../armnn $WORKING_DIR/armnn 170 else 171 echo "+++ Cloning Arm NN" 172 git clone https://review.mlplatform.org/ml/armnn.git armnn 173 cd armnn 174 175 git checkout $ARMNN_BRANCH 176 git log -1 177 fi 178 fi 179} 180 181function GetAndBuildComputeLibrary { 182 cd $WORKING_DIR 183 184 if [[ ! -d ComputeLibrary ]]; then 185 if [[ $CREATE_LINKS = 1 ]]; then 186 if [[ -d $BASE_DIR/../../ComputeLibrary ]]; then 187 echo "+++ Linking ComputeLibrary" 188 ln -s $BASE_DIR/../../ComputeLibrary $WORKING_DIR/ComputeLibrary 189 else 190 echo "+++ Cloning ComputeLibrary" 191 git clone https://review.mlplatform.org/ml/ComputeLibrary.git ComputeLibrary 192 cd ComputeLibrary 193 git checkout $($BASE_DIR/../../armnn/scripts/get_compute_library.sh -p) 194 git log -1 195 fi 196 else 197 echo "+++ Cloning ComputeLibrary" 198 199 git clone https://review.mlplatform.org/ml/ComputeLibrary.git ComputeLibrary 200 cd ComputeLibrary 201 git checkout $ACL_BRANCH 202 git log -1 203 fi 204 fi 205 cd $WORKING_DIR/ComputeLibrary 206 207 echo "+++ Building Compute Library" 208 scons toolchain_prefix=llvm- compiler_prefix=aarch64-linux-android$ANDROID_API- arch=arm64-v8a neon=$ACL_NEON opencl=$ACL_CL embed_kernels=$ACL_CL extra_cxx_flags="-fPIC" \ 209 benchmark_tests=0 validation_tests=0 os=android -j16 210} 211 212function GetAndBuildTFLite { 213 TENSORFLOW_REVISION="tags/v2.10.0" # Release 2.10.0 tag 214 TFLITE_ROOT_DIR=${WORKING_DIR}/tensorflow/tensorflow/lite 215 216 cd $WORKING_DIR 217 218 if [[ ! -d tensorflow ]]; then 219 if [[ -d $BASE_DIR/../../armnn ]]; then 220 TENSORFLOW_REVISION=$($BASE_DIR/../../armnn/scripts/get_tensorflow.sh -p) 221 fi 222 echo "+++ Cloning TensorFlow" 223 git clone https://github.com/tensorflow/tensorflow.git 224 AssertZeroExitCode "Cloning TensorFlow failed" 225 226 cd tensorflow 227 228 echo "Checking out ${TENSORFLOW_REVISION}" 229 git fetch && git checkout $TENSORFLOW_REVISION 230 231 cd $WORKING_DIR 232 fi 233 234 CMARGS="-DTFLITE_ENABLE_XNNPACK=OFF" 235 236 # Two different naming conventions; one for build and the other for CC_OPT_FLAGS 237 ANDROID_ARM_ARCH="arm64-v8a" 238 239 mkdir -p tflite-out/android 240 cd tflite-out/android 241 242 echo "*** Configure and Cross-Compile TfLite for ${TARGET_MACHINE} with architecture ${ANDROID_ARM_ARCH}" 243 echo "*** Outputting files to ${TFLITE_OUTPUT_DIR}/${TARGET_MACHINE}" 244 245 CMARGS="$CMARGS -DCMAKE_TOOLCHAIN_FILE=$NDK_DIR/build/cmake/android.toolchain.cmake \ 246 -DANDROID_ABI=$ANDROID_ARM_ARCH \ 247 -DANDROID_PLATFORM=$ANDROID_API" \ 248 249 $CMAKE $CMARGS $TFLITE_ROOT_DIR 250 AssertZeroExitCode "Failed to configure Tensorflow Lite from source" 251 252 cd $WORKING_DIR 253 254 $CMAKE --build tflite-out/android -j 16 255 AssertZeroExitCode "Failed to build Tensorflow Lite from source" 256 257 mkdir -p $WORKING_DIR/tflite-out/tensorflow/tensorflow/lite/schema 258 259 SCHEMA_LOCATION=$WORKING_DIR/tensorflow/tensorflow/lite/schema/schema.fbs 260 261 cp $SCHEMA_LOCATION $WORKING_DIR/tflite-out/tensorflow/tensorflow/lite/schema 262 263 cd $WORKING_DIR/tflite-out/tensorflow/tensorflow/lite/schema 264 $WORKING_DIR/flatbuffers-x86/bin/flatc -c --gen-object-api --reflect-types --reflect-names schema.fbs 265 AssertZeroExitCode "Failed to generate C++ schema from $SCHEMA_LOCATION" 266} 267 268function BuildArmNN { 269 echo "+++ Building Arm NN" 270 271 rm -rf $WORKING_DIR/armnn/build 272 273 mkdir $WORKING_DIR/armnn/build 274 cd $WORKING_DIR/armnn/build 275 276 CMARGS="-DCMAKE_BUILD_TYPE=Release \ 277 -DCMAKE_ANDROID_NDK=$NDK_DIR \ 278 -DNDK_VERSION=r25 \ 279 -DCMAKE_SYSTEM_NAME=Android \ 280 -DCMAKE_SYSTEM_VERSION=$ANDROID_API \ 281 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \ 282 -DCMAKE_SYSROOT=$WORKING_DIR/android-ndk-r25/toolchains/llvm/prebuilt/linux-x86_64/sysroot \ 283 -DARMCOMPUTE_ROOT=$WORKING_DIR/ComputeLibrary \ 284 -DARMCOMPUTE_BUILD_DIR=$WORKING_DIR/ComputeLibrary/build \ 285 -DARMCOMPUTENEON=$ACL_NEON -DARMCOMPUTECL=$ACL_CL -DARMNNREF=$REFERENCE \ 286 -DFLATBUFFERS_INCLUDE_PATH=$WORKING_DIR/flatbuffers-x86/include \ 287 -DFLATBUFFERS_ROOT=$WORKING_DIR/flatbuffers-android \ 288 -DFLATC_DIR=$WORKING_DIR/flatbuffers-x86 \ 289 -DBUILD_UNIT_TESTS=$BUILD_TESTS \ 290 -DBUILD_TESTS=$BUILD_TESTS \ 291 -fexceptions" 292 293 if [[ $TFLITE_PARSER == 1 ]]; then 294 CMARGS="$CMARGS \ 295 -DBUILD_TF_LITE_PARSER=1 \ 296 -DTF_LITE_GENERATED_PATH=$WORKING_DIR/tflite-out/tensorflow/tensorflow/lite/schema \ 297 -DTENSORFLOW_ROOT=$WORKING_DIR/tensorflow \ 298 -DTFLITE_LIB_ROOT=$WORKING_DIR/tflite-out/android" 299 fi 300 301 if [[ $DELEGATE == 1 ]]; then 302 CMARGS="$CMARGS \ 303 -DBUILD_ARMNN_TFLITE_DELEGATE=1 \ 304 -DTENSORFLOW_ROOT=$WORKING_DIR/tensorflow \ 305 -DTFLITE_LIB_ROOT=$WORKING_DIR/tflite-out/android \ 306 -DTFLITE_ROOT_DIR=$WORKING_DIR/tensorflow/tensorflow/lite" 307 fi 308 309 if [[ $DYNAMIC_SAMPLE == 1 ]]; then 310 DYNAMIC_SAMPLE_PATH="/data/local/tmp/dynamic/sample" 311 CMARGS="$CMARGS \ 312 -DDYNAMIC_BACKEND_PATHS=$DYNAMIC_SAMPLE_PATH \ 313 -DSAMPLE_DYNAMIC_BACKEND=1" 314 fi 315 echo "args" 316 echo $CMARGS 317 CXX=aarch64-linux-android$ANDROID_API-clang++ \ 318 CC=aarch64-linux-android$ANDROID_API-clang \ 319 CXX_FLAGS="-fPIE -fPIC" \ 320 $CMAKE $CMARGS .. 321 make -j16 322} 323 324function BuildStandaloneDynamicBackend { 325 echo "+++ Building Standalone Dynamic Sample Backend" 326 cd $WORKING_DIR/armnn/src/dynamic/sample 327 BUILD_DIR=build 328 rm -rf $BUILD_DIR 329 mkdir -p $BUILD_DIR 330 cd $BUILD_DIR 331 CXX=aarch64-linux-android$ANDROID_API-clang++ \ 332 CC=aarch64-linux-android$ANDROID_API-clang \ 333 CXX_FLAGS="-fPIE -fPIC" \ 334 $CMAKE \ 335 -DCMAKE_C_COMPILER_WORKS=TRUE \ 336 -DCMAKE_CXX_COMPILER_WORKS=TRUE \ 337 -DCMAKE_ANDROID_NDK=$NDK_DIR \ 338 -DCMAKE_SYSTEM_NAME=Android \ 339 -DCMAKE_SYSTEM_VERSION=$ANDROID_API \ 340 -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a \ 341 -DCMAKE_SYSROOT=$WORKING_DIR/android-ndk-r25/toolchains/llvm/prebuilt/linux-x86_64/sysroot \ 342 -DCMAKE_CXX_FLAGS=--std=c++14 \ 343 -DCMAKE_EXE_LINKER_FLAGS="-pie -llog" \ 344 -DCMAKE_MODULE_LINKER_FLAGS="-llog" \ 345 -DARMNN_PATH=$WORKING_DIR/armnn/build/libarmnn.so .. 346 make 347} 348 349# push sources to board 350function PushBuildSourcesToBoard { 351 echo "+++ Removing files and symbolic links from previous runs" 352 adb start-server 353 adb shell rm -rf /data/local/tmp/* 354 echo "+++ Pushing sources to board" 355 adb root 356 adb remount 357 sleep 10s 358 adb version 359 adb push libarmnn.so /data/local/tmp/ 360 adb push libtimelineDecoder.so /data/local/tmp/ 361 adb push libtimelineDecoderJson.so /data/local/tmp/ 362 adb push GatordMock /data/local/tmp/ 363 adb push libarmnnBasePipeServer.so /data/local/tmp/ 364 adb push libarmnnTestUtils.so /data/local/tmp/ 365 adb push UnitTests /data/local/tmp/ 366 if [[ $DELEGATE == 1 ]]; then 367 adb push ${WORKING_DIR}/armnn/build/delegate/DelegateUnitTests /data/local/tmp/ 368 adb push ${WORKING_DIR}/armnn/build/delegate/libarmnnDelegate.so /data/local/tmp/ 369 fi 370 adb push $NDK_DIR/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so /data/local/tmp/ 371 echo "+++ Pushing test files to board" 372 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/testSharedObject 373 adb push -p ${WORKING_DIR}/armnn/build/src/backends/backendsCommon/test/testSharedObject/* /data/local/tmp/src/backends/backendsCommon/test/testSharedObject/ 374 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/testDynamicBackend 375 adb push -p ${WORKING_DIR}/armnn/build/src/backends/backendsCommon/test/testDynamicBackend/* /data/local/tmp/src/backends/backendsCommon/test/testDynamicBackend/ 376 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath1 377 adb push -p ${WORKING_DIR}/armnn/build/src/backends/backendsCommon/test/backendsTestPath1/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath1/ 378 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2 379 adb push -p ${WORKING_DIR}/armnn/build/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/ 380 adb shell 'ln -s Arm_CpuAcc_backend.so /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so.1' 381 adb shell 'ln -s Arm_CpuAcc_backend.so.1 /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_CpuAcc_backend.so.1.2' 382 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' 383 adb push -p ${WORKING_DIR}/armnn/build/src/backends/backendsCommon/test/backendsTestPath2/Arm_GpuAcc_backend.so /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/ 384 adb shell 'ln -s nothing /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath2/Arm_no_backend.so' 385 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath3 386 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath5 387 adb push -p ${WORKING_DIR}/armnn/build/src/backends/backendsCommon/test/backendsTestPath5/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath5/ 388 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath6 389 adb push -p ${WORKING_DIR}/armnn/build/src/backends/backendsCommon/test/backendsTestPath6/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath6/ 390 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath7 391 adb shell mkdir -p /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath9 392 adb push -p ${WORKING_DIR}/armnn/build/src/backends/backendsCommon/test/backendsTestPath9/* /data/local/tmp/src/backends/backendsCommon/test/backendsTestPath9/ 393 adb shell mkdir -p /data/local/tmp/src/backends/dynamic/reference 394 adb push -p ${WORKING_DIR}/armnn/build/src/backends/dynamic/reference/Arm_CpuRef_backend.so /data/local/tmp/src/backends/dynamic/reference/ 395 if [[ $DYNAMIC_SAMPLE == 1 ]]; then 396 adb shell mkdir -p /data/local/tmp/dynamic/sample/ 397 adb push -p ${WORKING_DIR}/armnn/src/dynamic/sample/build/libArm_SampleDynamic_backend.so /data/local/tmp/dynamic/sample/ 398 fi 399 echo "+++ Running UnitTests" 400 adb shell LD_LIBRARY_PATH=/data/local/tmp:/vendor/lib64:/vendor/lib64/egl /data/local/tmp/UnitTests ; printf $? 401 if [[ $DELEGATE == 1 ]]; then 402 adb shell LD_LIBRARY_PATH=/data/local/tmp:/vendor/lib64:/vendor/lib64/egl /data/local/tmp/DelegateUnitTests ; printf $? 403 fi 404} 405 406# Cleanup any previous runs, setup clean directories 407echo "+++ Creating $WORKING_DIR directory" 408mkdir -p $WORKING_DIR 409AssertZeroExitCode "Creating $WORKING_DIR directory failed" 410 411GetAndroidNDK 412if [[ $? != 0 ]] ; then 413 echo "Downloading Android NDK failed" 414 exit 1 415fi 416GetAndBuildFlatbuffers 417if [[ $? != 0 ]] ; then 418 echo "Building Flatbuffers failed" 419 exit 1 420fi 421if [[ $(lsb_release -rs) == "18.04" ]]; then 422 # We know this is necessary for 18.04 builds. 423 GetAndBuildCmake319 424 CMAKE=$WORKING_DIR/cmake/install/bin/cmake 425fi 426GetArmNN 427if [[ $? != 0 ]] ; then 428 echo "Cloning Arm NN failed" 429 exit 1 430fi 431# Build TFLite if the Delegate or Parser is required 432if [[ $DELEGATE == 1 || $TFLITE_PARSER ]]; then 433 GetAndBuildTFLite 434fi 435if [[ $? != 0 ]] ; then 436 echo "Building tflite failed" 437 exit 1 438fi 439GetAndBuildComputeLibrary 440if [[ $? != 0 ]] ; then 441 echo "Building ComputeLibrary failed" 442 exit 1 443fi 444BuildArmNN 445if [[ $? != 0 ]] ; then 446 echo "Building Arm NN failed" 447 exit 1 448fi 449if [[ $DYNAMIC_SAMPLE == 1 ]]; then 450 BuildStandaloneDynamicBackend 451fi 452if [[ $PUSH_TO_BOARD == 1 ]]; then 453 PushBuildSourcesToBoard 454fi 455if [[ "$R_new" -eq 0 ]]; then 456 echo "Success!" 457else 458 echo "Failed to run UnitTests" 459 exit 1 460fi 461