xref: /aosp_15_r20/external/armnn/scripts/build_android_ndk_guide.sh (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
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