1#!/bin/bash 2# Copyright (c) Meta Platforms, Inc. and affiliates. 3# All rights reserved. 4# 5# This source code is licensed under the BSD-style license found in the 6# LICENSE file in the root directory of this source tree. 7 8set -ex 9 10build_jar() { 11 pushd extension/android 12 ./gradlew build 13 popd 14 mkdir -p "${BUILD_AAR_DIR}/libs" 15 cp extension/android/build/libs/executorch.jar "${BUILD_AAR_DIR}/libs/" 16} 17 18build_android_native_library() { 19 ANDROID_ABI="$1" 20 ANDROID_NDK="${ANDROID_NDK:-/opt/ndk}" 21 CMAKE_OUT="cmake-out-android-${ANDROID_ABI}" 22 EXECUTORCH_CMAKE_BUILD_TYPE="${EXECUTORCH_CMAKE_BUILD_TYPE:-Release}" 23 QNN_SDK_ROOT="${QNN_SDK_ROOT:-}" 24 if [ -n "$QNN_SDK_ROOT" ]; then 25 EXECUTORCH_BUILD_QNN=ON 26 else 27 EXECUTORCH_BUILD_QNN=OFF 28 fi 29 30 NEURON_BUFFER_ALLOCATOR_LIB="${NEURON_BUFFER_ALLOCATOR_LIB:-}" 31 NEURON_USDK_ADAPTER_LIB="${NEURON_USDK_ADAPTER_LIB:-}" 32 if [ -n "$NEURON_BUFFER_ALLOCATOR_LIB" ]; then 33 EXECUTORCH_BUILD_NEURON=ON 34 else 35 EXECUTORCH_BUILD_NEURON=OFF 36 fi 37 38 cmake . -DCMAKE_INSTALL_PREFIX="${CMAKE_OUT}" \ 39 -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK}/build/cmake/android.toolchain.cmake" \ 40 -DANDROID_ABI="${ANDROID_ABI}" \ 41 -DANDROID_PLATFORM=android-26 \ 42 -DEXECUTORCH_ENABLE_LOGGING=ON \ 43 -DEXECUTORCH_LOG_LEVEL=Info \ 44 -DEXECUTORCH_BUILD_XNNPACK=ON \ 45 -DEXECUTORCH_XNNPACK_SHARED_WORKSPACE=ON \ 46 -DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \ 47 -DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \ 48 -DEXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL=ON \ 49 -DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \ 50 -DEXECUTORCH_BUILD_KERNELS_OPTIMIZED=ON \ 51 -DEXECUTORCH_BUILD_KERNELS_QUANTIZED=ON \ 52 -DEXECUTORCH_BUILD_KERNELS_CUSTOM=ON \ 53 -DEXECUTORCH_BUILD_NEURON="${EXECUTORCH_BUILD_NEURON}" \ 54 -DNEURON_BUFFER_ALLOCATOR_LIB="${NEURON_BUFFER_ALLOCATOR_LIB}" \ 55 -DEXECUTORCH_BUILD_QNN="${EXECUTORCH_BUILD_QNN}" \ 56 -DQNN_SDK_ROOT="${QNN_SDK_ROOT}" \ 57 -DCMAKE_BUILD_TYPE="${EXECUTORCH_CMAKE_BUILD_TYPE}" \ 58 -B"${CMAKE_OUT}" 59 60 if [ "$(uname)" == "Darwin" ]; then 61 CMAKE_JOBS=$(( $(sysctl -n hw.ncpu) - 1 )) 62 else 63 CMAKE_JOBS=$(( $(nproc) - 1 )) 64 fi 65 cmake --build "${CMAKE_OUT}" -j "${CMAKE_JOBS}" --target install --config "${EXECUTORCH_CMAKE_BUILD_TYPE}" 66 67 cmake extension/android \ 68 -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \ 69 -DANDROID_ABI="${ANDROID_ABI}" \ 70 -DANDROID_PLATFORM=android-26 \ 71 -DCMAKE_INSTALL_PREFIX="${CMAKE_OUT}" \ 72 -DEXECUTORCH_ENABLE_LOGGING=ON \ 73 -DEXECUTORCH_LOG_LEVEL=Info \ 74 -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \ 75 -DNEURON_BUFFER_ALLOCATOR_LIB="$NEURON_BUFFER_ALLOCATOR_LIB" \ 76 -DEXECUTORCH_BUILD_KERNELS_CUSTOM=ON \ 77 -DEXECUTORCH_BUILD_LLAMA_JNI=ON \ 78 -DCMAKE_BUILD_TYPE="${EXECUTORCH_CMAKE_BUILD_TYPE}" \ 79 -B"${CMAKE_OUT}"/extension/android 80 81 cmake --build "${CMAKE_OUT}"/extension/android -j "${CMAKE_JOBS}" --config "${EXECUTORCH_CMAKE_BUILD_TYPE}" 82 83 # Copy artifacts to ABI specific directory 84 mkdir -p "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}" 85 cp "${CMAKE_OUT}"/extension/android/*.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/" 86 87 # Copy QNN related so library 88 if [ -n "$QNN_SDK_ROOT" ] && [ "$ANDROID_ABI" == "arm64-v8a" ]; then 89 cp "${CMAKE_OUT}"/lib/libqnn_executorch_backend.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/" 90 cp "${QNN_SDK_ROOT}"/lib/aarch64-android/libQnnHtp.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/" 91 cp "${QNN_SDK_ROOT}"/lib/aarch64-android/libQnnSystem.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/" 92 cp "${QNN_SDK_ROOT}"/lib/aarch64-android/libQnnHtpV69Stub.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/" 93 cp "${QNN_SDK_ROOT}"/lib/aarch64-android/libQnnHtpV73Stub.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/" 94 cp "${QNN_SDK_ROOT}"/lib/aarch64-android/libQnnHtpV75Stub.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/" 95 cp "${QNN_SDK_ROOT}"/lib/hexagon-v69/unsigned/libQnnHtpV69Skel.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/" 96 cp "${QNN_SDK_ROOT}"/lib/hexagon-v73/unsigned/libQnnHtpV73Skel.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/" 97 cp "${QNN_SDK_ROOT}"/lib/hexagon-v75/unsigned/libQnnHtpV75Skel.so "${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/" 98 fi 99 100 # Copy MTK related so library 101 if [ -n "$NEURON_BUFFER_ALLOCATOR_LIB" ] && [ -n "$NEURON_USDK_ADAPTER_LIB" ] && [ "$ANDROID_ABI" == "arm64-v8a" ]; then 102 cp "${CMAKE_OUT}"/backends/mediatek/libneuron_backend.so ${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/ 103 cp "${NEURON_BUFFER_ALLOCATOR_LIB}" ${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/ 104 cp "${NEURON_USDK_ADAPTER_LIB}" ${BUILD_AAR_DIR}/jni/${ANDROID_ABI}/ 105 fi 106} 107 108build_aar() { 109 echo \<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" \ 110 package=\"org.pytorch.executorch\"\> \ 111 \<uses-sdk android:minSdkVersion=\"19\" /\> \ 112 \</manifest\> > "${BUILD_AAR_DIR}/AndroidManifest.xml" 113 pushd "${BUILD_AAR_DIR}" 114 # Rename libexecutorch_jni.so to libexecutorch.so for soname consistency 115 # between Java and JNI 116 find jni -type f -name "libexecutorch_jni.so" -exec bash -c 'mv "$1" "${1/_jni/}"' bash {} \; 117 if [ "$EXECUTORCH_CMAKE_BUILD_TYPE" == "Release" ]; then 118 find jni -type f -name "*.so" -exec "$ANDROID_NDK"/toolchains/llvm/prebuilt/*/bin/llvm-strip {} \; 119 fi 120 # Zip all necessary files into the AAR file 121 zip -r executorch.aar libs jni/*/libexecutorch.so jni/*/libqnn*.so jni/*/libQnn*.so jni/*/libneuron_backend.so jni/*/libneuron_buffer_allocator.so jni/*/libneuronusdk_adapter.mtk.so AndroidManifest.xml 122 popd 123} 124 125build_android_demo_apps() { 126 mkdir -p examples/demo-apps/android/LlamaDemo/app/libs 127 cp ${BUILD_AAR_DIR}/executorch.aar examples/demo-apps/android/LlamaDemo/app/libs 128 pushd examples/demo-apps/android/LlamaDemo 129 ANDROID_HOME="${ANDROID_SDK:-/opt/android/sdk}" ./gradlew build assembleAndroidTest 130 popd 131 132 mkdir -p extension/benchmark/android/benchmark/app/libs 133 cp ${BUILD_AAR_DIR}/executorch.aar extension/benchmark/android/benchmark/app/libs 134 pushd extension/benchmark/android/benchmark 135 ANDROID_HOME="${ANDROID_SDK:-/opt/android/sdk}" ./gradlew build assembleAndroidTest 136 popd 137 138 pushd extension/android_test 139 ANDROID_HOME="${ANDROID_SDK:-/opt/android/sdk}" ./gradlew testDebugUnitTest 140 ANDROID_HOME="${ANDROID_SDK:-/opt/android/sdk}" ./gradlew build assembleAndroidTest 141 popd 142} 143 144collect_artifacts_to_be_uploaded() { 145 ARTIFACTS_DIR_NAME="$1" 146 DEMO_APP_DIR="${ARTIFACTS_DIR_NAME}/llm_demo" 147 # The app directory is named using its build flavor as a suffix. 148 mkdir -p "${DEMO_APP_DIR}" 149 # Collect the app and its test suite 150 cp examples/demo-apps/android/LlamaDemo/app/build/outputs/apk/debug/*.apk "${DEMO_APP_DIR}" 151 cp examples/demo-apps/android/LlamaDemo/app/build/outputs/apk/androidTest/debug/*.apk "${DEMO_APP_DIR}" 152 # Collect all ABI specific libraries 153 for ANDROID_ABI in "${ANDROID_ABIS[@]}"; do 154 mkdir -p "${DEMO_APP_DIR}/${ANDROID_ABI}" 155 cp cmake-out-android-${ANDROID_ABI}/lib/*.a "${DEMO_APP_DIR}/${ANDROID_ABI}/" 156 cp cmake-out-android-${ANDROID_ABI}/extension/android/*.so "${DEMO_APP_DIR}/${ANDROID_ABI}/" 157 done 158 # Collect JAR and AAR 159 cp extension/android/build/libs/executorch.jar "${DEMO_APP_DIR}" 160 find "${BUILD_AAR_DIR}/" -name 'executorch*.aar' -exec cp {} "${DEMO_APP_DIR}" \; 161 # Collect MiniBench APK 162 MINIBENCH_APP_DIR="${ARTIFACTS_DIR_NAME}/minibench" 163 mkdir -p "${MINIBENCH_APP_DIR}" 164 cp extension/benchmark/android/benchmark/app/build/outputs/apk/debug/*.apk "${MINIBENCH_APP_DIR}" 165 cp extension/benchmark/android/benchmark/app/build/outputs/apk/androidTest/debug/*.apk "${MINIBENCH_APP_DIR}" 166 # Collect Java library test 167 JAVA_LIBRARY_TEST_DIR="${ARTIFACTS_DIR_NAME}/library_test_dir" 168 mkdir -p "${JAVA_LIBRARY_TEST_DIR}" 169 cp extension/android_test/build/outputs/apk/debug/*.apk "${JAVA_LIBRARY_TEST_DIR}" 170 cp extension/android_test/build/outputs/apk/androidTest/debug/*.apk "${JAVA_LIBRARY_TEST_DIR}" 171} 172 173main() { 174 BUILD_AAR_DIR="$(mktemp -d)" 175 export BUILD_AAR_DIR 176 if [ -z "$ANDROID_ABIS" ]; then 177 ANDROID_ABIS=("arm64-v8a" "x86_64") 178 fi 179 export ANDROID_ABIS 180 181 ARTIFACTS_DIR_NAME="$1" 182 183 build_jar 184 for ANDROID_ABI in "${ANDROID_ABIS[@]}"; do 185 build_android_native_library ${ANDROID_ABI} 186 done 187 build_aar 188 build_android_demo_apps 189 if [ -n "$ARTIFACTS_DIR_NAME" ]; then 190 collect_artifacts_to_be_uploaded ${ARTIFACTS_DIR_NAME} 191 fi 192} 193 194if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then 195 main "$@" 196fi 197