| #!/bin/bash | 
 | # Copyright 2020 The IREE Authors | 
 | # | 
 | # Licensed under the Apache License v2.0 with LLVM Exceptions. | 
 | # See https://llvm.org/LICENSE.txt for license information. | 
 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 |  | 
 | set -e | 
 |  | 
 | ######################### | 
 | # Script input parameters | 
 | ######################### | 
 |  | 
 | echo "=== A script for building iree-run-module apk ===" | 
 | echo "This script wraps iree-run-module together with a" | 
 | echo "specific IREE VM module and invocation information." | 
 | echo "" | 
 | echo "At a minimum, it expects the following env vars:" | 
 | echo "* ANDROID_SDK_ROOT" | 
 | echo "* ANDROID_NDK_ROOT" | 
 | echo "* ANDROID_SDK_BUILD_TOOLS_VERSION" | 
 | echo "See the script for details and more controls." | 
 | echo "===-------------------------------------------===" | 
 | echo "" | 
 |  | 
 | print_usage_and_exit() { | 
 |   echo "Usage: $0 <artifact-directory> " | 
 |   echo "       --device <device>" | 
 |   echo "       --module_file <input-module-file> " | 
 |   echo "       --entry_function <entry-function> " | 
 |   echo "       --function_inputs_file <input-buffer-file> " | 
 |   exit 1 | 
 | } | 
 |  | 
 | while (( "$#" )); do | 
 |   case "$1" in | 
 |     --device) | 
 |       if [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then | 
 |         IREE_DEVICE=$2 | 
 |         shift 2 | 
 |       else | 
 |         echo "Error: missing argument for $1" >&2 | 
 |         print_usage_and_exit | 
 |       fi | 
 |       ;; | 
 |     --module_file) | 
 |       if [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then | 
 |         IREE_INPUT_MODULE_FILE=$(readlink -f $2) | 
 |         shift 2 | 
 |       else | 
 |         echo "Error: missing argument for $1" >&2 | 
 |         print_usage_and_exit | 
 |       fi | 
 |       ;; | 
 |     --entry_function) | 
 |       if [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then | 
 |         IREE_ENTRY_FUNCTION=$2 | 
 |         shift 2 | 
 |       else | 
 |         echo "Error: missing argument for $1" >&2 | 
 |         print_usage_and_exit | 
 |       fi | 
 |       ;; | 
 |     --function_inputs_file) | 
 |       if [[ -n "$2" ]] && [[ ${2:0:1} != "-" ]]; then | 
 |         IREE_INPUT_BUFFER_FILE=$(readlink -f $2) | 
 |         shift 2 | 
 |       else | 
 |         echo "Error: missing argument for $1" >&2 | 
 |         print_usage_and_exit | 
 |       fi | 
 |       ;; | 
 |     -*|--*=) # Unsupported flags | 
 |       echo "Error: Unsupported flag $1" >&2 | 
 |       exit 1 | 
 |       ;; | 
 |     *) # Positional arguments | 
 |       if [[ -z "${IREE_ARTIFACT_ROOT+x}" ]]; then | 
 |         IREE_ARTIFACT_ROOT=$(readlink -f $1) | 
 |       else | 
 |         echo "Error: <artifact-directory> already set to ${IREE_ARTIFACT_ROOT}" >&2 | 
 |         print_usage_and_exit | 
 |       fi | 
 |       shift | 
 |       ;; | 
 |   esac | 
 | done | 
 |  | 
 | if [[ -z "${IREE_ARTIFACT_ROOT}" ]] || [[ -z "${IREE_INPUT_MODULE_FILE}" ]] || \ | 
 |    [[ -z "${IREE_ENTRY_FUNCTION}" ]] || [[ -z "${IREE_INPUT_BUFFER_FILE}" ]] || \ | 
 |    [[ -z "${IREE_DEVICE}" ]]; then | 
 |   echo "Error: missing necessary parameters" >&2 | 
 |   print_usage_and_exit | 
 | fi | 
 |  | 
 | ################################# | 
 | # IREE Android app configurations | 
 | ################################# | 
 |  | 
 | # The final Android APK name; default to "iree-run-module.apk". | 
 | IREE_APK_NAME="${IREE_APK_NAME:-iree-run-module}" | 
 | # The CMAKE build type for compiling IREE. default to Release. | 
 | IREE_BUILD_TYPE="${IREE_BUILD_TYPE:-Release}" | 
 | # The target Android API level; default to Android 10 (API level 29). | 
 | IREE_ANDROID_API_LEVEL="${IREE_ANDROID_API_LEVEL:-29}" | 
 | # The target Android platform ABI; default to arm64-v8a. | 
 | IREE_ANDROID_ABI="${IREE_ANDROID_ABI:-arm64-v8a}" | 
 |  | 
 | ################################ | 
 | # Android SDK/NDK configurations | 
 | ################################ | 
 |  | 
 | # Android SDK root; must be provided as environment variable. | 
 | # By default Android Studio uses | 
 | # * $HOME/Android/Sdk for Linux. | 
 | # * $HOME/Library/Android/sdk for macOS. | 
 | # * $%LOCALAPPDATA%\Android\sdk for Windows. | 
 | ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT:?environment variable not set}" | 
 | # Android NDK root; must be provided as environment variable. | 
 | ANDROID_NDK_ROOT="${ANDROID_NDK_ROOT:?environment variable not set}" | 
 | # Android SDK build tools version; must be provided as environment variable. | 
 | ANDROID_SDK_BUILD_TOOLS_VERSION="${ANDROID_SDK_BUILD_TOOLS_VERSION?environment variable not set}" | 
 | # Key store for signing apk files; default to Android debug keystore created | 
 | # by Android Studio. | 
 | ANDROID_KEYSTORE="${ANDROID_KEYSTORE:-${HOME}/.android/debug.keystore}" | 
 |  | 
 | ###################### | 
 | # IREE build toolchain | 
 | ###################### | 
 |  | 
 | CMAKE_BIN="${CMAKE_BIN:-$(which cmake)}" | 
 | NINJA_BIN="${NINJA_BIN:-$(which ninja)}" | 
 | CC_BIN="${CC_BIN:-$(which clang)}" | 
 | CXX_BIN="${CXX_BIN:-$(which clang++)}" | 
 | JAVAC_BIN="${JAVAC_BIN:-$(which javac)}" | 
 |  | 
 | ################################## | 
 | # IREE source/artifact directories | 
 | ################################## | 
 |  | 
 | # IREE project source root. | 
 | IREE_SOURCE_ROOT="$(git rev-parse --show-toplevel)" | 
 | # iree-run-module Android app source root. | 
 | IREE_NATIVE_APP_SOURCE_ROOT="${IREE_SOURCE_ROOT?}/tools/android/run_module_app" | 
 |  | 
 | # Directory for IREE native code intermediate intermediate artifacts. | 
 | IREE_NATIVE_LIB_BUILD_DIR="${IREE_ARTIFACT_ROOT?}/iree/${IREE_BUILD_TYPE?}" | 
 | # Directory for holding APK parts. | 
 | IREE_APK_PARTS_DIR="${IREE_ARTIFACT_ROOT?}/parts" | 
 | # Directory for IREE native libraries. | 
 | IREE_NATIVE_LIB_DIR="${IREE_APK_PARTS_DIR?}/libs/lib/${IREE_ANDROID_ABI?}" | 
 | # Directory for Android app assets. | 
 | IREE_ASSET_DIR="${IREE_APK_PARTS_DIR?}/assets" | 
 | # Directory for Android app R.class. | 
 | IREE_RESOURCE_GEN_DIR="${IREE_APK_PARTS_DIR?}/rclass" | 
 |  | 
 | ######################### | 
 | # Android build toolchain | 
 | ######################### | 
 |  | 
 | ANDROID_SDK_BUILD_TOOLS_DIR="${ANDROID_SDK_ROOT?}/build-tools/${ANDROID_SDK_BUILD_TOOLS_VERSION?}" | 
 | ANDROID_SDK_PLATFORMS_DIR="${ANDROID_SDK_ROOT?}/platforms/android-${IREE_ANDROID_API_LEVEL?}" | 
 |  | 
 | AAPT_BIN="${ANDROID_SDK_BUILD_TOOLS_DIR?}/aapt" | 
 | DX_BIN="${ANDROID_SDK_BUILD_TOOLS_DIR?}/dx" | 
 | ZIPALIGN_BIN="${ANDROID_SDK_BUILD_TOOLS_DIR?}/zipalign" | 
 | APKSIGNER_BIN="${ANDROID_SDK_BUILD_TOOLS_DIR?}/apksigner" | 
 |  | 
 | AAPT_ADD="${AAPT_BIN?} add" | 
 | # Link in the Android framework classes and disable compression for IREE | 
 | # bytecode modules. This allows us to mmap the file directly. | 
 | AAPT_PACK="${AAPT_BIN?} package -f -I ${ANDROID_SDK_PLATFORMS_DIR?}/android.jar -0 vmfb" | 
 | DX="${DX_BIN?} --dex" | 
 | ZIPALIGN="${ZIPALIGN_BIN?} -f -p 4" | 
 | APKSIGN="${APKSIGNER_BIN?} sign" | 
 | JAVAC="${JAVAC_BIN?} -classpath ${ANDROID_SDK_PLATFORMS_DIR?}/android.jar -sourcepath ${IREE_RESOURCE_GEN_DIR?} -d ${IREE_APK_PARTS_DIR?}" | 
 |  | 
 | ############################# | 
 | # Build IREE native libraries | 
 | ############################# | 
 |  | 
 | mkdir -p "${IREE_NATIVE_LIB_BUILD_DIR?}" | 
 |  | 
 | echo ">>> Building IREE native libraries <<<" | 
 |  | 
 | IREE_NATIVE_LIB_NAME=iree_tools_android_run_module_app_iree_run_module_app | 
 |  | 
 | pushd "${IREE_NATIVE_LIB_BUILD_DIR?}" | 
 | "${CMAKE_BIN?}" "${IREE_SOURCE_ROOT?}" -G Ninja \ | 
 |   -DCMAKE_BUILD_TYPE="${IREE_BUILD_TYPE?}" \ | 
 |   -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK_ROOT?}/build/cmake/android.toolchain.cmake" \ | 
 |   -DANDROID_ABI="${IREE_ANDROID_ABI?}" \ | 
 |   -DANDROID_PLATFORM="android-${IREE_ANDROID_API_LEVEL?}" \ | 
 |   -DIREE_HOST_C_COMPILER="${CC_BIN?}" \ | 
 |   -DIREE_HOST_CXX_COMPILER="${CXX_BIN?}" \ | 
 |   -DIREE_BUILD_COMPILER=OFF \ | 
 |   -DIREE_BUILD_TESTS=OFF \ | 
 |   -DIREE_BUILD_SAMPLES=OFF | 
 | "${NINJA_BIN?}" "${IREE_NATIVE_LIB_NAME?}" | 
 | popd | 
 |  | 
 | ##################### | 
 | # Package Android app | 
 | ##################### | 
 |  | 
 | # Clean artifacts from previous runs. | 
 | rm -rf "${IREE_ARTIFACT_ROOT?}/${IREE_APK_NAME?}.apk" "${IREE_APK_PARTS_DIR?}" | 
 |  | 
 | echo ">>> Generating AndroidManifest.xml <<<" | 
 |  | 
 | # Create an AndroidManifest.xml with proper target SDK version. | 
 | mkdir -p "${IREE_APK_PARTS_DIR?}" | 
 | IREE_ANDROID_API_LEVEL="${IREE_ANDROID_API_LEVEL?}" envsubst \ | 
 |   < "${IREE_NATIVE_APP_SOURCE_ROOT?}/AndroidManifest.xml.template" \ | 
 |   > "${IREE_APK_PARTS_DIR?}/AndroidManifest.xml" | 
 |  | 
 | echo ">>> Preparing shared libraries and vm module information <<<" | 
 |  | 
 | # Find the compiled iree_run_module_app shared library and symlink it to a | 
 | # known location for packaging. | 
 | mkdir -p "${IREE_NATIVE_LIB_DIR?}" | 
 | IREE_NATIVE_LIB=$(find ${IREE_NATIVE_LIB_BUILD_DIR?} -name "lib${IREE_NATIVE_LIB_NAME?}.so") | 
 | # Note: the target link name must match with | 
 | # run_module_app/AndroidManifest.xml.template. | 
 | ln -sf "${IREE_NATIVE_LIB?}" "${IREE_NATIVE_LIB_DIR?}/libiree_run_module_app.so" | 
 |  | 
 | # Copy the VM FlatBuffer and iree-run-module invocation related information | 
 | # over as assets. | 
 | mkdir -p "${IREE_ASSET_DIR?}" | 
 | # Note: the following files must match with run_module_app/src/main.cc. | 
 | cp "${IREE_INPUT_MODULE_FILE?}" "${IREE_ASSET_DIR?}/module.vmfb" | 
 | cp "${IREE_INPUT_BUFFER_FILE?}" "${IREE_ASSET_DIR?}/inputs.txt" | 
 | echo -n "${IREE_ENTRY_FUNCTION?}" > "${IREE_ASSET_DIR?}/entry_function.txt" | 
 | echo -n "${IREE_DEVICE?}" > "${IREE_ASSET_DIR?}/device.txt" | 
 |  | 
 | echo ">>> Compiling app resources <<<" | 
 |  | 
 | # Generate the R.java for resources. | 
 | mkdir -p "${IREE_RESOURCE_GEN_DIR?}" | 
 | ${AAPT_PACK?} --non-constant-id -m \ | 
 |   -M "${IREE_APK_PARTS_DIR?}/AndroidManifest.xml" \ | 
 |   -S "${IREE_NATIVE_APP_SOURCE_ROOT?}/res" \ | 
 |   -J "${IREE_RESOURCE_GEN_DIR?}" \ | 
 |   --generate-dependencies | 
 |  | 
 | # Compile the R.java and create classes.dex out of it for Android. | 
 | echo "Using javac: '${JAVAC_BIN?}'" | 
 | ${JAVAC?} "${IREE_RESOURCE_GEN_DIR?}"/com/iree-org/iree/run_module/*.java | 
 | ${DX?} --output="${IREE_APK_PARTS_DIR?}/classes.dex" "${IREE_APK_PARTS_DIR?}" | 
 |  | 
 | echo ">>> Packaging apk file <<<" | 
 |  | 
 | # Package assets and shared libraries into an apk file. | 
 | ${AAPT_PACK?} -m \ | 
 |   -M "${IREE_APK_PARTS_DIR?}/AndroidManifest.xml" \ | 
 |   -S "${IREE_NATIVE_APP_SOURCE_ROOT?}/res" \ | 
 |   -A "${IREE_APK_PARTS_DIR?}/assets" \ | 
 |   -F "${IREE_APK_PARTS_DIR?}/${IREE_APK_NAME?}.unaligned.apk" \ | 
 |   --shared-lib "${IREE_APK_PARTS_DIR?}/libs" | 
 |  | 
 | pushd "${IREE_APK_PARTS_DIR?}" | 
 | # Also package the resources into the apk file. | 
 | ${AAPT_ADD?} "${IREE_APK_NAME?}.unaligned.apk" classes.dex | 
 | echo ">>> Aligning apk file <<<" | 
 | ${ZIPALIGN?} "${IREE_APK_NAME?}.unaligned.apk" "${IREE_APK_NAME?}.apk" | 
 | echo ">>> Signing apk file <<<" | 
 | echo "NOTE: if you are using the Android Studio's debug keystore, the password is 'android'." | 
 | ${APKSIGN?} --ks "${ANDROID_KEYSTORE?}" --min-sdk-version 28 "${IREE_APK_NAME?}.apk" | 
 | mv "${IREE_APK_NAME?}.apk" "${IREE_ARTIFACT_ROOT?}" | 
 | popd | 
 |  | 
 | echo ">>> Done: '${IREE_ARTIFACT_ROOT?}/${IREE_APK_NAME?}.apk' <<<" |