Skip to content

Commit

Permalink
Build Apple xcframework (#892)
Browse files Browse the repository at this point in the history
  • Loading branch information
skyline75489 authored Sep 28, 2024
1 parent a7ed199 commit 8cf7dda
Show file tree
Hide file tree
Showing 19 changed files with 695 additions and 39 deletions.
7 changes: 7 additions & 0 deletions .pipelines/nuget-publishing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ parameters:
type: boolean
default: true

- name: enable_apple_framework
displayName: 'Whether Apple framework for iOS & MacCatalyst is built.'
type: boolean
default: false

- name: ort_version
displayName: 'OnnxRuntime version'
type: string
Expand Down Expand Up @@ -89,6 +94,7 @@ stages:
enable_win_dml: ${{ parameters.enable_win_dml }}
enable_win_arm64: ${{ parameters.enable_win_arm64 }}
enable_macos_cpu: ${{ parameters.enable_macos_cpu }}
enable_apple_framework: ${{ parameters.enable_apple_framework }}
ort_version: ${{ parameters.ort_version }}
ort_cuda_version: ${{ parameters.ort_cuda_version }}
ort_dml_version: ${{ parameters.ort_dml_version }}
Expand All @@ -104,6 +110,7 @@ stages:
enable_win_dml: ${{ parameters.enable_win_dml }}
enable_win_arm64: ${{ parameters.enable_win_arm64 }}
enable_macos_cpu: ${{ parameters.enable_macos_cpu }}
enable_apple_framework: ${{ parameters.enable_apple_framework }}
ort_version: ${{ parameters.ort_version }}
ort_cuda_version: ${{ parameters.ort_cuda_version }}
ort_dml_version: ${{ parameters.ort_dml_version }}
Expand Down
11 changes: 11 additions & 0 deletions .pipelines/stages/capi-packaging-stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ parameters:
type: boolean
- name: enable_macos_cpu
type: boolean
- name: enable_apple_framework
type: boolean
- name: ort_version
type: string
- name: ort_cuda_version
Expand Down Expand Up @@ -111,3 +113,12 @@ stages:
ort_version: ${{ parameters.ort_version }}
os: 'osx'
build_config: ${{ parameters.build_config }}

- ${{ if eq(parameters.enable_apple_framework, true) }}:
- template: jobs/capi-packaging-job.yml
parameters:
os: 'ios'
ep: 'cpu'
arch: 'arm64'
ort_version: ${{ parameters.ort_version }}
build_config: ${{ parameters.build_config }}
8 changes: 7 additions & 1 deletion .pipelines/stages/jobs/capi-packaging-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ parameters:
- 'linux'
- 'win'
- 'osx'
- 'ios'
- name: build_config
type: string
default: 'release'
Expand All @@ -34,7 +35,7 @@ jobs:
pool: 'onnxruntime-genai-windows-vs-2022-arm64'
${{ else }}:
pool: 'onnxruntime-Win-CPU-2022'
${{ if eq(parameters.os, 'osx') }}:
${{ if or(eq(parameters.os, 'osx'), eq(parameters.os, 'ios')) }}:
pool:
vmImage: 'macOS-latest'

Expand Down Expand Up @@ -143,4 +144,9 @@ jobs:
ep: ${{ parameters.ep }}
build_config: ${{ parameters.build_config }}

- ${{ if eq(parameters.os, 'ios') }}:
- template: steps/capi-appleframework-step.yml
parameters:
build_config: ${{ parameters.build_config }}

- template: steps/compliant-and-cleanup-step.yml
6 changes: 6 additions & 0 deletions .pipelines/stages/jobs/nuget-packaging-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ parameters:
type: boolean
default: false

- name: enable_apple_framework
displayName: 'Whether Apple framework for iOS & MacCatalyst is built.'
type: boolean
default: false

- name: ort_version
type: string

Expand Down Expand Up @@ -85,6 +90,7 @@ jobs:
value: 'Microsoft.ML.OnnxRuntime.Gpu'
${{ if eq(parameters.ep, 'directml') }}:
value: 'Microsoft.ML.OnnxRuntime.DirectML'

steps:
- ${{ if and(eq(parameters.enable_win_cpu, true), eq(parameters.ep, 'cpu')) }}:
- template: steps/utils/flex-download-pipeline-artifact.yml
Expand Down
39 changes: 39 additions & 0 deletions .pipelines/stages/jobs/steps/capi-appleframework-step.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
parameters:
- name: build_config
type: string
default: 'release'

steps:

- checkout: self
clean: true
path: onnxruntime-genai
submodules: recursive

- template: utils/set-genai-version.yml

- template: utils/set-nightly-build-option-variable.yml

- script: |
set -e
python3 -m pip install requests
python3 tools/ci_build/github/apple/build_apple_framework.py \
--build_dir "$(Build.BinariesDirectory)/apple_framework" \
tools/ci_build/github/apple/default_full_ios_framework_build_settings.json
mkdir $(Build.BinariesDirectory)/artifacts
mkdir -p $(Build.BinariesDirectory)/artifacts_staging/onnxruntime-genai-ios-xcframework-$(genai_version)
cp -R $(Build.BinariesDirectory)/apple_framework/framework_out/onnxruntime-genai.xcframework \
$(Build.BinariesDirectory)/artifacts_staging/onnxruntime-genai-ios-xcframework-$(genai_version)
pushd $(Build.BinariesDirectory)/artifacts_staging
zip -vr $(Build.BinariesDirectory)/artifacts/onnxruntime_genai_ios_xcframework.zip \
onnxruntime-genai-ios-xcframework-$(genai_version)
popd
displayName: 'Build Apple XCFramework'
workingDirectory: '$(Build.Repository.LocalPath)'

- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: ONNXRuntime GenAI XCFramework'
inputs:
ArtifactName: capi-onnxruntime-genai-ios-xcframework
PathtoPublish: '$(Build.BinariesDirectory)/artifacts'
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ steps:
inputs:
debugMode: false
continueOnError: true
condition: ne(variables['os'], 'osx') # Not available on macOS. See https://eng.ms/docs/products/credential-risk-exposure-defense/solutions/credscan_client/overview
condition: and(ne(variables['os'], 'osx'), ne(variables['os'], 'ios')) # Not available on macOS. See https://eng.ms/docs/products/credential-risk-exposure-defense/solutions/credscan_client/overview

- task: TSAUpload@2
displayName: 'TSA upload'
Expand Down
6 changes: 6 additions & 0 deletions .pipelines/stages/nuget-packaging-stage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ parameters:
type: boolean
default: true

- name: enable_apple_framework
displayName: 'Whether Apple framework for iOS & MacCatalyst is built.'
type: boolean
default: false

- name: ort_version
type: string
- name: ort_cuda_version
Expand All @@ -57,6 +62,7 @@ stages:
enable_win_cpu: ${{ parameters.enable_win_cpu }}
enable_win_arm64: ${{ parameters.enable_win_arm64 }}
enable_macos_cpu: ${{ parameters.enable_macos_cpu }}
enable_apple_framework: ${{ parameters.enable_apple_framework }}
- ${{ if or(eq(parameters.enable_linux_cuda, true), eq(parameters.enable_win_cuda, true)) }}:
- template: jobs/nuget-packaging-job.yml
parameters:
Expand Down
23 changes: 21 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

cmake_minimum_required(VERSION 3.26)
cmake_minimum_required(VERSION 3.28)
include(FetchContent)
include(CMakeDependentOption)
project(Generators LANGUAGES C CXX)
Expand All @@ -13,6 +13,12 @@ if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_
message(FATAL_ERROR "GCC version must be greater than or equal to 11")
endif()

# Avoid warning of Calling FetchContent_Populate(Lib) is deprecated temporarily
# TODO: find a better way to handle the header-only 3rd party deps
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.30.0")
cmake_policy(SET CMP0169 OLD)
endif()

if(MSVC)
# DLL initialization errors due to old conda msvcp140.dll dll are a result of the new MSVC compiler
# See https://developercommunity.visualstudio.com/t/Access-violation-with-std::mutex::lock-a/10664660#T-N10668856
Expand Down Expand Up @@ -46,6 +52,15 @@ if(MSVC)
)
endif()

