Update Android instructions (#3971)

Update Android build instructions to provide more information.
Add info on testing directly on Android
Update build.py to better support using Ninja generator to build Android on Windows.
This commit is contained in:
Scott McKay 2020-05-19 07:30:45 +10:00 committed by GitHub
parent 024b92a970
commit c6a94f95cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 174 additions and 14 deletions

View file

@ -83,7 +83,7 @@ For other system requirements and other dependencies, please see [this section](
|Description|Command|Additional description|
|-----------|-----------|-----------|
|**Basic build**|build.bat (Windows)<br>./build.sh (Linux)||
|**Debug build**|--config RelWithDebInfo|Debug build|
|**Release build**|--config Release|Release build. Other valid config values are RelWithDebInfo and Debug.|
|**Use OpenMP**|--use_openmp|OpenMP will parallelize some of the code for potential performance improvements. This is not recommended for running on single threads.|
|**Build using parallel processing**|--parallel|This is strongly recommended to speed up the build.|
|**Build Shared Library**|--build_shared_lib||
@ -829,19 +829,90 @@ ls -l /code/onnxruntime/build/Linux/MinSizeRel/dist/*.whl
#### Pre-Requisites
Install Android NDK in Android Studio or https://developer.android.com/ndk/downloads
The SDK and NDK packages can be installed via Android Studio or the sdkmanager command line tool.
Android Studio is more convenient but a larger installation.
The command line tools are smaller and usage can be scripted, but are a little more complicated to setup. They also require a Java runtime environment to be available.
General Info:
- API levels: https://developer.android.com/guide/topics/manifest/uses-sdk-element.html
- Android ABIs: https://developer.android.com/ndk/guides/abis
- System Images: https://developer.android.com/topic/generic-system-image
##### Android Studio
Install Android Studio from https://developer.android.com/studio
Install any additional SDK Platforms if necessary
- File->Settings->Appearance & Behavior->System Settings->Android SDK to see what is currently installed
- Note that the SDK path you need to use as --android_sdk_path when building ORT is also on this configuration page
- Most likely you don't require additional SDK Platform packages as the latest platform can target earlier API levels.
Install an NDK version
- File->Settings->Appearance & Behavior->System Settings->Android SDK
- 'SDK Tools' tab
- Select 'Show package details' checkbox at the bottom to see specific versions.
By default the latest will be installed which should be fine.
- The NDK path will be the 'ndk/{version}' subdirectory of the SDK path shown
- e.g. if 21.1.6352462 is installed it will be {SDK path}/ndk/21.1.6352462
##### sdkmanager from command line tools
- If necessary install the Java Runtime Environment and set the JAVA_HOME environment variable to point to it
- https://www.java.com/en/download/
- Windows note: You MUST install the 64-bit version (https://www.java.com/en/download/manual.jsp) otherwise sdkmanager will only list x86 packages
and the latest NDK is x64 only.
- For sdkmanager to work it needs a certain directory structure.
First create the top level directory for the Android infrastructure.
- in our example we'll call that `.../Android/`
- Download the command line tools from the 'Command line tools only' section towards the bottom
of https://developer.android.com/studio
- Create a directory called 'cmdline-tools' under your top level directory
- giving `.../Android/cmdline-tools`
- extract the 'tools' directory from the command line tools zip file into this directory
- giving `.../Android/cmdline-tools/tools`
- Windows note: preferably extract using 7-zip.
If using the built in Windows zip extract tool you will need to fix the directory structure
by moving the jar files from `tools\lib\_` up to `tools\lib`
- See https://stackoverflow.com/questions/27364963/could-not-find-or-load-main-class-com-android-sdkmanager-main
- you should now be able to run Android/cmdline-tools/bin/sdkmanager[.bat] successfully
- if you see an error about it being unable to save settings and the sdkmanager help text,
your directory structure is incorrect.
- see the final steps in this answer to double check: https://stackoverflow.com/a/61176718
- Run `.../Android/cmdline-tools/bin/sdkmanager --list` to see the packages available
- Install the SDK Platform
- Generally installing the latest is fine. You pick an API level when compiling the code and the latest platform will support many recent API levels
- e.g. `sdkmanager --install "platforms;android-29"`
- This will install into the 'platforms' directory of our top level directory
- so the 'Android' directory in our example
- The SDK path to use as --android_sdk_path when building is this top level directory
- Install the NDK
- Find the available NDK versions by running `sdkmanager --list`
- Install
- you can install a specific version or the latest (called 'ndk-bundle')
- e.g. `sdkmanager --install "ndk;21.1.6352462"`
- NDK path in our example with this install would be `.../Android/ndk/21.1.6352462`
- NOTE: If you install the ndk-bundle package the path will be `.../Android/ndk-bundle` as there's no version number
#### Build Instructions
##### Cross compiling on Windows
```bash
./build.bat --android --android_sdk_path <android sdk path> --android_ndk_path <android ndk path> --android_abi <android abi, e.g., arm64-v8a (default) or armeabi-v7a> --android_api <android api level, e.g., 27 (default)>
The [Ninja](https://ninja-build.org/) generator needs to be used to build on Windows as the Visual Studio generator doesn't support Android.
```
./build.bat --android --android_sdk_path <android sdk path> --android_ndk_path <android ndk path> --android_abi <android abi, e.g., arm64-v8a (default) or armeabi-v7a> --android_api <android api level, e.g., 27 (default)> --cmake_generator Ninja
```
e.g. using the paths from our example
```
./build.bat --android --android_sdk_path .../Android --android_ndk_path .../Android/ndk/21.1.6352462 --android_abi arm64-v8a --android_api 27 --cmake_generator Ninja
```
##### Cross compiling on Linux
```bash
```
./build.sh --android --android_sdk_path <android sdk path> --android_ndk_path <android ndk path> --android_abi <android abi, e.g., arm64-v8a (default) or armeabi-v7a> --android_api <android api level, e.g., 27 (default)>
```

81
docs/Android_testing.md Normal file
View file

@ -0,0 +1,81 @@
# Testing Android Changes using the Emulator
See [BUILD.md](../Build.md#Android) for Android build instructions and information on the locations of the various files referred to here.
## Install the emulator
If using Android Studio this is included in the base install.
If using sdkmanager install the emulator by running
- `sdkmanager[.bat] --install "emulator"`
The emulator will emulate the Android device not its processor, so you need to build onnxruntime
with an ABI that's valid for the host machine, and install a system image that matches.
For example you can emulate a Pixel 3 device on an Intel 64-bit host, but it will require a binary built against x86_64
rather than the arm64-v8a ABI of the real device.
e.g. on Intel 64-bit you would build with `--android_abi x86_64` to create onnxruntime libraries/executables that can be run on the Android emulator
## Create the device to emulate
### Android Studio
Tools->AVD Manager->Create Virtual Device...
Once created the emulator can be started using the 'play' button in AVD Manager.
### sdkmanager
First install a system image. Use `sdkmanager --list` to see the available system images.
e.g. `sdkmanager --install "system-images;android-27;default;x86_64`
Create the virtual device using avdmanager[.bat] (which should be in the same directory as sdkmanager[.bat]).
e.g. `avdmanager create avd -n android27_emulator -k "system-images;android-27;default;x86_64"`
Run the emulator
e.g. `.../Android/emulator/emulator -avd android27_emulator -partition-size 2048 -no-snapshot -no-audio`
## Testing running a model on the emulator directly
Use ADB to copy files and execute commands
https://developer.android.com/studio/command-line/adb
ADB is located in the 'platform-tools' folder of the SDK directory.
Copy onnx_test_runner and the directory of the model to test (in ONNX test directory format) to /data/local/tmp.
```
adb push <onnxruntime repo>/build/<platform>/<config>/onnx_test_runner /data/local/tmp/
adb push <onnxruntime repo>/build/<platform>/<config>/testdata/transform/gemm_activation_fusion /data/local/tmp/
```
e.g. on Windows that might be
```
<Android SDK path>\platform-tools\adb.exe push <onnxruntime repo>\build\Windows\Debug\onnx_test_runner /data/local/tmp/testdata
<Android SDK path>\platform-tools\adb.exe push <onnxruntime repo>\build\Windows\Debug\testdata\transform\gemm_activation_fusion /data/local/tmp/
```
You may need to change permissions to make onnx_test_runner executable:
`<Android SDK path>\platform-tools\adb.exe shell chmod +x /data/local/tmp/onnx_test_runner`
Run onnx_test_runner with the model directory:
`<Android SDK path>\platform-tools\adb.exe shell 'cd /data/local/tmp && ./onnx_test_runner gemm_activation_fusion'`
The output should look something like this:
```
D:\Android\platform-tools> .\adb.exe shell 'cd /data/local/tmp && ./onnx_test_runner gemm_activation_fusion'
result:
Models: 1
Total test cases: 1
Succeeded: 1
Not implemented: 0
Failed: 0
Stats by Operator type:
Not implemented(0):
Failed:
Failed Test Cases:
```

View file

@ -831,7 +831,7 @@ def build_targets(args, cmake_path, build_dir, configs, parallel):
build_tool_args = []
if parallel:
num_cores = str(multiprocessing.cpu_count())
if is_windows():
if is_windows() and args.cmake_generator != 'Ninja':
build_tool_args += [
"/maxcpucount:" + num_cores,
# if nodeReuse is true, msbuild processes will stay around for a bit after the build completes
@ -1417,8 +1417,11 @@ def build_protoc_for_host(cmake_path, source_dir, build_dir, args):
'-Dprotobuf_WITH_ZLIB_DEFAULT=OFF',
'-Dprotobuf_BUILD_SHARED_LIBS=OFF'
]
is_ninja = args.cmake_generator == 'Ninja'
if is_windows():
if args.cmake_generator != 'Ninja':
if not is_ninja:
cmd_args += ['-T', 'host=x64']
cmd_args += ['-G', args.cmake_generator]
elif is_macOS() and args.use_xcode:
@ -1433,14 +1436,19 @@ def build_protoc_for_host(cmake_path, source_dir, build_dir, args):
run_subprocess(cmd_args)
# Absolute protoc path is needed for cmake
expected_protoc_path = (
os.path.join(
protoc_build_dir, 'Release', 'protoc.exe') if is_windows()
else (os.path.join(protoc_build_dir, 'Release', 'protoc')
if is_macOS() and args.use_xcode
else os.path.join(protoc_build_dir, 'protoc')))
config_dir = ''
suffix = ''
if (is_windows() and not is_ninja) or (is_macOS() and args.use_xcode):
config_dir = 'Release'
if is_windows():
suffix = '.exe'
expected_protoc_path = os.path.join(protoc_build_dir, config_dir, 'protoc' + suffix)
if not os.path.exists(expected_protoc_path):
raise BuildError("Couldn't build protoc for host. Failing build.")
raise BuildError("Couldn't find {}. Host build of protoc failed.".format(expected_protoc_path))
return expected_protoc_path