onnxruntime/tools/ci_build/github/android/build_aar_package.py
Ashrit Shetty df873177eb
Update win-ort-main to tip main 250116 (#23398)
### Description
This PR is to update the win-ort-main branch to the tip main
branch as of 2025-01-16.

### Motivation and Context
This update includes the OpenVino fix for debug builds.

---------

Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqun.fu@microsoft.com>
Signed-off-by: Junze Wu <junze.wu@intel.com>
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jianhui Dai <jianhui.j.dai@intel.com>
Co-authored-by: Yueqing Zhang <yuz75@Pitt.edu>
Co-authored-by: amancini-N <63410090+amancini-N@users.noreply.github.com>
Co-authored-by: Adrian Lizarraga <adlizarraga@microsoft.com>
Co-authored-by: liqun Fu <liqfu@microsoft.com>
Co-authored-by: Guenther Schmuelling <guschmue@microsoft.com>
Co-authored-by: Yifan Li <109183385+yf711@users.noreply.github.com>
Co-authored-by: yf711 <yifanl@microsoft.com>
Co-authored-by: Wanming Lin <wanming.lin@intel.com>
Co-authored-by: wejoncy <wejoncy@163.com>
Co-authored-by: wejoncy <wejoncy@.com>
Co-authored-by: Scott McKay <skottmckay@gmail.com>
Co-authored-by: Changming Sun <chasun@microsoft.com>
Co-authored-by: Jean-Michaël Celerier <jeanmichael.celerier+github@gmail.com>
Co-authored-by: Dmitry Deshevoy <mityada@gmail.com>
Co-authored-by: xhcao <xinghua.cao@intel.com>
Co-authored-by: Yueqing Zhang <yueqingz@amd.com>
Co-authored-by: Yulong Wang <7679871+fs-eire@users.noreply.github.com>
Co-authored-by: Jiajia Qin <jiajiaqin@microsoft.com>
Co-authored-by: Wu, Junze <junze.wu@intel.com>
Co-authored-by: Jian Chen <cjian@microsoft.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Matthieu Darbois <mayeut@users.noreply.github.com>
Co-authored-by: Prathik Rao <prathik.rao@gmail.com>
Co-authored-by: wonchung-microsoft <wonchung@microsoft.com>
Co-authored-by: Vincent Wang <wangwchpku@outlook.com>
Co-authored-by: PARK DongHa <luncliff@gmail.com>
Co-authored-by: Hector Li <hecli@microsoft.com>
Co-authored-by: Sam Webster <13457618+samwebster@users.noreply.github.com>
Co-authored-by: Adrian Lizarraga <adrianlm2@gmail.com>
Co-authored-by: Preetha Veeramalai <preetha.veeramalai@intel.com>
Co-authored-by: jatinwadhwa921 <jatin.wadhwa@intel.com>
Co-authored-by: Satya Kumar Jandhyala <satya.k.jandhyala@gmail.com>
Co-authored-by: Corentin Maravat <101636442+cocotdf@users.noreply.github.com>
Co-authored-by: Xiaoyu <85524621+xiaoyu-work@users.noreply.github.com>
Co-authored-by: Tianlei Wu <tlwu@microsoft.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jie Chen <jie.a.chen@intel.com>
Co-authored-by: Jianhui Dai <jianhui.j.dai@intel.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Edward Chen <18449977+edgchen1@users.noreply.github.com>
Co-authored-by: Baiju Meswani <bmeswani@microsoft.com>
Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com>
Co-authored-by: Justin Chu <justinchuby@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Ted Themistokleous <107195283+TedThemistokleous@users.noreply.github.com>
Co-authored-by: Jeff Daily <jeff.daily@amd.com>
Co-authored-by: Artur Wojcik <artur.wojcik@outlook.com>
Co-authored-by: Ted Themistokleous <tedthemistokleous@amd.com>
Co-authored-by: Xinya Zhang <Xinya.Zhang@amd.com>
Co-authored-by: ikalinic <ilija.kalinic@amd.com>
Co-authored-by: sstamenk <sstamenk@amd.com>
Co-authored-by: Yi-Hong Lyu <yilyu@microsoft.com>
Co-authored-by: Ti-Tai Wang <titaiwang@microsoft.com>
2025-01-16 15:20:25 -08:00

251 lines
10 KiB
Python

#!/usr/bin/env python3
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import argparse
import json
import os
import pathlib
import shutil
import subprocess
import sys
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
REPO_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, "..", "..", "..", ".."))
BUILD_PY = os.path.join(REPO_DIR, "tools", "ci_build", "build.py")
JAVA_ROOT = os.path.join(REPO_DIR, "java")
sys.path.insert(0, os.path.join(REPO_DIR, "tools", "python"))
from util import is_windows # noqa: E402
# We by default will build all 4 ABIs
DEFAULT_BUILD_ABIS = ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]
# Onnx Runtime native library is built against NDK API 21 by default
# It is possible to build from source for Android API levels below 21, but it is not guaranteed
DEFAULT_ANDROID_MIN_SDK_VER = 24
# Android API 24 is the default target API version for Android builds, based on Microsoft 1CS requirements
# It is possible to build from source using API level 21 and higher as the target SDK version
DEFAULT_ANDROID_TARGET_SDK_VER = 34
def _parse_build_settings(args):
setting_file = args.build_settings_file.resolve()
if not setting_file.is_file():
raise FileNotFoundError(f"Build config file {setting_file} is not a file.")
with open(setting_file) as f:
build_settings_data = json.load(f)
build_settings = {}
build_settings["build_abis"] = build_settings_data.get("build_abis", DEFAULT_BUILD_ABIS)
build_params = []
if "build_params" in build_settings_data:
build_params += build_settings_data["build_params"]
else:
raise ValueError("build_params is required in the build config file")
if "android_min_sdk_version" in build_settings_data:
build_settings["android_min_sdk_version"] = build_settings_data["android_min_sdk_version"]
else:
build_settings["android_min_sdk_version"] = DEFAULT_ANDROID_MIN_SDK_VER
build_params += ["--android_api=" + str(build_settings["android_min_sdk_version"])]
if "android_target_sdk_version" in build_settings_data:
build_settings["android_target_sdk_version"] = build_settings_data["android_target_sdk_version"]
else:
build_settings["android_target_sdk_version"] = DEFAULT_ANDROID_TARGET_SDK_VER
if build_settings["android_min_sdk_version"] > build_settings["android_target_sdk_version"]:
raise ValueError(
"android_min_sdk_version {} cannot be larger than android_target_sdk_version {}".format(
build_settings["android_min_sdk_version"], build_settings["android_target_sdk_version"]
)
)
build_settings["build_params"] = build_params
return build_settings
def _build_aar(args):
build_settings = _parse_build_settings(args)
build_dir = os.path.abspath(args.build_dir)
ops_config_path = os.path.abspath(args.include_ops_by_config) if args.include_ops_by_config else None
qnn_android_build = "--use_qnn" in build_settings["build_params"]
# Setup temp environment for building
temp_env = os.environ.copy()
temp_env["ANDROID_HOME"] = os.path.abspath(args.android_sdk_path)
temp_env["ANDROID_NDK_HOME"] = os.path.abspath(args.android_ndk_path)
# Temp dirs to hold building results
intermediates_dir = os.path.join(build_dir, "intermediates")
build_config = args.config
aar_dir = os.path.join(intermediates_dir, "aar", build_config)
jnilibs_dir = os.path.join(intermediates_dir, "jnilibs", build_config)
exe_dir = os.path.join(intermediates_dir, "executables", build_config)
base_build_command = [sys.executable, BUILD_PY] + build_settings["build_params"] + ["--config=" + build_config]
header_files_path = ""
if qnn_android_build:
qnn_home = args.qnn_path
sdk_file = os.path.join(qnn_home, "sdk.yaml")
qnn_sdk_version = None
with open(sdk_file) as f:
for line in f:
if line.strip().startswith("version:"):
# yaml file has simple key: value format with version as key
qnn_sdk_version = line.split(":", 1)[1].strip()
break
# Note: The QNN package version does not follow Semantic Versioning (SemVer) format.
# only use major.minor.patch version for qnn sdk version and truncate the build_id info if any
# yaml file typically has version like 2.26.0
if qnn_sdk_version:
qnn_sdk_version = ".".join(qnn_sdk_version.split(".")[:3])
base_build_command += ["--qnn_home=" + qnn_home]
else:
raise ValueError("Error: QNN SDK version not found in sdk.yaml file.")
# Build binary for each ABI, one by one
for abi in build_settings["build_abis"]:
abi_build_dir = os.path.join(intermediates_dir, abi)
abi_build_command = [*base_build_command, "--android_abi=" + abi, "--build_dir=" + abi_build_dir]
if ops_config_path is not None:
abi_build_command += ["--include_ops_by_config=" + ops_config_path]
subprocess.run(abi_build_command, env=temp_env, shell=False, check=True, cwd=REPO_DIR)
# create symbolic links for libonnxruntime.so and libonnxruntime4j_jni.so
# to jnilibs/[abi] for later compiling the aar package
abi_jnilibs_dir = os.path.join(jnilibs_dir, abi)
os.makedirs(abi_jnilibs_dir, exist_ok=True)
for lib_name in ["libonnxruntime.so", "libonnxruntime4j_jni.so"]:
target_lib_name = os.path.join(abi_jnilibs_dir, lib_name)
# If the symbolic already exists, delete it first
# For some reason, os.path.exists will return false for a symbolic link in Linux,
# add double check with os.path.islink
if os.path.exists(target_lib_name) or os.path.islink(target_lib_name):
os.remove(target_lib_name)
os.symlink(os.path.join(abi_build_dir, build_config, lib_name), target_lib_name)
# copy executables for each abi, in case we want to publish those as well
# some of them might not exist, e.g., if we skip building the tests
abi_exe_dir = os.path.join(exe_dir, abi)
for exe_name in ["libonnxruntime.so", "onnxruntime_perf_test", "onnx_test_runner"]:
src_exe_path = os.path.join(abi_build_dir, build_config, exe_name)
if not os.path.exists(src_exe_path):
continue
os.makedirs(abi_exe_dir, exist_ok=True)
dest_exe_path = os.path.join(abi_exe_dir, exe_name)
shutil.copyfile(src_exe_path, dest_exe_path)
# we only need to define the header files path once
if not header_files_path:
header_files_path = os.path.join(abi_build_dir, build_config, "android", "headers")
# The directory to publish final AAR
aar_publish_dir = os.path.join(build_dir, "aar_out", build_config)
os.makedirs(aar_publish_dir, exist_ok=True)
gradle_path = os.path.join(JAVA_ROOT, "gradlew" if not is_windows() else "gradlew.bat")
# get the common gradle command args
gradle_command = [
gradle_path,
"--no-daemon",
"-b=build-android.gradle",
"-c=settings-android.gradle",
"-DjniLibsDir=" + jnilibs_dir,
"-DbuildDir=" + aar_dir,
"-DheadersDir=" + header_files_path,
"-DpublishDir=" + aar_publish_dir,
"-DminSdkVer=" + str(build_settings["android_min_sdk_version"]),
"-DtargetSdkVer=" + str(build_settings["android_target_sdk_version"]),
(
"-DENABLE_TRAINING_APIS=1"
if "--enable_training_apis" in build_settings["build_params"]
else "-DENABLE_TRAINING_APIS=0"
),
"-DreleaseVersionSuffix=" + os.getenv("RELEASE_VERSION_SUFFIX", ""),
]
# Add qnn specific parameters
if qnn_android_build:
gradle_command.append(f"-DqnnVersion={qnn_sdk_version}")
# clean, build, and publish to a local directory
subprocess.run([*gradle_command, "clean"], env=temp_env, shell=False, check=True, cwd=JAVA_ROOT)
subprocess.run([*gradle_command, "build"], env=temp_env, shell=False, check=True, cwd=JAVA_ROOT)
subprocess.run([*gradle_command, "publish"], env=temp_env, shell=False, check=True, cwd=JAVA_ROOT)
def parse_args():
parser = argparse.ArgumentParser(
os.path.basename(__file__),
description="""Create Android Archive (AAR) package for one or more Android ABI(s)
and building properties specified in the given build config file, see
tools/ci_build/github/android/default_full_aar_build_settings.json for details.
The output of the final AAR package can be found under [build_dir]/aar_out
""",
)
parser.add_argument(
"--android_sdk_path", type=str, default=os.environ.get("ANDROID_HOME", ""), help="Path to the Android SDK"
)
parser.add_argument(
"--android_ndk_path", type=str, default=os.environ.get("ANDROID_NDK_HOME", ""), help="Path to the Android NDK"
)
parser.add_argument("--qnn_path", type=str, default=os.environ.get("QNN_HOME", ""), help="Path to the QNN SDK")
parser.add_argument(
"--build_dir",
type=str,
default=os.path.join(REPO_DIR, "build/android_aar"),
help="Provide the root directory for build output",
)
parser.add_argument(
"--include_ops_by_config",
type=str,
help="Include ops from config file. See /docs/Reduced_Operator_Kernel_build.md for more information.",
)
parser.add_argument(
"--config",
type=str,
default="Release",
choices=["Debug", "MinSizeRel", "Release", "RelWithDebInfo"],
help="Configuration to build.",
)
parser.add_argument(
"build_settings_file", type=pathlib.Path, help="Provide the file contains settings for building AAR"
)
return parser.parse_args()
def main():
args = parse_args()
# Android SDK and NDK path are required
if not args.android_sdk_path:
raise ValueError("android_sdk_path is required")
if not args.android_ndk_path:
raise ValueError("android_ndk_path is required")
_build_aar(args)
if __name__ == "__main__":
main()