diff --git a/cmake/onnxruntime_objectivec.cmake b/cmake/onnxruntime_objectivec.cmake index ecc504dacb..810fc3b523 100644 --- a/cmake/onnxruntime_objectivec.cmake +++ b/cmake/onnxruntime_objectivec.cmake @@ -42,15 +42,8 @@ set(OBJC_ROOT "${REPO_ROOT}/objectivec") # onnxruntime_objc target # these headers are the public interface -# explicitly list them here so it is easy to see what is included -set(onnxruntime_objc_headers - "${OBJC_ROOT}/include/onnxruntime.h" - "${OBJC_ROOT}/include/ort_coreml_execution_provider.h" - "${OBJC_ROOT}/include/ort_enums.h" - "${OBJC_ROOT}/include/ort_env.h" - "${OBJC_ROOT}/include/ort_session.h" - "${OBJC_ROOT}/include/ort_value.h" - ) +file(GLOB onnxruntime_objc_headers CONFIGURE_DEPENDS + "${OBJC_ROOT}/include/*.h") file(GLOB onnxruntime_objc_srcs CONFIGURE_DEPENDS "${OBJC_ROOT}/src/*.h" diff --git a/objectivec/include/ort_coreml_execution_provider.h b/objectivec/include/ort_coreml_execution_provider.h index 6e17bbb093..bdde5814f3 100644 --- a/objectivec/include/ort_coreml_execution_provider.h +++ b/objectivec/include/ort_coreml_execution_provider.h @@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN /** * Gets whether the CoreML execution provider is available. */ -BOOL ORTIsCoreMLExecutionProviderAvailable(); +BOOL ORTIsCoreMLExecutionProviderAvailable(void); /** * Options for configuring the CoreML execution provider. diff --git a/tools/ci_build/github/apple/objectivec/assemble_pod_package.py b/tools/ci_build/github/apple/objectivec/assemble_pod_package.py new file mode 100755 index 0000000000..7543df0b82 --- /dev/null +++ b/tools/ci_build/github/apple/objectivec/assemble_pod_package.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 + +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import argparse +import os +import pathlib +import re +import shutil +import sys + + +_script_dir = pathlib.Path(__file__).parent.resolve(strict=True) +_repo_root = _script_dir.parents[4] + +# these variables contain paths or path patterns that are relative to the repo root + +# the license file +license_file = "LICENSE" + +# include directories for compiling the pod itself +include_dirs = [ + "objectivec", + "cmake/external/SafeInt", +] + +# pod source files +source_files = [ + "objectivec/include/*.h", + "objectivec/src/*.h", + "objectivec/src/*.m", + "objectivec/src/*.mm", + "cmake/external/SafeInt/safeint/SafeInt.hpp", +] + +# pod public header files +# note: these are a subset of source_files +public_header_files = [ + "objectivec/include/*.h", +] + +# pod test source files +test_source_files = [ + "objectivec/test/*.h", + "objectivec/test/*.m", + "objectivec/test/*.mm", +] + +# pod test resource files +test_resource_files = [ + "objectivec/test/testdata/*.ort", +] + + +def parse_args(): + parser = argparse.ArgumentParser(description=""" + Assembles the files for the Objective-C pod package in a staging directory. + This directory can be validated (e.g., with `pod lib lint`) and then zipped to create a package for release. + """) + + parser.add_argument("--staging-dir", type=pathlib.Path, + default=pathlib.Path("./onnxruntime-mobile-objc-staging"), + help="Staging directory for the Objective-C pod files.") + parser.add_argument("--pod-version", required=True, + help="Objective-C pod version.") + parser.add_argument("--pod-source-http", required=True, + help="Objective-C pod source http value (e.g., the package download URL).") + + return parser.parse_args() + + +_template_variable_pattern = re.compile(r"@(\w+)@") # match "@var@" + + +def gen_file_from_template(template_file: pathlib.Path, output_file: pathlib.Path, + variable_substitutions: dict[str, str]): + ''' + Generates a file from a template file. + The template file may contain template variables that will be substituted + with the provided values in the generated output file. + In the template file, template variable names are delimited by "@"'s, + e.g., "@var@". + + :param template_file The template file path. + :param output_file The generated output file path. + :variable_substitutions The mapping from template variable name to value. + ''' + with open(template_file, mode="r") as template: + content = template.read() + + def replace_template_variable(match): + variable_name = match.group(1) + return variable_substitutions.get(variable_name, match.group(0)) + + content = _template_variable_pattern.sub(replace_template_variable, content) + + with open(output_file, mode="w") as output: + output.write(content) + + +def copy_to_staging_dir(patterns: list[str], staging_dir: pathlib.Path): + ''' + Copies files to a staging directory. + The files are relative to the repo root, and the repo root-relative + intermediate directory structure is maintained. + + :param patterns The paths or path patterns relative to the repo root. + :param staging_dir The staging directory. + ''' + paths = [path for pattern in patterns for path in _repo_root.glob(pattern)] + for path in paths: + repo_relative_path = path.relative_to(_repo_root) + dst_path = staging_dir / repo_relative_path + os.makedirs(dst_path.parent, exist_ok=True) + shutil.copy(path, dst_path) + + +def main(): + args = parse_args() + + staging_dir = args.staging_dir.resolve() + print(f"Assembling files in staging directory: {staging_dir}") + if staging_dir.exists(): + print("Warning: staging directory already exists", file=sys.stderr) + + # copy the necessary files to the staging directory + copy_to_staging_dir( + [license_file] + source_files + test_source_files + test_resource_files, + staging_dir) + + # generate the podspec file from the template + + def path_patterns_as_variable_value(patterns: list[str]): + return ", ".join([f'"{pattern}"' for pattern in patterns]) + + variable_substitutions = { + "VERSION": args.pod_version, + "SOURCE_HTTP": args.pod_source_http, + "LICENSE_FILE": path_patterns_as_variable_value([license_file]), + "INCLUDE_DIR_LIST": path_patterns_as_variable_value(include_dirs), + "PUBLIC_HEADER_FILE_LIST": path_patterns_as_variable_value(public_header_files), + "SOURCE_FILE_LIST": path_patterns_as_variable_value(source_files), + "TEST_SOURCE_FILE_LIST": path_patterns_as_variable_value(test_source_files), + "TEST_RESOURCE_FILE_LIST": path_patterns_as_variable_value(test_resource_files), + } + + podspec_template = _script_dir / "onnxruntime-mobile-objc.podspec.template" + podspec = staging_dir / "onnxruntime-mobile-objc.podspec" + + gen_file_from_template(podspec_template, podspec, variable_substitutions) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/ci_build/github/apple/objectivec/onnxruntime-mobile-objc.podspec.template b/tools/ci_build/github/apple/objectivec/onnxruntime-mobile-objc.podspec.template new file mode 100644 index 0000000000..a022129253 --- /dev/null +++ b/tools/ci_build/github/apple/objectivec/onnxruntime-mobile-objc.podspec.template @@ -0,0 +1,52 @@ +Pod::Spec.new do |s| + s.name = 'onnxruntime-mobile-objc' + s.version = '@VERSION@' + s.summary = 'ONNX Runtime Objective-C Pod' + + s.description = <<-DESC + Preview pod for the ONNX Runtime Objective-C API. + DESC + + s.homepage = 'https://github.com/microsoft/onnxruntime' + s.license = { :type => 'MIT', :file => @LICENSE_FILE@ } + s.author = { "ONNX Runtime" => "onnxruntime@microsoft.com" } + s.source = { :http => "@SOURCE_HTTP@" } + s.ios.deployment_target = '11.0' + s.preserve_paths = [ @LICENSE_FILE@ ] + s.default_subspec = "Core" + + s.subspec "Core" do |core| + core.dependency "onnxruntime-mobile-c", "#{s.version}" + core.requires_arc = true + core.compiler_flags = "-std=c++17", "-fobjc-arc-exceptions", "-Wall", "-Wextra", "-Werror" + + include_dirs = [ + @INCLUDE_DIR_LIST@ + ].map { |relative_include_dir| + '"${PODS_TARGET_SRCROOT}/' + relative_include_dir + '"' + } + + core.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => include_dirs.join(" "), + "EXCLUDED_ARCHS[sdk=iphonesimulator*]": "arm64", + } + + core.public_header_files = [ + @PUBLIC_HEADER_FILE_LIST@ + ] + + core.source_files = [ + @SOURCE_FILE_LIST@ + ] + + core.test_spec "Tests" do |test| + test.source_files = [ + @TEST_SOURCE_FILE_LIST@ + ] + + test.resources = [ + @TEST_RESOURCE_FILE_LIST@ + ] + end + end +end