# Suggested by https://gitlab.kitware.com/cmake/cmake/-/issues/20132
# MacCatalyst is not well supported in CMake
# The error that can emerge without this flag can look like:
# "clang : error : overriding '-mmacosx-version-min=11.0' option with '-target x86_64-apple-ios14.0-macabi' [-Werror,-Woverriding-t-option]"
if (PLATFORM_NAME STREQUAL "macabi")
add_compile_options(-Wno-overriding-t-option)
add_link_options(-Wno-overriding-t-option)
endif()

if(ENABLE_TESTS)
# call enable_testing so we can add tests from subdirectories (e.g. test and src/java)
# it applies recursively to all subdirectories
Expand Down Expand Up @@ -85,12 +100,16 @@ target_link_directories(onnxruntime-genai PRIVATE ${ORT_LIB_DIR})

# we keep the shared libraries disconnected on Android as they will come from separate AARs and we don't want to force
# the ORT version to match in both.
if(CMAKE_SYSTEM_NAME STREQUAL "Android" OR CMAKE_SYSTEM_NAME STREQUAL "Linux" OR (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND (NOT BUILD_APPLE_FRAMEWORK)))
if(CMAKE_SYSTEM_NAME STREQUAL "Android" OR CMAKE_SYSTEM_NAME STREQUAL "Linux" OR (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND (NOT BUILD_APPLE_FRAMEWORK) AND (NOT MAC_CATALYST)))
add_compile_definitions(_ORT_GENAI_USE_DLOPEN)
else()
target_link_libraries(onnxruntime-genai PRIVATE ${ONNXRUNTIME_LIB})
endif()

