mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-29 20:14:01 +00:00
Move iOS package from framework to xcframework (#8805)
* additional changes * test package run * minor fix * minor fix * minor fix * Get around no arm64 simulator * fix objc pod build failure * downgrade_eigen * update objc podspec template
This commit is contained in:
parent
e25986781f
commit
8992e31c85
7 changed files with 107 additions and 52 deletions
|
|
@ -15,11 +15,11 @@ 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")
|
||||
|
||||
# We by default will build below 2 archs
|
||||
DEFAULT_BUILD_OSX_ARCHS = [
|
||||
{'sysroot': 'iphoneos', 'arch': 'arm64'},
|
||||
{'sysroot': 'iphonesimulator', 'arch': 'x86_64'},
|
||||
]
|
||||
# We by default will build below 3 archs
|
||||
DEFAULT_BUILD_OSX_ARCHS = {
|
||||
'iphoneos': ['arm64'],
|
||||
'iphonesimulator': ['arm64', 'x86_64'],
|
||||
}
|
||||
|
||||
|
||||
def _parse_build_settings(args):
|
||||
|
|
@ -40,23 +40,16 @@ def _parse_build_settings(args):
|
|||
return build_settings
|
||||
|
||||
|
||||
def _build_package(args):
|
||||
build_settings = _parse_build_settings(args)
|
||||
build_dir = os.path.abspath(args.build_dir)
|
||||
|
||||
# Temp dirs to hold building results
|
||||
intermediates_dir = os.path.join(build_dir, 'intermediates')
|
||||
build_config = args.config
|
||||
base_build_command = [sys.executable, BUILD_PY, '--config=' + build_config] + build_settings['build_params']
|
||||
|
||||
# Build fat framework for all archs of a single sysroot
|
||||
# For example, arm64 and x86_64 for iphonesimulator
|
||||
def _build_for_ios_sysroot(build_config, intermediates_dir, base_build_command,
|
||||
sysroot, archs, build_dynamic_framework):
|
||||
# paths of the onnxruntime libraries for different archs
|
||||
ort_libs = []
|
||||
info_plist_path = ''
|
||||
|
||||
# Build binary for each arch, one by one
|
||||
for osx_arch in build_settings['build_osx_archs']:
|
||||
sysroot = osx_arch['sysroot']
|
||||
current_arch = osx_arch['arch']
|
||||
for current_arch in archs:
|
||||
build_dir_current_arch = os.path.join(intermediates_dir, sysroot + "_" + current_arch)
|
||||
build_command = base_build_command + [
|
||||
'--ios_sysroot=' + sysroot,
|
||||
|
|
@ -64,16 +57,13 @@ def _build_package(args):
|
|||
'--build_dir=' + build_dir_current_arch
|
||||
]
|
||||
|
||||
if args.include_ops_by_config is not None:
|
||||
build_command += ['--include_ops_by_config=' + str(args.include_ops_by_config.resolve())]
|
||||
|
||||
# the actual build process for current arch
|
||||
subprocess.run(build_command, shell=False, check=True, cwd=REPO_DIR)
|
||||
|
||||
# get the compiled lib path
|
||||
framework_dir = os.path.join(
|
||||
build_dir_current_arch, build_config, build_config + "-" + sysroot,
|
||||
'onnxruntime.framework' if args.build_dynamic_framework
|
||||
'onnxruntime.framework' if build_dynamic_framework
|
||||
else os.path.join('static_framework', 'onnxruntime.framework'))
|
||||
ort_libs.append(os.path.join(framework_dir, 'onnxruntime'))
|
||||
|
||||
|
|
@ -84,12 +74,15 @@ def _build_package(args):
|
|||
headers = glob.glob(os.path.join(framework_dir, 'Headers', '*.h'))
|
||||
|
||||
# manually create the fat framework
|
||||
framework_dir = os.path.join(build_dir, 'framework_out', 'onnxruntime.framework')
|
||||
framework_dir = os.path.join(intermediates_dir, 'frameworks', sysroot, 'onnxruntime.framework')
|
||||
# remove the existing framework if any
|
||||
if os.path.exists(framework_dir):
|
||||
shutil.rmtree(framework_dir)
|
||||
pathlib.Path(framework_dir).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# copy the Info.plist, framework_info.json, and header files
|
||||
shutil.copy(info_plist_path, framework_dir)
|
||||
shutil.copy(framework_info_path, build_dir)
|
||||
shutil.copy(framework_info_path, os.path.dirname(framework_dir))
|
||||
header_dir = os.path.join(framework_dir, 'Headers')
|
||||
pathlib.Path(header_dir).mkdir(parents=True, exist_ok=True)
|
||||
for _header in headers:
|
||||
|
|
@ -101,14 +94,62 @@ def _build_package(args):
|
|||
lipo_command += ['-output', os.path.join(framework_dir, 'onnxruntime')]
|
||||
subprocess.run(lipo_command, shell=False, check=True)
|
||||
|
||||
return framework_dir
|
||||
|
||||
|
||||
def _build_package(args):
|
||||
build_settings = _parse_build_settings(args)
|
||||
build_dir = os.path.abspath(args.build_dir)
|
||||
|
||||
# Temp dirs to hold building results
|
||||
intermediates_dir = os.path.join(build_dir, 'intermediates')
|
||||
build_config = args.config
|
||||
base_build_command = [sys.executable, BUILD_PY, '--config=' + build_config] + build_settings['build_params']
|
||||
if args.include_ops_by_config is not None:
|
||||
base_build_command += ['--include_ops_by_config=' + str(args.include_ops_by_config.resolve())]
|
||||
|
||||
# build framework for individual sysroot
|
||||
framework_dirs = []
|
||||
framework_info_path = ''
|
||||
public_headers_path = ''
|
||||
for sysroot in build_settings['build_osx_archs']:
|
||||
framework_dir = _build_for_ios_sysroot(
|
||||
build_config, intermediates_dir, base_build_command, sysroot,
|
||||
build_settings['build_osx_archs'][sysroot], args.build_dynamic_framework)
|
||||
framework_dirs.append(framework_dir)
|
||||
# podspec and headers for each sysroot are the same, pick one of them
|
||||
if not framework_info_path:
|
||||
framework_info_path = os.path.join(os.path.dirname(framework_dir), 'framework_info.json')
|
||||
public_headers_path = os.path.join(os.path.dirname(framework_dir), 'onnxruntime.framework', 'Headers')
|
||||
|
||||
# create the folder for xcframework and copy the LICENSE and podspec file
|
||||
xcframework_dir = os.path.join(build_dir, 'framework_out')
|
||||
pathlib.Path(xcframework_dir).mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy(os.path.join(REPO_DIR, 'LICENSE'), xcframework_dir)
|
||||
shutil.copytree(public_headers_path, os.path.join(xcframework_dir, 'Headers'), dirs_exist_ok=True)
|
||||
shutil.copy(framework_info_path, build_dir)
|
||||
|
||||
# remove existing xcframework if any
|
||||
xcframework_path = os.path.join(xcframework_dir, 'onnxruntime.xcframework')
|
||||
if os.path.exists(xcframework_path):
|
||||
shutil.rmtree(xcframework_path)
|
||||
|
||||
# Assemble the final xcframework
|
||||
build_xcframework_cmd = ['xcrun', 'xcodebuild', '-create-xcframework',
|
||||
'-output', xcframework_path]
|
||||
for framework_dir in framework_dirs:
|
||||
build_xcframework_cmd.extend(['-framework', framework_dir])
|
||||
|
||||
subprocess.run(build_xcframework_cmd, shell=False, check=True, cwd=REPO_DIR)
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
os.path.basename(__file__),
|
||||
description='''Create iOS framework and podspec for one or more osx_archs (fat framework)
|
||||
description='''Create iOS framework and podspec for one or more osx_archs (xcframework)
|
||||
and building properties specified in the given build config file, see
|
||||
tools/ci_build/github/apple/default_mobile_ios_framework_build_settings.json for details.
|
||||
The output of the final framework and podspec can be found under [build_dir]/framework_out.
|
||||
The output of the final xcframework and podspec can be found under [build_dir]/framework_out.
|
||||
Please note, this building script will only work on macOS.
|
||||
'''
|
||||
)
|
||||
|
|
@ -124,12 +165,12 @@ def parse_args():
|
|||
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 iOS framework')
|
||||
|
||||
parser.add_argument("--build_dynamic_framework", action='store_true',
|
||||
help="Build Dynamic Framework (default is build static framework).")
|
||||
|
||||
parser.add_argument('build_settings_file', type=pathlib.Path,
|
||||
help='Provide the file contains settings for building iOS framework')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.build_settings_file.resolve().is_file():
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ def parse_args():
|
|||
parser.add_argument("--framework-info-file", type=pathlib.Path, required=True,
|
||||
help="Path to the framework_info.json file containing additional values for the podspec. "
|
||||
"This file should be generated by CMake in the build directory.")
|
||||
parser.add_argument("--public-headers-dir", type=pathlib.Path, required=True,
|
||||
help="Path to the public headers directory to include in the pod.")
|
||||
parser.add_argument("--framework-dir", type=pathlib.Path, required=True,
|
||||
help="Path to the onnxruntime.framework directory to include in the pod.")
|
||||
|
||||
|
|
@ -50,6 +52,8 @@ def main():
|
|||
# copy the necessary files to the staging directory
|
||||
framework_dir = args.framework_dir.resolve()
|
||||
shutil.copytree(framework_dir, staging_dir / framework_dir.name, dirs_exist_ok=True)
|
||||
public_headers_dir = args.public_headers_dir.resolve()
|
||||
shutil.copytree(public_headers_dir, staging_dir / public_headers_dir.name, dirs_exist_ok=True)
|
||||
copy_repo_relative_to_dir(["LICENSE"], staging_dir)
|
||||
|
||||
# generate the podspec file from the template
|
||||
|
|
|
|||
|
|
@ -7,20 +7,16 @@ Pod::Spec.new do |spec|
|
|||
spec.source = { :http => "file:///http_source_placeholder" }
|
||||
spec.summary = "ONNX Runtime Mobile C/C++ Pod"
|
||||
spec.platform = :ios, "@IOS_DEPLOYMENT_TARGET@"
|
||||
spec.vendored_frameworks = "onnxruntime.framework"
|
||||
spec.vendored_frameworks = "onnxruntime.xcframework"
|
||||
spec.static_framework = true
|
||||
spec.weak_framework = [ @WEAK_FRAMEWORK@ ]
|
||||
spec.source_files = "onnxruntime.framework/Headers/*.h"
|
||||
spec.source_files = "Headers/*.h"
|
||||
spec.preserve_paths = [ @LICENSE_FILE@ ]
|
||||
spec.description = <<-DESC
|
||||
A pod for the ONNX Runtime Mobile C/C++ library.
|
||||
DESC
|
||||
spec.library = "c++"
|
||||
spec.pod_target_xcconfig = {
|
||||
spec.library = "c++"
|
||||
spec.pod_target_xcconfig = {
|
||||
"OTHER_CPLUSPLUSFLAGS" => "-fvisibility=hidden -fvisibility-inlines-hidden",
|
||||
}
|
||||
spec.user_target_xcconfig = {
|
||||
# TODO workaround - support arm64 iphonesimulator later
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" => "arm64"
|
||||
}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
{
|
||||
"build_osx_archs": [
|
||||
{
|
||||
"sysroot": "iphoneos",
|
||||
"arch": "arm64"
|
||||
},
|
||||
{
|
||||
"sysroot": "iphonesimulator",
|
||||
"arch": "x86_64"
|
||||
}
|
||||
],
|
||||
"build_osx_archs": {
|
||||
"iphoneos": [
|
||||
"arm64"
|
||||
],
|
||||
"iphonesimulator": [
|
||||
"arm64",
|
||||
"x86_64"
|
||||
]
|
||||
},
|
||||
"build_params": [
|
||||
"--ios",
|
||||
"--parallel",
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ Pod::Spec.new do |s|
|
|||
core.pod_target_xcconfig = {
|
||||
"HEADER_SEARCH_PATHS" => include_dirs.join(" "),
|
||||
"OTHER_CPLUSPLUSFLAGS" => "-fvisibility=hidden -fvisibility-inlines-hidden",
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" => "arm64",
|
||||
}
|
||||
|
||||
core.public_header_files = [
|
||||
|
|
|
|||
|
|
@ -31,9 +31,17 @@ def _test_ios_packages(args):
|
|||
if not c_framework_dir.is_dir():
|
||||
raise FileNotFoundError('c_framework_dir {} is not a folder.'.format(c_framework_dir))
|
||||
|
||||
framework_path = os.path.join(c_framework_dir, 'onnxruntime.framework')
|
||||
if not pathlib.Path(framework_path).exists():
|
||||
raise FileNotFoundError('{} does not have onnxruntime.framework'.format(c_framework_dir))
|
||||
has_framework = pathlib.Path(os.path.join(c_framework_dir, 'onnxruntime.framework')).exists()
|
||||
has_xcframework = pathlib.Path(os.path.join(c_framework_dir, 'onnxruntime.xcframework')).exists()
|
||||
|
||||
if not has_framework and not has_xcframework:
|
||||
raise FileNotFoundError('{} does not have onnxruntime.framework/xcframework'.format(c_framework_dir))
|
||||
|
||||
if has_framework and has_xcframework:
|
||||
raise ValueError('Cannot proceed when both onnxruntime.framework '
|
||||
'and onnxruntime.xcframework exist')
|
||||
|
||||
framework_name = 'onnxruntime.framework' if has_framework else 'onnxruntime.xcframework'
|
||||
|
||||
# create a temp folder
|
||||
import tempfile
|
||||
|
|
@ -49,7 +57,7 @@ def _test_ios_packages(args):
|
|||
# shutil.make_archive require target file as full path without extension
|
||||
zip_base_filename = os.path.join(local_pods_dir, 'onnxruntime-mobile-c')
|
||||
zip_file_path = zip_base_filename + '.zip'
|
||||
shutil.make_archive(zip_base_filename, 'zip', root_dir=c_framework_dir, base_dir='onnxruntime.framework')
|
||||
shutil.make_archive(zip_base_filename, 'zip', root_dir=c_framework_dir, base_dir=framework_name)
|
||||
|
||||
# copy the test project to the temp_dir
|
||||
test_proj_path = os.path.join(REPO_DIR, 'onnxruntime', 'test', 'platform', 'ios', 'ios_package_test')
|
||||
|
|
@ -78,6 +86,13 @@ def _test_ios_packages(args):
|
|||
with open(podspec, 'r') as file:
|
||||
file_data = file.read()
|
||||
file_data = file_data.replace('file:///http_source_placeholder', 'file:' + zip_file_path)
|
||||
|
||||
# We will only publish xcframework, however, assembly of the xcframework is a post process
|
||||
# and it cannot be done by CMake for now. See, https://gitlab.kitware.com/cmake/cmake/-/issues/21752
|
||||
# For a single sysroot and arch built by build.py or cmake, we can only generate framework
|
||||
# We still need a way to test it, replace the xcframework with framework in the podspec
|
||||
if has_framework:
|
||||
file_data = file_data.replace('onnxruntime.xcframework', 'onnxruntime.framework')
|
||||
with open(podspec, 'w') as file:
|
||||
file.write(file_data)
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ jobs:
|
|||
--staging-dir "$(Build.BinariesDirectory)/staging/onnxruntime-mobile-c" \
|
||||
--pod-version ${ORT_POD_VERSION} \
|
||||
--framework-info-file "$(Build.BinariesDirectory)/ios_framework/framework_info.json" \
|
||||
--framework-dir "$(Build.BinariesDirectory)/ios_framework/framework_out/onnxruntime.framework"
|
||||
--framework-dir "$(Build.BinariesDirectory)/ios_framework/framework_out/onnxruntime.xcframework" \
|
||||
--public-headers-dir "$(Build.BinariesDirectory)/ios_framework/framework_out/Headers"
|
||||
displayName: "Assemble onnxruntime-mobile-c pod files"
|
||||
|
||||
- script: |
|
||||
|
|
|
|||
Loading…
Reference in a new issue