From 8b5354fb672ce8fa9a771c54ac79e7e8d6083f2f Mon Sep 17 00:00:00 2001 From: vraspar Date: Mon, 12 Aug 2024 17:37:22 -0700 Subject: [PATCH] Update macosx framework packaging to follow apple guidelines (#776) * Update macosx framework packaging to follow apple guidelines * Test path fix * Update tools/ci_build/extract_nuget_files.ps1 --------- --- .pipelines/ios_packaging.yml | 2 +- .../build-package-for-ios-cocoapods.yml | 4 +- nuget/DummyNativeNuget.nuspec | 2 +- nuget/NativeNuget.nuspec | 2 +- ...icrosoft.ML.OnnxRuntime.Extensions.targets | 2 +- tools/android/build_aar.py | 9 +-- tools/ci_build/extract_nuget_files.ps1 | 17 ++++- tools/ios/assemble_pod_package.py | 13 +++- tools/ios/build_xcframework.py | 75 ++++++++++++++----- 9 files changed, 92 insertions(+), 34 deletions(-) diff --git a/.pipelines/ios_packaging.yml b/.pipelines/ios_packaging.yml index 8e75ea215..83087c008 100644 --- a/.pipelines/ios_packaging.yml +++ b/.pipelines/ios_packaging.yml @@ -162,7 +162,7 @@ jobs: pushd ${POD_STAGING_DIR} # assemble the files in the artifacts staging directory - zip -r ${ARTIFACTS_STAGING_DIR}/${POD_ARCHIVE_BASENAME} * --exclude ${PODSPEC_BASENAME} + zip -vry ${ARTIFACTS_STAGING_DIR}/${POD_ARCHIVE_BASENAME} * --exclude ${PODSPEC_BASENAME} cp ${PODSPEC_BASENAME} ${ARTIFACTS_STAGING_DIR}/${PODSPEC_BASENAME} popd diff --git a/.pipelines/templates/build-package-for-ios-cocoapods.yml b/.pipelines/templates/build-package-for-ios-cocoapods.yml index 059e4d74b..52a0724c8 100644 --- a/.pipelines/templates/build-package-for-ios-cocoapods.yml +++ b/.pipelines/templates/build-package-for-ios-cocoapods.yml @@ -173,13 +173,13 @@ jobs: POD_STAGING_DIR="$(Build.BinariesDirectory)/pod_staging" ARTIFACTS_STAGING_DIR="$(Build.ArtifactStagingDirectory)" POD_NAME="onnxruntime-extensions-c" - POD_ARCHIVE_BASENAME="pod-archive-${POD_NAME}-${ORT_EXTENSIONS_POD_VERSION}.zip" + POD_ARCHIVE_BASENAME="onnxruntime_extensions.xcframework.${ORT_EXTENSIONS_POD_VERSION}.zip" PODSPEC_BASENAME="${POD_NAME}.podspec" pushd ${POD_STAGING_DIR} # assemble the files in the artifacts staging directory - zip -r ${ARTIFACTS_STAGING_DIR}/${POD_ARCHIVE_BASENAME} * --exclude ${PODSPEC_BASENAME} + zip -vry ${ARTIFACTS_STAGING_DIR}/${POD_ARCHIVE_BASENAME} * --exclude ${PODSPEC_BASENAME} cp ${PODSPEC_BASENAME} ${ARTIFACTS_STAGING_DIR}/${PODSPEC_BASENAME} popd diff --git a/nuget/DummyNativeNuget.nuspec b/nuget/DummyNativeNuget.nuspec index 81260fa1a..a85cb6fdc 100644 --- a/nuget/DummyNativeNuget.nuspec +++ b/nuget/DummyNativeNuget.nuspec @@ -54,7 +54,7 @@ - + diff --git a/nuget/NativeNuget.nuspec b/nuget/NativeNuget.nuspec index 22ce047f9..e5f9b65dd 100644 --- a/nuget/NativeNuget.nuspec +++ b/nuget/NativeNuget.nuspec @@ -51,7 +51,7 @@ - + diff --git a/nuget/targets/net6.0-ios/Microsoft.ML.OnnxRuntime.Extensions.targets b/nuget/targets/net6.0-ios/Microsoft.ML.OnnxRuntime.Extensions.targets index 9c05e6f79..6d6821cb0 100644 --- a/nuget/targets/net6.0-ios/Microsoft.ML.OnnxRuntime.Extensions.targets +++ b/nuget/targets/net6.0-ios/Microsoft.ML.OnnxRuntime.Extensions.targets @@ -1,7 +1,7 @@ - + Static True True diff --git a/tools/android/build_aar.py b/tools/android/build_aar.py index 49b026a4d..8b0e34dfc 100755 --- a/tools/android/build_aar.py +++ b/tools/android/build_aar.py @@ -30,10 +30,7 @@ def build_for_abi( str(_repo_dir / "tools" / "build.py"), f"--build_dir={build_dir}", f"--config={config}", - "--update", - "--build", "--parallel", - "--test", # Android options "--android", f"--android_abi={abi}", @@ -53,7 +50,7 @@ def do_build_by_mode( api_level: int, sdk_path: Path, ndk_path: Path, - build_py_args: list[str] + build_py_args: list[str], ): output_dir = output_dir.resolve() @@ -77,12 +74,12 @@ def do_build_by_mode( jnilib_names = ["libortextensions.so", "libonnxruntime_extensions4j_jni.so"] for jnilib_name in jnilib_names: - shutil.copyfile(build_dir / config / "java" / "android" / abi / jnilib_name, jnilibs_dir / jnilib_name) + shutil.copyfile(build_dir / config / "lib" / jnilib_name, jnilibs_dir / jnilib_name) # depending on the build settings these libraries may not be build optional_jnilib_names = ["libcrypto.so", "libssl.so", "libcurl.so"] for jnilib_name in optional_jnilib_names: - src = build_dir / config / "java" / "android" / abi / jnilib_name + src = build_dir / config / "lib" / jnilib_name if src.exists(): shutil.copyfile(src, jnilibs_dir / jnilib_name) diff --git a/tools/ci_build/extract_nuget_files.ps1 b/tools/ci_build/extract_nuget_files.ps1 index 79d3d2aac..21257833c 100644 --- a/tools/ci_build/extract_nuget_files.ps1 +++ b/tools/ci_build/extract_nuget_files.ps1 @@ -20,7 +20,7 @@ New-Item -Path $nuget_sources_dir -ItemType directory ## .zip files # unzip directly -Get-ChildItem $artifact_download_dir -Filter *.zip | +Get-ChildItem $artifact_download_dir -Include *.zip -Exclude onnxruntime_extensions.xcframework.*.zip | Foreach-Object { $cmd = "7z.exe x $($_.FullName) -y -o$nuget_sources_dir" Write-Output $cmd @@ -44,6 +44,21 @@ Foreach-Object { Invoke-Expression -Command $cmd } +# process iOS xcframework +$xcframeworks = Get-ChildItem $Env:BUILD_BINARIESDIRECTORY\nuget-artifacts -Filter onnxruntime_extensions.xcframework.*.zip +if ($xcframeworks.Count -eq 1) { + $xcframework = $xcframeworks[0] + # remove version info from filename and use required filename format + $target_file = "$nuget_sources_dir\onnxruntime_extensions.xcframework.zip" + New-Item -Path $target_dir -ItemType directory + + Write-Output "Copy-Item $($xcframework.FullName) $target_file" + Copy-Item $xcframework.FullName $target_file +} +elseif ($xcframeworks.Count -ne 1) { + Write-Error "Expected at most one onnxruntime_extensions.xcframework.*.zip file but got: [$xcframeworks]" +} + # copy android AAR. # target file structure: diff --git a/tools/ios/assemble_pod_package.py b/tools/ios/assemble_pod_package.py index 195d52f0d..138634fc9 100755 --- a/tools/ios/assemble_pod_package.py +++ b/tools/ios/assemble_pod_package.py @@ -7,10 +7,10 @@ import argparse import json -from pathlib import Path import re import shutil import sys +from pathlib import Path from typing import Dict _script_dir = Path(__file__).resolve().parent @@ -60,7 +60,12 @@ def replace_template_variable(match): def assemble_pod_package( - staging_dir: Path, xcframework_dir: Path, public_headers_dir: Path, xcframework_info_file: Path, pod_version: str, catalyst_enabled: bool, + staging_dir: Path, + xcframework_dir: Path, + public_headers_dir: Path, + xcframework_info_file: Path, + pod_version: str, + catalyst_enabled: bool, ): staging_dir = staging_dir.resolve() xcframework_dir = xcframework_dir.resolve(strict=True) @@ -74,8 +79,8 @@ def assemble_pod_package( # copy files to staging dir shutil.copyfile(_repo_dir / "LICENSE", staging_dir / "LICENSE") - shutil.copytree(xcframework_dir, staging_dir / xcframework_dir.name, dirs_exist_ok=True) - shutil.copytree(public_headers_dir, staging_dir / public_headers_dir.name, dirs_exist_ok=True) + shutil.copytree(xcframework_dir, staging_dir / xcframework_dir.name, dirs_exist_ok=True, symlinks=True) + shutil.copytree(public_headers_dir, staging_dir / public_headers_dir.name, dirs_exist_ok=True, symlinks=True) # generate podspec pod_name = "onnxruntime-extensions-c" diff --git a/tools/ios/build_xcframework.py b/tools/ios/build_xcframework.py index 22f278784..993bbb1b4 100644 --- a/tools/ios/build_xcframework.py +++ b/tools/ios/build_xcframework.py @@ -9,10 +9,9 @@ import argparse import json -import os -from pathlib import Path import shutil import sys +from pathlib import Path _repo_dir = Path(__file__).resolve().parents[2] sys.path.insert(0, str(_repo_dir / "tools")) @@ -98,7 +97,7 @@ def build_framework_for_platform_and_arch( cmake_defines = [] - if platform != "macosx" and platform != "maccatalyst": #ios simulator or iphoneos platform + if platform != "macosx" and platform != "maccatalyst": # ios simulator or iphoneos platform cmake_defines += [ # required by OpenCV CMake toolchain file # https://github.com/opencv/opencv/blob/4223495e6cd67011f86b8ecd9be1fa105018f3b1/platforms/ios/cmake/Toolchains/common-ios-toolchain.cmake#L64-L66 @@ -213,19 +212,61 @@ def platform_arch_framework_build_dir(platform, arch): platform_fat_framework_dir.mkdir() # copy over files from arch-specific framework to fat framework - for framework_file_relative_path in [Path("Headers"), Path("Info.plist")]: - src = first_arch_framework_dir / framework_file_relative_path - dst = platform_fat_framework_dir / framework_file_relative_path - if src.is_dir(): - shutil.copytree(src, dst) - else: - shutil.copy(src, dst) - - # combine arch-specific framework libraries - arch_libs = [str(framework_dir / "onnxruntime_extensions") for framework_dir in arch_framework_dirs] - run( - *([_lipo, "-create", "-output", str(platform_fat_framework_dir / "onnxruntime_extensions")] + arch_libs) - ) + # macos requires different framework structure: + # https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html + if platform == "macosx" or platform == "maccatalyst": + # Set up directory strcture + dest_headers_dir = platform_fat_framework_dir / "Versions/A/Headers" + dest_resources_dir = platform_fat_framework_dir / "Versions/A/Resources" + + # Copy headers and Info.plist + shutil.copytree(first_arch_framework_dir / Path("Headers"), dest_headers_dir) + Path(dest_resources_dir).mkdir(parents=True, exist_ok=True) + shutil.copy(first_arch_framework_dir / Path("Info.plist"), dest_resources_dir / "Info.plist") + + # combine arch-specific framework libraries + arch_libs = [str(framework_dir / "onnxruntime_extensions") for framework_dir in arch_framework_dirs] + run( + *( + [ + _lipo, + "-create", + "-output", + str(platform_fat_framework_dir / "Versions/A/onnxruntime_extensions"), + ] + + arch_libs + ) + ) + + # create Symbolic links + Path(platform_fat_framework_dir / "Versions/Current").symlink_to("A", target_is_directory=True) + Path(platform_fat_framework_dir / "Headers").symlink_to( + "Versions/Current/Headers", target_is_directory=True + ) + Path(platform_fat_framework_dir / "Resources").symlink_to( + "Versions/Current/Resources", target_is_directory=True + ) + Path(platform_fat_framework_dir / "onnxruntime_extensions").symlink_to( + "Versions/Current/onnxruntime_extensions" + ) + + else: + for framework_file_relative_path in [Path("Headers"), Path("Info.plist")]: + src = first_arch_framework_dir / framework_file_relative_path + dst = platform_fat_framework_dir / framework_file_relative_path + if src.is_dir(): + shutil.copytree(src, dst) + else: + shutil.copy(src, dst) + + # combine arch-specific framework libraries + arch_libs = [str(framework_dir / "onnxruntime_extensions") for framework_dir in arch_framework_dirs] + run( + *( + [_lipo, "-create", "-output", str(platform_fat_framework_dir / "onnxruntime_extensions")] + + arch_libs + ) + ) platform_fat_framework_dirs.append(platform_fat_framework_dir) @@ -241,7 +282,7 @@ def platform_arch_framework_build_dir(platform, arch): # copy public headers output_headers_dir = output_dir / "Headers" _rmtree_if_existing(output_headers_dir) - shutil.copytree(headers_dir, output_headers_dir) + shutil.copytree(headers_dir, output_headers_dir, symlinks=True) # merge framework_info.json per platform into xcframework_info.json in output_dir _merge_framework_info_files(framework_info_files_to_merge, Path(output_dir, "xcframework_info.json"))