if(APPLE)
target_link_libraries(onnxruntime-genai PRIVATE "-framework Foundation" "-framework CoreML")
endif()

set_target_properties(onnxruntime-genai PROPERTIES FOLDER "Sources")
set_target_properties(onnxruntime-genai-static PROPERTIES FOLDER "Sources")
source_group(TREE ${PROJECT_SOURCE_DIR} FILES ${generator_srcs})
Expand Down
75 changes: 57 additions & 18 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,12 @@ class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescript
# The following options are mutually exclusive (cross compiling options such as android, ios, etc.)
platform_group = parser.add_mutually_exclusive_group()
platform_group.add_argument("--android", action="store_true", help="Build for Android")
platform_group.add_argument("--ios", action="store_true", help="Build for ios")
platform_group.add_argument("--ios", action="store_true", help="Build for iOS")
platform_group.add_argument(
"--macos",
choices=["MacOSX", "Catalyst"],
help="Specify the target platform for macOS build. Only specify this argument when --build_apple_framework is present.",
)

# Android options
parser.add_argument(
Expand All @@ -157,23 +162,27 @@ class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescript

# iOS build options
parser.add_argument(
"--ios_sysroot",
"--apple_sysroot",
default="",
help="Specify the location name of the macOS platform SDK to be used",
)
parser.add_argument(
"--ios_arch",
"--osx_arch",
type=str,
help="Specify the Target specific architectures for iOS "
"This is only supported on MacOS host",
)
parser.add_argument(
"--ios_deployment_target",
"--apple_deploy_target",
type=str,
help="Specify the minimum version of the target platform "
"This is only supported on MacOS host",
)

parser.add_argument(
"--build_apple_framework", action="store_true", help="Build a macOS/iOS framework for the ONNXRuntime."
)

parser.add_argument(
"--arm64",
action="store_true",
Expand Down Expand Up @@ -285,14 +294,14 @@ def _validate_ios_args(args: argparse.Namespace):
raise ValueError("A Mac host is required to build for iOS")

needed_args = [
args.ios_sysroot,
args.ios_arch,
args.ios_deployment_target,
args.apple_sysroot,
args.osx_arch,
args.apple_deploy_target,
]
arg_names = [
"--ios_sysroot <the location or name of the macOS platform SDK>",
"--ios_arch <the Target specific architectures for iOS>",
"--ios_deployment_target <the minimum version of the target platform>",
"--apple_sysroot <the location or name of the macOS platform SDK>",
"--osx_arch <the Target specific architectures for iOS>",
"--apple_deploy_target <the minimum version of the target platform>",
]
have_required_args = all(_ is not None for _ in needed_args)
if not have_required_args:
Expand Down Expand Up @@ -485,9 +494,26 @@ def update(args: argparse.Namespace, env: dict[str, str]):
"-DENABLE_TESTS=OFF",
]

if args.ios or args.macos:
platform_name = "macabi" if args.macos == "Catalyst" else args.apple_sysroot
command += [
"-DENABLE_PYTHON=OFF",
"-DENABLE_TESTS=OFF",
"-DENABLE_MODEL_BENCHMARK=OFF",
f"-DBUILD_APPLE_FRAMEWORK={'ON' if args.build_apple_framework else 'OFF'}",
"-DPLATFORM_NAME=" + platform_name,
]

if args.macos:
command += [
f"-DCMAKE_OSX_SYSROOT={args.apple_sysroot}",
f"-DCMAKE_OSX_ARCHITECTURES={args.osx_arch}",
f"-DCMAKE_OSX_DEPLOYMENT_TARGET={args.apple_deploy_target}",
]

if args.ios:
def _get_opencv_toolchain_file():
if args.ios_sysroot == "iphoneos":
if args.apple_sysroot == "iphoneos":
return (
REPO_ROOT / "cmake" / "external" / "opencv" / "platforms" / "iOS" / "cmake" /
"Toolchains" / "Toolchain-iPhoneOS_Xcode.cmake"
Expand All @@ -498,19 +524,32 @@ def _get_opencv_toolchain_file():
"Toolchains" / "Toolchain-iPhoneSimulator_Xcode.cmake"
)


command += [
"-DCMAKE_SYSTEM_NAME=iOS",
f"-DCMAKE_OSX_SYSROOT={args.ios_sysroot}",
f"-DCMAKE_OSX_ARCHITECTURES={args.ios_arch}",
f"-DCMAKE_OSX_DEPLOYMENT_TARGET={args.ios_deployment_target}",
"-DENABLE_PYTHON=OFF",
f"-DIOS_ARCH={args.osx_arch}",
f"-DIPHONEOS_DEPLOYMENT_TARGET={args.apple_deploy_target}",
# The following arguments are specific to the OpenCV toolchain file
f"-DIOS_ARCH={args.ios_arch}",
f"-DIPHONEOS_DEPLOYMENT_TARGET={args.ios_deployment_target}",
f"-DCMAKE_TOOLCHAIN_FILE={_get_opencv_toolchain_file()}",
]

if args.macos == "Catalyst":
if args.cmake_generator == "Xcode":
raise Exception("Xcode CMake generator ('--cmake_generator Xcode') doesn't support Mac Catalyst build.")

macabi_target = f"{args.osx_arch}-apple-ios{args.apple_deploy_target}-macabi"
command += [
"-DCMAKE_CXX_COMPILER_TARGET=" + macabi_target,
"-DCMAKE_C_COMPILER_TARGET=" + macabi_target,
"-DCMAKE_CC_COMPILER_TARGET=" + macabi_target,
f"-DCMAKE_CXX_FLAGS=--target={macabi_target}",
f"-DCMAKE_CXX_FLAGS_RELEASE=-O3 -DNDEBUG --target={macabi_target}",
f"-DCMAKE_C_FLAGS=--target={macabi_target}",
f"-DCMAKE_C_FLAGS_RELEASE=-O3 -DNDEBUG --target={macabi_target}",
f"-DCMAKE_CC_FLAGS=--target={macabi_target}",
f"-DCMAKE_CC_FLAGS_RELEASE=-O3 -DNDEBUG --target={macabi_target}",
"-DMAC_CATALYST=1",
]

if args.arm64:
command += ["-A", "ARM64"]
elif args.arm64ec:
Expand Down
20 changes: 20 additions & 0 deletions cmake/Info.plist.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>${MACOSX_FRAMEWORK_NAME}</string>
<key>CFBundleName</key>
<string>${MACOSX_FRAMEWORK_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_FRAMEWORK_IDENTIFIER}</string>
<key>CFBundleVersion</key>
<string>${ORT_VERSION}</string>
<key>CFBundleShortVersionString</key>
<string>${ORT_VERSION}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
</dict>
</plist>
6 changes: 6 additions & 0 deletions cmake/external/onnxruntime_external_deps.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,9 @@ FetchContent_Declare(
)
set(OCOS_BUILD_PRESET ort_genai)
onnxruntime_fetchcontent_makeavailable(onnxruntime_extensions)

list(APPEND EXTERNAL_LIBRARIES
onnxruntime_extensions
ocos_operators
noexcep_operators
)
Loading

0 comments on commit 8cf7dda

Please sign in to comment.