Skip to content

Commit

Permalink
Updates to apple packaging (#21611)
Browse files Browse the repository at this point in the history
### Description
<!-- Describe your changes. -->
Add ability to test packaging without rebuilding every time.
Add ability to comment out some platforms/architectures without the
scripts to assemble the c/obj-c packages breaking.
Update a couple of commands to preserve symlinks.


### Motivation and Context
<!-- - Why is this change required? What problem does it solve?
- If it fixes an open issue, please link to the issue here. -->
Make debugging packaging issues faster.
Creates correct package for mac-catalyst and doesn't require setting
symlinks via bash script.
  • Loading branch information
skottmckay authored and prathikr committed Aug 7, 2024
1 parent 48ea164 commit b61a7c9
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 36 deletions.
23 changes: 0 additions & 23 deletions tools/ci_build/github/apple/assemble_apple_packaging_artifacts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,6 @@ ORT_POD_VERSION=${4:?${USAGE_TEXT}}
POD_ARCHIVE_BASENAME="pod-archive-${POD_NAME}-${ORT_POD_VERSION}.zip"
PODSPEC_BASENAME="${POD_NAME}.podspec"


# Macos requires a different structure for the framework
# This will create the necessary symlinks for the macos framework before packaging
# Adding the symlinks here rather than in the build script ensures that symlinks are not lost
for MACOS_DIR in "${BINARIES_STAGING_DIR}/${POD_NAME}/onnxruntime.xcframework/macos"*; do
if [ -d "${MACOS_DIR}" ]; then
echo "Creating symlinks for ${MACOS_DIR}"
pushd "${MACOS_DIR}/onnxruntime.framework"

rm -rf Headers Resources onnxruntime
rm -rf Versions/Current

ln -sfn A Versions/Current
ln -sfn Versions/Current/Headers Headers
ln -sfn Versions/Current/Resources Resources
ln -sfn Versions/Current/onnxruntime onnxruntime

popd

fi
done


echo "Contents of ${BINARIES_STAGING_DIR}/${POD_NAME}:"
ls -lR "${BINARIES_STAGING_DIR}/${POD_NAME}"

Expand Down
11 changes: 9 additions & 2 deletions tools/ci_build/github/apple/build_and_assemble_apple_pods.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ def parse_args():
)

parser.add_argument("--test", action="store_true", help="Run tests on the framework and pod package files.")
parser.add_argument(
"--skip-build",
action="store_true",
help="Use build from previous run. Useful to debug test issues or packaging changes.",
)

