| 
 | 1 | +#!/bin/bash  | 
 | 2 | + | 
 | 3 | +set -e  | 
 | 4 | + | 
 | 5 | +PWD=`pwd`  | 
 | 6 | +ANDROID_PLATFORM=android-34  | 
 | 7 | +ANDROID_NDK=${PWD}/android-ndk-r26c  | 
 | 8 | +REMOTE_PATH=/data/local/tmp/  | 
 | 9 | +GGUF_MODEL_NAME=/sdcard/deepseek-r1-distill-qwen-1.5b-q4_0.gguf  | 
 | 10 | + | 
 | 11 | +#QNN SDK could be found at:  | 
 | 12 | +#https://www.qualcomm.com/developer/software/qualcomm-ai-engine-direct-sdk  | 
 | 13 | +#https://developer.qualcomm.com/software/hexagon-dsp-sdk/tools  | 
 | 14 | +QNN_SDK_URL=https://www.qualcomm.com/developer/software/qualcomm-ai-engine-direct-sdk  | 
 | 15 | +QNN_SDK_PATH=/opt/qcom/aistack/qairt/2.31.0.250130/  | 
 | 16 | + | 
 | 17 | +function dump_vars()  | 
 | 18 | +{  | 
 | 19 | +    echo -e "ANDROID_NDK:          ${ANDROID_NDK}"  | 
 | 20 | +    echo -e "QNN_SDK_PATH:         ${QNN_SDK_PATH}"  | 
 | 21 | +}  | 
 | 22 | + | 
 | 23 | + | 
 | 24 | +function show_pwd()  | 
 | 25 | +{  | 
 | 26 | +    echo -e "current working path:$(pwd)\n"  | 
 | 27 | +}  | 
 | 28 | + | 
 | 29 | + | 
 | 30 | +function check_qnn_sdk()  | 
 | 31 | +{  | 
 | 32 | +    if [ ! -d ${QNN_SDK_PATH} ]; then  | 
 | 33 | +        echo -e "QNN_SDK_PATH ${QNN_SDK_PATH} not exist, pls check or download it from ${QNN_SDK_URL}...\n"  | 
 | 34 | +        exit 1  | 
 | 35 | +    fi  | 
 | 36 | +}  | 
 | 37 | + | 
 | 38 | + | 
 | 39 | +function check_and_download_ndk()  | 
 | 40 | +{  | 
 | 41 | +    is_android_ndk_exist=1  | 
 | 42 | + | 
 | 43 | +    if [ ! -d ${ANDROID_NDK} ]; then  | 
 | 44 | +        is_android_ndk_exist=0  | 
 | 45 | +    fi  | 
 | 46 | + | 
 | 47 | +    if [ ! -f ${ANDROID_NDK}/build/cmake/android.toolchain.cmake ]; then  | 
 | 48 | +        is_android_ndk_exist=0  | 
 | 49 | +    fi  | 
 | 50 | + | 
 | 51 | +    if [ ${is_android_ndk_exist} -eq 0 ]; then  | 
 | 52 | + | 
 | 53 | +        if [ ! -f android-ndk-r26c-linux.zip ]; then  | 
 | 54 | +            wget --no-config --quiet --show-progress -O android-ndk-r26c-linux.zip  https://dl.google.com/android/repository/android-ndk-r26c-linux.zip  | 
 | 55 | +        fi  | 
 | 56 | + | 
 | 57 | +        unzip android-ndk-r26c-linux.zip  | 
 | 58 | + | 
 | 59 | +        if [ $? -ne 0 ]; then  | 
 | 60 | +            printf "failed to download android ndk to %s \n" "${ANDROID_NDK}"  | 
 | 61 | +            exit 1  | 
 | 62 | +        fi  | 
 | 63 | + | 
 | 64 | +        printf "android ndk saved to ${ANDROID_NDK} \n\n"  | 
 | 65 | +    else  | 
 | 66 | +        printf "android ndk already exist:${ANDROID_NDK} \n\n"  | 
 | 67 | +    fi  | 
 | 68 | +}  | 
 | 69 | + | 
 | 70 | + | 
 | 71 | +function build_arm64  | 
 | 72 | +{  | 
 | 73 | +    cmake -H. -B./out/android -DGGML_USE_QNN=ON -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=latest -DCMAKE_C_FLAGS=-march=armv8.7-a -DGGML_QNN=ON -DGGML_QNN_SDK_PATH=${QNN_SDK_PATH}  | 
 | 74 | +    cd out/android  | 
 | 75 | +    make -j16  | 
 | 76 | +    show_pwd  | 
 | 77 | + | 
 | 78 | +    cd -  | 
 | 79 | +}  | 
 | 80 | + | 
 | 81 | + | 
 | 82 | +function remove_temp_dir()  | 
 | 83 | +{  | 
 | 84 | +    if [ -d out ]; then  | 
 | 85 | +        echo "remove out directory in `pwd`"  | 
 | 86 | +        rm -rf out  | 
 | 87 | +    fi  | 
 | 88 | +}  | 
 | 89 | + | 
 | 90 | + | 
 | 91 | +function check_qnn_libs()  | 
 | 92 | +{  | 
 | 93 | +    #reuse the cached qnn libs on Android phone  | 
 | 94 | +    adb shell ls ${REMOTE_PATH}/libQnnCpu.so  | 
 | 95 | +    if [ $? -eq 0 ]; then  | 
 | 96 | +        printf "QNN libs already exist on Android phone\n"  | 
 | 97 | +    else  | 
 | 98 | +        update_qnn_libs  | 
 | 99 | +    fi  | 
 | 100 | +}  | 
 | 101 | + | 
 | 102 | + | 
 | 103 | +function update_qnn_libs()  | 
 | 104 | +{  | 
 | 105 | +        adb push ${QNN_SDK_PATH}/lib/aarch64-android/libQnnSystem.so              ${REMOTE_PATH}/  | 
 | 106 | +        adb push ${QNN_SDK_PATH}/lib/aarch64-android/libQnnCpu.so                 ${REMOTE_PATH}/  | 
 | 107 | +        adb push ${QNN_SDK_PATH}/lib/aarch64-android/libQnnGpu.so                 ${REMOTE_PATH}/  | 
 | 108 | + | 
 | 109 | +        adb push ${QNN_SDK_PATH}/lib/aarch64-android/libQnnHtp.so                 ${REMOTE_PATH}/  | 
 | 110 | +        adb push ${QNN_SDK_PATH}/lib/aarch64-android/libQnnHtpNetRunExtensions.so ${REMOTE_PATH}/  | 
 | 111 | +        adb push ${QNN_SDK_PATH}/lib/aarch64-android/libQnnHtpPrepare.so          ${REMOTE_PATH}/  | 
 | 112 | +        adb push ${QNN_SDK_PATH}/lib/aarch64-android/libQnnHtpV75Stub.so          ${REMOTE_PATH}/  | 
 | 113 | +        adb push ${QNN_SDK_PATH}/lib/hexagon-v75/unsigned/libQnnHtpV75Skel.so     ${REMOTE_PATH}/  | 
 | 114 | +}  | 
 | 115 | + | 
 | 116 | + | 
 | 117 | +function build_ggml_qnn()  | 
 | 118 | +{  | 
 | 119 | +    show_pwd  | 
 | 120 | +    check_and_download_ndk  | 
 | 121 | +    check_qnn_sdk  | 
 | 122 | +    dump_vars  | 
 | 123 | +    remove_temp_dir  | 
 | 124 | +    build_arm64  | 
 | 125 | +}  | 
 | 126 | + | 
 | 127 | + | 
 | 128 | +function run_llamacli()  | 
 | 129 | +{  | 
 | 130 | +    check_qnn_libs  | 
 | 131 | + | 
 | 132 | +    if [ -f ./out/android/bin/libggml-qnn.so ]; then  | 
 | 133 | +        adb push ./out/android/bin/*.so ${REMOTE_PATH}/  | 
 | 134 | +    fi  | 
 | 135 | +    adb push ./out/android/bin/llama-cli ${REMOTE_PATH}/  | 
 | 136 | +    adb shell chmod +x ${REMOTE_PATH}/llama-cli  | 
 | 137 | + | 
 | 138 | +    adb shell "cd ${REMOTE_PATH} \  | 
 | 139 | +               && export LD_LIBRARY_PATH=${REMOTE_PATH} \  | 
 | 140 | +               && ${REMOTE_PATH}/llama-cli -mg 2 -m ${GGUF_MODEL_NAME} -p \"introduce the movie Once Upon a Time in America briefly.\n\""  | 
 | 141 | + | 
 | 142 | +}  | 
 | 143 | + | 
 | 144 | +function run_test-backend-ops()  | 
 | 145 | +{  | 
 | 146 | +    check_qnn_libs  | 
 | 147 | + | 
 | 148 | +    if [ -f ./out/android/bin/libggml-qnn.so ]; then  | 
 | 149 | +        adb push ./out/android/bin/*.so ${REMOTE_PATH}/  | 
 | 150 | +    fi  | 
 | 151 | +    adb push ./out/android/bin/test-backend-ops ${REMOTE_PATH}/  | 
 | 152 | +    adb shell chmod +x ${REMOTE_PATH}/test-backend-ops  | 
 | 153 | + | 
 | 154 | +    adb shell "cd ${REMOTE_PATH} \  | 
 | 155 | +               && export LD_LIBRARY_PATH=${REMOTE_PATH} \  | 
 | 156 | +               && ${REMOTE_PATH}/test-backend-ops test"  | 
 | 157 | + | 
 | 158 | +}  | 
 | 159 | + | 
 | 160 | + | 
 | 161 | +function show_usage()  | 
 | 162 | +{  | 
 | 163 | +    echo "Usage:"  | 
 | 164 | +    echo "  $0 build"  | 
 | 165 | +    echo "  $0 updateqnnlib"  | 
 | 166 | +    echo "  $0 run_llamacli"  | 
 | 167 | +    echo "  $0 run_testop"  | 
 | 168 | +    echo -e "\n\n\n"  | 
 | 169 | +}  | 
 | 170 | + | 
 | 171 | + | 
 | 172 | +show_pwd  | 
 | 173 | + | 
 | 174 | +check_qnn_sdk  | 
 | 175 | + | 
 | 176 | +if [ $# == 0 ]; then  | 
 | 177 | +    show_usage  | 
 | 178 | +    exit 1  | 
 | 179 | +elif [ $# == 1 ]; then  | 
 | 180 | +    if [ "$1" == "-h" ]; then  | 
 | 181 | +        show_usage  | 
 | 182 | +        exit 1  | 
 | 183 | +    elif [ "$1" == "help" ]; then  | 
 | 184 | +        show_usage  | 
 | 185 | +        exit 1  | 
 | 186 | +    elif [ "$1" == "build" ]; then  | 
 | 187 | +        build_ggml_qnn  | 
 | 188 | +        exit 0  | 
 | 189 | +    elif [ "$1" == "run_llamacli" ]; then  | 
 | 190 | +        run_llamacli  | 
 | 191 | +        exit 0  | 
 | 192 | +    elif [ "$1" == "run_testop" ]; then  | 
 | 193 | +        run_test-backend-ops  | 
 | 194 | +        exit 0  | 
 | 195 | +    elif [ "$1" == "updateqnnlib" ]; then  | 
 | 196 | +        update_qnn_libs  | 
 | 197 | +        exit 0  | 
 | 198 | +    fi  | 
 | 199 | +else  | 
 | 200 | +    show_usage  | 
 | 201 | +    exit 1  | 
 | 202 | +fi  | 
0 commit comments