This guide walks through cross-compiling IREE core runtime towards the Android platform. Cross-compiling IREE compilers towards Android is not supported at the moment.
Cross-compilation involves both a host platform and a target platform. One invokes compiler toolchains on the host platform to generate libraries and executables that can be run on the target platform.
The host platform should have been set up for developing IREE. Right now Linux and Windows are supported. Please make sure you have followed the steps for Linux or Windows.
Android NDK provides compiler toolchains for compiling C/C++ code to target Android. You can download it here. We recommend to download the latest release; the steps in following sections may assume that.
Alternatively, if you have installed Android Studio, you can follow this guide to install Android NDK.
After downloading, it is recommended to set the ANDROID_NDK
environment variable pointing to the directory. For Linux, you can export
in your shell's rc file. For Windows, you can search “environment variable” in the taskbar or use Windows
+ R
to open the “Run” dialog to run rundll32 sysdm.cpl,EditEnvironmentVariables
.
For Linux, search your the distribution's package manager to install adb
. For example, on Ubuntu:
$ sudo apt install adb
For Windows, it's easier to get adb
via Android Studio. adb
is included in the Android SDK Platform-Tools package. You can download this package with the SDK Manager, which installs it at android_sdk/platform-tools/
. Or if you want the standalone Android SDK Platform-Tools package, you can download it here. You may also want to add the folder to the PATH
environment variable.
Build and install at least the compiler tools on your host machine, or install them from a binary distribution:
$ cmake -G Ninja -B ../iree-build-host/ -DCMAKE_INSTALL_PREFIX=../iree-build-host/install . $ cmake --build ../iree-build-host/ --target install
Debugging note:
IREE_LLVMAOT_LINKER_PATH
is set for targeting Android then the build above will fail, and you should run unset IREE_LLVMAOT_LINKER_PATH
.$ cmake -G Ninja -B ../iree-build-host/ \ -DCMAKE_C_COMPILER=clang \ -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_INSTALL_PREFIX=../iree-build-host/install .
Build the runtime using the Android NDK toolchain:
$ cmake -G Ninja -B ../iree-build-android/ \ -DCMAKE_TOOLCHAIN_FILE="${ANDROID_NDK?}/build/cmake/android.toolchain.cmake" \ -DIREE_HOST_BINARY_ROOT=$(realpath ../iree-build-host/install) \ -DANDROID_ABI="arm64-v8a" \ -DANDROID_PLATFORM=android-29 \ -DIREE_BUILD_COMPILER=OFF \ -DIREE_BUILD_SAMPLES=OFF \ . $ cmake --build ../iree-build-android/
-DANDROID_ABI="arm64-v8a"
) Android 10 (-DANDROID_PLATFORM=android-29
). This may require the latest Android NDK release. You can choose the suitable ANDROID_ABI
and ANDROID_PLATFORM
for your target device. You can also refer to Android NDK's CMake documentation for more toolchain arguments.Make sure you enable developer options and USB debugging for your Android device.
Connect your Android device to the development machine and make sure you can see the device when:
$ adb devices List of devices attached XXXXXXXXXXX device
Then you can run all device tests via
$ cd ../iree-build-android $ ctest --output-on-failure
The above command will upload necessary build artifacts to the Android device's /data/local/tmp
directory, run the tests there, and report status back.
Alternatively, if you want to invoke a specific HAL backend on a IREE module:
Translate a source MLIR into IREE module:
# Assuming in IREE source root $ ../iree-build-host/install/bin/iree-translate \ -iree-mlir-to-vm-bytecode-module \ -iree-hal-target-backends=vmvx \ $PWD/iree/samples/models/simple_abs.mlir \ -o /tmp/simple_abs_vmvx.vmfb
Then push the IREE runtime executable and module to the device:
$ adb push ../iree-build-android/iree/tools/iree-run-module /data/local/tmp/ $ adb shell chmod +x /data/local/tmp/iree-run-module $ adb push /tmp/simple_abs_vmvx.vmfb /data/local/tmp/
Log into Android:
$ adb shell android $ cd /data/local/tmp/ android $ ./iree-run-module \ --driver=vmvx \ --module_file=simple_abs_vmvx.vmfb \ --entry_function=abs \ --function_input=f32=-5 EXEC @abs f32=5
Please make sure your Android device is Vulkan capable. Vulkan is supported on Android since 7, but Android 10 is our primary target at the moment.
Translate a source MLIR into IREE module:
$ ../iree-build-host/install/bin/iree-translate \ -iree-mlir-to-vm-bytecode-module \ -iree-hal-target-backends=vulkan-spirv \ $PWD/iree/samples/models/simple_abs.mlir \ -o /tmp/simple_abs_vulkan.vmfb
Then push the IREE runtime executable and module to the device:
$ adb push ../iree-build-android/iree/tools/iree-run-module /data/local/tmp/ $ adb shell chmod +x /data/local/tmp/iree-run-module $ adb push /tmp/simple_abs_vulkan.vmfb /data/local/tmp/
Log into Android:
$ adb shell android $ cd /data/local/tmp/ android $ ./iree-run-module \ --driver=vulkan \ --module_file=simple_abs_vulkan.vmfb \ --entry_function=abs \ --function_input=f32=-5 EXEC @abs f32=5
vkCreateInstance
not availableSince Android 8 Oreo, Android re-architected the OS framework with project Treble. Framework libraries and vendor libraries have a more strict and clear separation. Their dependencies are carefully scrutinized and only selected cases are allowed. This is enforced with linker namespaces.
/data/local/tmp
is the preferred directory for automating native binary tests built using NDK toolchain. They should be allowed to access libraries like libvulkan.so
for their functionality. However, there was an issue with fully treblized Android 10 where /data/local/tmp
did not have access to the linker namespaces needed by libvulkan.so
. This should be fixed now. But as typically in the Android system, it takes a long time to see the fix getting propagated, if ever.
A known workaround is to symlink the vendor Vulkan implementation under /vendor/lib[64]
as libvulkan.so
under /data/local/tmp
and use LD_LIBRARY_PATH=/data/local/tmp
when invoking IREE executables.
For Qualcomm Adreno GPUs, the vendor Vulkan implementation is at /vendor/lib[64]/hw/vulkan.*.so
. So for example for Snapdragon 865:
$ adb shell ln -s /vendor/lib64/hw/vulkan.kona.so /data/local/tmp/libvulkan.so
For ARM Mali GPUs, there is only one monolithic driver (/vendor/lib[64]/libGLES_mali.so
) for OpenGL and Vulkan and the Vulkan vendor driver (/vendor/lib[64]/hw/vulkan.*.so
) is just a symlink to it. So for example:
$ adb shell ln -s /vendor/lib64/libGLES_mali.so /data/local/tmp/libvulkan.so
Translate a source MLIR into an IREE module:
$ ../iree-build-host/install/bin/iree-translate \ -iree-mlir-to-vm-bytecode-module \ -iree-hal-target-backends=dylib-llvm-aot \ -iree-llvm-target-triple=aarch64-linux-android \ $PWD/iree/samples/models/simple_abs.mlir \ -o /tmp/simple_abs_dylib.vmfb
Then push the IREE runtime executable and module to the device:
$ adb push ../iree-build-android/iree/tools/iree-run-module /data/local/tmp/ $ adb shell chmod +x /data/local/tmp/iree-run-module $ adb push /tmp/simple_abs_dylib.vmfb /data/local/tmp/
Log into Android:
$ adb shell android $ cd /data/local/tmp/ android $ ./iree-run-module \ --driver=dylib \ --module_file=simple_abs_dylib.vmfb \ --entry_function=abs \ --function_input=f32=-5 EXEC @abs f32=5