build_framework_group = parser.add_argument_group(
title="iOS framework build arguments",
Expand Down Expand Up @@ -114,7 +119,8 @@ def main():

build_apple_framework_args += ["--build_dir", str(build_dir), args.build_settings_file]

run(build_apple_framework_args)
if not args.skip_build:
run(build_apple_framework_args)

if args.test:
test_apple_packages_args = [
Expand Down Expand Up @@ -171,7 +177,8 @@ def main():
def move_dir(src, dst):
if dst.is_dir():
shutil.rmtree(dst)
shutil.move(src, dst)
shutil.copytree(src, dst, symlinks=True)
shutil.rmtree(src)

move_dir(c_pod_staging_dir, staging_dir / c_pod_name)
move_dir(objc_pod_staging_dir, staging_dir / objc_pod_name)
Expand Down
2 changes: 1 addition & 1 deletion tools/ci_build/github/apple/build_apple_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def _build_package(args):
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.copytree(public_headers_path, os.path.join(xcframework_dir, "Headers"), dirs_exist_ok=True, symlinks=True)
_merge_framework_info_files(framework_info_files_to_merge, os.path.join(build_dir, "xcframework_info.json"))

# remove existing xcframework if any
Expand Down
13 changes: 8 additions & 5 deletions tools/ci_build/github/apple/c/assemble_c_pod_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
PackageVariant,
copy_repo_relative_to_dir,
gen_file_from_template,
get_podspec_values,
load_json_config,
)

Expand Down Expand Up @@ -66,23 +67,25 @@ def assemble_c_pod_package(
print("Warning: staging directory already exists", file=sys.stderr)

# copy the necessary files to the staging directory
shutil.copytree(framework_dir, staging_dir / framework_dir.name, dirs_exist_ok=True)
shutil.copytree(public_headers_dir, staging_dir / public_headers_dir.name, dirs_exist_ok=True)
shutil.copytree(framework_dir, staging_dir / framework_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)
copy_repo_relative_to_dir(["LICENSE"], staging_dir)

(ios_deployment_target, macos_deployment_target, weak_framework) = get_podspec_values(framework_info)

# generate the podspec file from the template
variable_substitutions = {
"DESCRIPTION": pod_config["description"],
# By default, we build both "iphoneos" and "iphonesimulator" architectures, and the deployment target should be the same between these two.
"IOS_DEPLOYMENT_TARGET": framework_info["iphonesimulator"]["APPLE_DEPLOYMENT_TARGET"],
"MACOSX_DEPLOYMENT_TARGET": framework_info.get("macosx", {}).get("APPLE_DEPLOYMENT_TARGET", ""),
"IOS_DEPLOYMENT_TARGET": ios_deployment_target,
"MACOSX_DEPLOYMENT_TARGET": macos_deployment_target,
"LICENSE_FILE": "LICENSE",
"NAME": pod_name,
"ORT_C_FRAMEWORK": framework_dir.name,
"ORT_C_HEADERS_DIR": public_headers_dir.name,
"SUMMARY": pod_config["summary"],
"VERSION": pod_version,
"WEAK_FRAMEWORK": framework_info["iphonesimulator"]["WEAK_FRAMEWORK"],
"WEAK_FRAMEWORK": weak_framework,
}

podspec_template = _script_dir / "c.podspec.template"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
copy_repo_relative_to_dir,
filter_files,
gen_file_from_template,
get_podspec_values,
load_json_config,
)

Expand Down Expand Up @@ -147,12 +148,14 @@ def assemble_objc_pod_package(
def path_patterns_as_variable_value(patterns: list[str]):
return ", ".join([f'"{pattern}"' for pattern in patterns])

(ios_deployment_target, macos_deployment_target, _) = get_podspec_values(framework_info)

variable_substitutions = {
"C_POD_NAME": c_pod_config["name"],
"DESCRIPTION": pod_config["description"],
"INCLUDE_DIR_LIST": path_patterns_as_variable_value(include_dirs),
"IOS_DEPLOYMENT_TARGET": framework_info["iphonesimulator"]["APPLE_DEPLOYMENT_TARGET"],
"MACOSX_DEPLOYMENT_TARGET": framework_info.get("macosx", {}).get("APPLE_DEPLOYMENT_TARGET", ""),
"IOS_DEPLOYMENT_TARGET": ios_deployment_target,
"MACOSX_DEPLOYMENT_TARGET": macos_deployment_target,
"LICENSE_FILE": license_file,
"NAME": pod_name,
"PUBLIC_HEADER_FILE_LIST": path_patterns_as_variable_value(pod_files["public_header_files"]),
Expand Down
38 changes: 38 additions & 0 deletions tools/ci_build/github/apple/package_assembly_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,44 @@ def load_json_config(json_config_file: pathlib.Path):
return json.load(config)


def get_podspec_values(framework_info):
"""
Get the podspec deployement targets and weak framework info from the dictionary that load_json_config returned.
Looks for iphonesimulator, iphoneos and macos settings.
Handles missing platforms and checks consistency.
Returns empty string for deployment target if that platofrm is not enabled.
:return (ios_deployment_target, macos_deployment_target, weak_framework)
"""
ios_deployment_target = ""
macos_deployment_target = ""
weak_framework = "" # should be the same for all platforms
# get info, allowing for a subset of platforms to be specified
for framework in ("iphonesimulator", "iphoneos", "macosx"):
if framework not in framework_info:
continue

target = framework_info[framework]["APPLE_DEPLOYMENT_TARGET"]
weak = framework_info[framework]["WEAK_FRAMEWORK"]

if not weak_framework:
weak_framework = weak
else:
# should be consistent
assert weak == weak_framework

if framework == "macosx":
macos_deployment_target = target
else:
if not ios_deployment_target:
ios_deployment_target = target
else:
# should be consistent
assert ios_deployment_target == target

return (ios_deployment_target, macos_deployment_target, weak_framework)


def get_ort_version():
"""
Gets the ONNX Runtime version string from the repo.
Expand Down
5 changes: 3 additions & 2 deletions tools/ci_build/github/apple/test_apple_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ def _test_apple_packages(args):

# create a zip file contains the framework
zip_file_path = local_pods_dir / f"{pod_name}.zip"
# shutil.make_archive require target file as full path without extension
shutil.make_archive(zip_file_path.with_suffix(""), "zip", root_dir=local_pods_dir)

# shutil.make_archive doesn't preserve symlinks. we know this is running on macOS so use zip
subprocess.run(["zip", "-r", "-y", str(zip_file_path), "."], cwd=local_pods_dir, check=True)

# update the podspec to point to the local framework zip file
with open(podspec) as file:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ stages:
cp -R $(Build.BinariesDirectory)/ios_framework/framework_out/onnxruntime.xcframework \
$(Build.BinariesDirectory)/artifacts_staging/onnxruntime-ios-xcframework-$(OnnxRuntimeVersion)
pushd $(Build.BinariesDirectory)/artifacts_staging
zip -vr $(Build.BinariesDirectory)/artifacts/onnxruntime_xcframework.zip \
zip -vry $(Build.BinariesDirectory)/artifacts/onnxruntime_xcframework.zip \
onnxruntime-ios-xcframework-$(OnnxRuntimeVersion)
popd
displayName: "Build Apple xcframework"
Expand Down

0 comments on commit b61a7c9

Please sign in to comment.