Initial Objective-C API (#7366)

Initial implementation of an Objective-C API.
This commit is contained in:
Edward Chen 2021-04-27 10:06:30 -07:00 committed by GitHub
parent 78e583d08c
commit d21304ceb0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 1131 additions and 33 deletions

View file

@ -65,6 +65,7 @@ option(onnxruntime_MSVC_STATIC_RUNTIME "Compile for the static CRT" OFF)
option(onnxruntime_GCC_STATIC_CPP_RUNTIME "Compile for the static libstdc++" OFF)
option(onnxruntime_BUILD_UNIT_TESTS "Build ONNXRuntime unit tests" ON)
option(onnxruntime_BUILD_CSHARP "Build C# library" OFF)
option(onnxruntime_BUILD_OBJC "Build Objective-C library" OFF)
option(onnxruntime_USE_PREINSTALLED_EIGEN "Use pre-installed EIGEN. Need to provide eigen_SOURCE_PATH if turn this on." OFF)
option(onnxruntime_BUILD_BENCHMARKS "Build ONNXRuntime micro-benchmarks" OFF)
@ -1574,6 +1575,11 @@ if (onnxruntime_ENABLE_PYTHON)
include(onnxruntime_python.cmake)
endif()
if (onnxruntime_BUILD_OBJC)
message(STATUS "Objective-C Build is enabled")
include(onnxruntime_objectivec.cmake)
endif()
if (onnxruntime_BUILD_UNIT_TESTS)
include(onnxruntime_unittests.cmake)
endif()

View file

@ -79,7 +79,6 @@ endif()
add_dependencies(onnxruntime onnxruntime_generate_def ${onnxruntime_EXTERNAL_DEPENDENCIES})
target_include_directories(onnxruntime PRIVATE ${ONNXRUNTIME_ROOT})
onnxruntime_add_include_to_target(onnxruntime)
target_compile_definitions(onnxruntime PRIVATE VER_MAJOR=${VERSION_MAJOR_PART})
target_compile_definitions(onnxruntime PRIVATE VER_MINOR=${VERSION_MINOR_PART})

View file

@ -119,10 +119,9 @@ target_include_directories(onnxruntime_common
PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${ONNXRUNTIME_ROOT} ${eigen_INCLUDE_DIRS}
# propagate include directories of dependencies that are part of public interface
PUBLIC
$<TARGET_PROPERTY:safeint_interface,INTERFACE_INCLUDE_DIRECTORIES>
${OPTIONAL_LITE_INCLUDE_DIR})
target_link_libraries(onnxruntime_common Boost::mp11)
target_link_libraries(onnxruntime_common safeint_interface Boost::mp11)
if(NOT WIN32)
target_include_directories(onnxruntime_common PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/external/nsync/public")

View file

@ -0,0 +1,124 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
if(${CMAKE_VERSION} VERSION_LESS "3.18")
message(FATAL_ERROR "CMake 3.18+ is required when building the Objective-C API.")
endif()
check_language(OBJC)
if(CMAKE_OBJC_COMPILER)
enable_language(OBJC)
else()
message(FATAL_ERROR "Objective-C is not supported.")
endif()
check_language(OBJCXX)
if(CMAKE_OBJCXX_COMPILER)
enable_language(OBJCXX)
else()
message(FATAL_ERROR "Objective-C++ is not supported.")
endif()
add_compile_options(
"$<$<COMPILE_LANGUAGE:OBJC,OBJCXX>:-Wall>"
"$<$<COMPILE_LANGUAGE:OBJC,OBJCXX>:-Wextra>")
if(onnxruntime_DEV_MODE)
add_compile_options(
"$<$<COMPILE_LANGUAGE:OBJC,OBJCXX>:-Werror>")
endif()
set(OBJC_ROOT "${REPO_ROOT}/objectivec")
set(OBJC_ARC_COMPILE_OPTIONS "-fobjc-arc" "-fobjc-arc-exceptions")
# 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/onnxruntime/ort_env.h"
"${OBJC_ROOT}/include/onnxruntime/ort_session.h"
"${OBJC_ROOT}/include/onnxruntime/ort_value.h")
file(GLOB onnxruntime_objc_srcs
"${OBJC_ROOT}/src/*.h"
"${OBJC_ROOT}/src/*.m"
"${OBJC_ROOT}/src/*.mm")
# files common to implementation and test targets
set(onnxruntime_objc_common_srcs
"${OBJC_ROOT}/common/assert_arc_enabled.mm")
source_group(TREE "${OBJC_ROOT}" FILES
${onnxruntime_objc_headers}
${onnxruntime_objc_srcs}
${onnxruntime_objc_common_srcs})
add_library(onnxruntime_objc SHARED
${onnxruntime_objc_headers}
${onnxruntime_objc_srcs}
${onnxruntime_objc_common_srcs})
target_include_directories(onnxruntime_objc
PUBLIC
"${OBJC_ROOT}/include"
PRIVATE
"${ONNXRUNTIME_ROOT}"
"${OBJC_ROOT}")
find_library(FOUNDATION_LIB Foundation REQUIRED)
target_link_libraries(onnxruntime_objc
PRIVATE
onnxruntime
safeint_interface
${FOUNDATION_LIB})
target_compile_options(onnxruntime_objc PRIVATE ${OBJC_ARC_COMPILE_OPTIONS})
set_target_properties(onnxruntime_objc PROPERTIES
FRAMEWORK TRUE
VERSION "1.0.0"
SOVERSION "1.0.0"
FRAMEWORK_VERSION "A"
PUBLIC_HEADER "${onnxruntime_objc_headers}"
FOLDER "ONNXRuntime"
CXX_STANDARD 17) # TODO remove when everything else moves to 17
if(onnxruntime_BUILD_UNIT_TESTS)
find_package(XCTest REQUIRED)
# onnxruntime_test_objc target
file(GLOB onnxruntime_objc_test_srcs
"${OBJC_ROOT}/test/*.h"
"${OBJC_ROOT}/test/*.m"
"${OBJC_ROOT}/test/*.mm")
source_group(TREE "${OBJC_ROOT}" FILES ${onnxruntime_objc_test_srcs})
xctest_add_bundle(onnxruntime_objc_test onnxruntime_objc
${onnxruntime_objc_headers}
${onnxruntime_objc_test_srcs}
${onnxruntime_objc_common_srcs})
target_include_directories(onnxruntime_objc_test
PRIVATE
"${OBJC_ROOT}")
target_compile_options(onnxruntime_objc_test PRIVATE ${OBJC_ARC_COMPILE_OPTIONS})
set_target_properties(onnxruntime_objc_test PROPERTIES
FOLDER "ONNXRuntimeTest")
add_custom_command(TARGET onnxruntime_objc_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${OBJC_ROOT}/test/testdata"
"$<TARGET_BUNDLE_CONTENT_DIR:onnxruntime_objc_test>/Resources/testdata")
xctest_add_test(XCTest.onnxruntime_objc_test onnxruntime_objc_test)
set_property(TEST XCTest.onnxruntime_objc_test APPEND PROPERTY
ENVIRONMENT "DYLD_LIBRARY_PATH=$<TARGET_FILE_DIR:onnxruntime>")
endif()

View file

@ -1041,7 +1041,7 @@ if (onnxruntime_USE_ROCM)
endif()
# During transition to separate hipFFT repo, put hipfft/include early
target_include_directories(onnxruntime_providers_rocm PRIVATE ${onnxruntime_ROCM_HOME}/hipfft/include ${onnxruntime_ROCM_HOME}/include ${onnxruntime_ROCM_HOME}/hipcub/include ${onnxruntime_ROCM_HOME}/hiprand/include ${onnxruntime_ROCM_HOME}/rocrand/include)
target_include_directories(onnxruntime_providers_rocm PRIVATE ${ONNXRUNTIME_ROOT} ${CMAKE_CURRENT_BINARY_DIR}/amdgpu/onnxruntime ${MPI_INCLUDE_DIRS} ${SAFEINT_INCLUDE_DIR} ${ONNXRUNTIME_ROOT}/../cmake/external/eigen)
target_include_directories(onnxruntime_providers_rocm PRIVATE ${ONNXRUNTIME_ROOT} ${CMAKE_CURRENT_BINARY_DIR}/amdgpu/onnxruntime ${MPI_INCLUDE_DIRS} ${ONNXRUNTIME_ROOT}/../cmake/external/eigen)
if (onnxruntime_ENABLE_TRAINING)
target_include_directories(onnxruntime_providers_rocm PRIVATE ${ORTTRAINING_ROOT} ${CMAKE_CURRENT_BINARY_DIR}/amdgpu/orttraining)

View file

@ -70,3 +70,8 @@ The [autopep8](https://pypi.org/project/autopep8/) tool can be used to automatic
Editors such as PyCharm [(see here)](https://www.jetbrains.com/help/pycharm/code-inspection.html) and Visual Studio Code [(see here)](https://code.visualstudio.com/docs/python/linting#_flake8) can be configured to check for PEP8 issues.
## Objective-C/C++ Code Style
Please follow the [Google Objective-C/C++ Style Guide](https://google.github.io/styleguide/objcguide.html).
Clang-format can be used to format Objective-C/C++ code. The .clang-format file is in the repository root directory.

View file

@ -157,7 +157,7 @@ ORT_RUNTIME_CLASS(Env);
ORT_RUNTIME_CLASS(Status); // nullptr for Status* indicates success
ORT_RUNTIME_CLASS(MemoryInfo);
ORT_RUNTIME_CLASS(IoBinding);
ORT_RUNTIME_CLASS(Session); //Don't call OrtReleaseSession from Dllmain (because session owns a thread pool)
ORT_RUNTIME_CLASS(Session); //Don't call ReleaseSession from Dllmain (because session owns a thread pool)
ORT_RUNTIME_CLASS(Value);
ORT_RUNTIME_CLASS(RunOptions);
ORT_RUNTIME_CLASS(TypeInfo);
@ -343,12 +343,12 @@ struct OrtApi {
const char*(ORT_API_CALL* GetErrorMessage)(_In_ const OrtStatus* status)NO_EXCEPTION ORT_ALL_ARGS_NONNULL;
/**
* \param out Should be freed by `OrtReleaseEnv` after use
* \param out Should be freed by `ReleaseEnv` after use
*/
ORT_API2_STATUS(CreateEnv, OrtLoggingLevel logging_level, _In_ const char* logid, _Outptr_ OrtEnv** out);
/**
* \param out Should be freed by `OrtReleaseEnv` after use
* \param out Should be freed by `ReleaseEnv` after use
*/
ORT_API2_STATUS(CreateEnvWithCustomLogger, OrtLoggingFunction logging_function, _In_opt_ void* logger_param,
OrtLoggingLevel logging_level, _In_ const char* logid, _Outptr_ OrtEnv** out);
@ -375,7 +375,7 @@ struct OrtApi {
_Inout_updates_all_(output_names_len) OrtValue** output);
/**
* \return A pointer of the newly created object. The pointer should be freed by OrtReleaseSessionOptions after use
* \return A pointer of the newly created object. The pointer should be freed by ReleaseSessionOptions after use
*/
ORT_API2_STATUS(CreateSessionOptions, _Outptr_ OrtSessionOptions** options);
@ -432,7 +432,7 @@ struct OrtApi {
ORT_API2_STATUS(SetInterOpNumThreads, _Inout_ OrtSessionOptions* options, int inter_op_num_threads);
/*
Create a custom op domain. After all sessions using it are released, call OrtReleaseCustomOpDomain
Create a custom op domain. After all sessions using it are released, call ReleaseCustomOpDomain
*/
ORT_API2_STATUS(CreateCustomOpDomain, _In_ const char* domain, _Outptr_ OrtCustomOpDomain** out);
@ -474,18 +474,18 @@ struct OrtApi {
ORT_API2_STATUS(SessionGetOverridableInitializerCount, _In_ const OrtSession* sess, _Out_ size_t* out);
/**
* \param out should be freed by OrtReleaseTypeInfo after use
* \param out should be freed by ReleaseTypeInfo after use
*/
ORT_API2_STATUS(SessionGetInputTypeInfo, _In_ const OrtSession* sess, size_t index, _Outptr_ OrtTypeInfo** type_info);
/**
* \param out should be freed by OrtReleaseTypeInfo after use
* \param out should be freed by ReleaseTypeInfo after use
*/
ORT_API2_STATUS(SessionGetOutputTypeInfo, _In_ const OrtSession* sess, size_t index,
_Outptr_ OrtTypeInfo** type_info);
/**
* \param out should be freed by OrtReleaseTypeInfo after use
* \param out should be freed by ReleaseTypeInfo after use
*/
ORT_API2_STATUS(SessionGetOverridableInitializerTypeInfo, _In_ const OrtSession* sess, size_t index,
_Outptr_ OrtTypeInfo** type_info);
@ -501,7 +501,7 @@ struct OrtApi {
_Inout_ OrtAllocator* allocator, _Outptr_ char** value);
/**
* \return A pointer to the newly created object. The pointer should be freed by OrtReleaseRunOptions after use
* \return A pointer to the newly created object. The pointer should be freed by ReleaseRunOptions after use
*/
ORT_API2_STATUS(CreateRunOptions, _Outptr_ OrtRunOptions** out);
@ -520,8 +520,8 @@ struct OrtApi {
ORT_API2_STATUS(RunOptionsUnsetTerminate, _Inout_ OrtRunOptions* options);
/**
* Create a tensor from an allocator. OrtReleaseValue will also release the buffer inside the output value
* \param out Should be freed by calling OrtReleaseValue
* Create a tensor from an allocator. ReleaseValue will also release the buffer inside the output value
* \param out Should be freed by calling ReleaseValue
* \param type must be one of TENSOR_ELEMENT_DATA_TYPE_xxxx
*/
ORT_API2_STATUS(CreateTensorAsOrtValue, _Inout_ OrtAllocator* allocator, _In_ const int64_t* shape, size_t shape_len,
@ -529,8 +529,8 @@ struct OrtApi {
/**
* Create a tensor with user's buffer. You can fill the buffer either before calling this function or after.
* p_data is owned by caller. OrtReleaseValue won't release p_data.
* \param out Should be freed by calling OrtReleaseValue
* p_data is owned by caller. ReleaseValue won't release p_data.
* \param out Should be freed by calling ReleaseValue
*/
ORT_API2_STATUS(CreateTensorWithDataAsOrtValue, _In_ const OrtMemoryInfo* info, _Inout_ void* p_data,
size_t p_data_len, _In_ const int64_t* shape, size_t shape_len, ONNXTensorElementDataType type,
@ -578,7 +578,7 @@ struct OrtApi {
ORT_API2_STATUS(GetOnnxTypeFromTypeInfo, _In_ const OrtTypeInfo*, _Out_ enum ONNXType* out);
/**
* The 'out' value should be released by calling OrtReleaseTensorTypeAndShapeInfo
* The 'out' value should be released by calling ReleaseTensorTypeAndShapeInfo
*/
ORT_API2_STATUS(CreateTensorTypeAndShapeInfo, _Outptr_ OrtTensorTypeAndShapeInfo** out);
@ -611,14 +611,14 @@ struct OrtApi {
ORT_API2_STATUS(GetTensorShapeElementCount, _In_ const OrtTensorTypeAndShapeInfo* info, _Out_ size_t* out);
/**
* \param out Should be freed by OrtReleaseTensorTypeAndShapeInfo after use
* \param out Should be freed by ReleaseTensorTypeAndShapeInfo after use
*/
ORT_API2_STATUS(GetTensorTypeAndShape, _In_ const OrtValue* value, _Outptr_ OrtTensorTypeAndShapeInfo** out);
/**
* Get the type information of an OrtValue
* \param value
* \param out The returned value should be freed by OrtReleaseTypeInfo after use
* \param out The returned value should be freed by ReleaseTypeInfo after use
*/
ORT_API2_STATUS(GetTypeInfo, _In_ const OrtValue* value, _Outptr_result_maybenull_ OrtTypeInfo** out);
@ -793,7 +793,7 @@ struct OrtApi {
ORT_CLASS_RELEASE(Env);
ORT_CLASS_RELEASE(Status); // nullptr for Status* indicates success
ORT_CLASS_RELEASE(MemoryInfo);
ORT_CLASS_RELEASE(Session); //Don't call OrtReleaseSession from Dllmain (because session owns a thread pool)
ORT_CLASS_RELEASE(Session); //Don't call ReleaseSession from Dllmain (because session owns a thread pool)
ORT_CLASS_RELEASE(Value);
ORT_CLASS_RELEASE(RunOptions);
ORT_CLASS_RELEASE(TypeInfo);
@ -1156,7 +1156,7 @@ struct OrtApi {
* Use this in conjunction with DisablePerSessionThreads API or else the session will use
* its own thread pools.
*
* \param out should be freed by `OrtReleaseEnv` after use
* \param out should be freed by `ReleaseEnv` after use
*/
ORT_API2_STATUS(CreateEnvWithCustomLoggerAndGlobalThreadPools, OrtLoggingFunction logging_function, _In_opt_ void* logger_param, OrtLoggingLevel logging_level,
_In_ const char* logid, _In_ const struct OrtThreadingOptions* tp_options, _Outptr_ OrtEnv** out);

View file

@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
static_assert(__has_feature(objc_arc), "Objective-C ARC must be enabled.");

10
objectivec/format_objc.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
# formats Objective-C/C++ code
set -e
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
clang-format -i $(find ${SCRIPT_DIR} -name "*.h" -o -name "*.m" -o -name "*.mm")

View file

@ -0,0 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// this header contains the entire ONNX Runtime Objective-C API
// the headers below can also be imported individually
#import "onnxruntime/ort_env.h"
#import "onnxruntime/ort_session.h"
#import "onnxruntime/ort_value.h"

View file

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* The ORT environment.
*/
@interface ORTEnv : NSObject
- (nullable instancetype)init NS_UNAVAILABLE;
/**
* Creates an ORT Environment.
*
* @param[out] error Optional error information set if an error occurs.
* @return The instance, or nil if an error occurs.
*/
- (nullable instancetype)initWithError:(NSError**)error NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class ORTEnv;
@class ORTValue;
/**
* An ORT session loads and runs a model.
*/
@interface ORTSession : NSObject
- (nullable instancetype)init NS_UNAVAILABLE;
/**
* Creates an ORT Session.
*
* @param env The ORT Environment instance.
* @param path The path to the ONNX model.
* @param[out] error Optional error information set if an error occurs.
* @return The instance, or nil if an error occurs.
*/
- (nullable instancetype)initWithEnv:(ORTEnv*)env
modelPath:(NSString*)path
error:(NSError**)error NS_DESIGNATED_INITIALIZER;
/**
* Runs the model.
* The inputs and outputs are pre-allocated.
*
* @param inputs Dictionary of input names to input ORT values.
* @param outputs Dictionary of output names to output ORT values.
* @param[out] error Optional error information set if an error occurs.
* @return Whether the model was run successfully.
*/
- (BOOL)runWithInputs:(NSDictionary<NSString*, ORTValue*>*)inputs
outputs:(NSDictionary<NSString*, ORTValue*>*)outputs
error:(NSError**)error;
/**
* Runs the model.
* The inputs are pre-allocated and the outputs are allocated by ORT.
*
* @param inputs Dictionary of input names to input ORT values.
* @param outputNames Set of output names.
* @param[out] error Optional error information set if an error occurs.
* @return A dictionary of output names to output ORT values with the outputs
* requested in `outputNames`, or nil if an error occurs.
*/
- (nullable NSDictionary<NSString*, ORTValue*>*)runWithInputs:(NSDictionary<NSString*, ORTValue*>*)inputs
outputNames:(NSSet<NSString*>*)outputNames
error:(NSError**)error;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,88 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* The supported ORT value types.
*/
typedef NS_ENUM(int32_t, ORTValueType) {
ORTValueTypeUnknown,
ORTValueTypeTensor,
};
/**
* The supported ORT tensor element data types.
*/
typedef NS_ENUM(int32_t, ORTTensorElementDataType) {
ORTTensorElementDataTypeUndefined,
ORTTensorElementDataTypeFloat,
ORTTensorElementDataTypeInt32,
};
/**
* An ORT value encapsulates data used as an input or output to a model at runtime.
*/
@interface ORTValue : NSObject
- (nullable instancetype)init NS_UNAVAILABLE;
/**
* Creates a value that is a tensor.
* The tensor data is allocated by the caller.
*
* @param data The tensor data.
* @param type The tensor data element type.
* @param shape The tensor shape.
* @param[out] error Optional error information set if an error occurs.
* @return The instance, or nil if an error occurs.
*/
- (nullable instancetype)initTensorWithData:(NSMutableData*)tensorData
elementType:(ORTTensorElementDataType)elementType
shape:(NSArray<NSNumber*>*)shape
error:(NSError**)error;
/**
* Gets the value type.
*
* @param[out] valueType The type of the value.
* @param[out] error Optional error information set if an error occurs.
* @return Whether the value type was retrieved successfully.
*/
- (BOOL)valueType:(ORTValueType*)valueType
error:(NSError**)error;
/**
* Gets the tensor data element type.
* This assumes that the value is a tensor.
*
* @param[out] elementType The type of the tensor's data elements.
* @param[out] error Optional error information set if an error occurs.
* @return Whether the tensor data element type was retrieved successfully.
*/
- (BOOL)tensorElementType:(ORTTensorElementDataType*)elementType
error:(NSError**)error;
/**
* Gets the tensor shape.
* This assumes that the value is a tensor.
*
* @param[out] error Optional error information set if an error occurs.
* @return The tensor shape, or nil if an error occurs.
*/
- (nullable NSArray<NSNumber*>*)tensorShapeWithError:(NSError**)error;
/**
* Gets the tensor data.
* This assumes that the value is a tensor.
*
* @param[out] error Optional error information set if an error occurs.
* @return The tensor data, or nil if an error occurs.
*/
- (nullable NSMutableData*)tensorDataWithError:(NSError**)error;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#include "core/session/onnxruntime_cxx_api.h"
NS_ASSUME_NONNULL_BEGIN
void ORTSaveCodeAndDescriptionToError(int code, const char* description, NSError** error);
void ORTSaveExceptionToError(const Ort::Exception& e, NSError** error);
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "src/error_utils.h"
NS_ASSUME_NONNULL_BEGIN
static NSString* const kOrtErrorDomain = @"onnxruntime";
void ORTSaveCodeAndDescriptionToError(int code, const char* descriptionCstr, NSError** error) {
if (!error) return;
NSString* description = [NSString stringWithCString:descriptionCstr
encoding:NSASCIIStringEncoding];
*error = [NSError errorWithDomain:kOrtErrorDomain
code:code
userInfo:@{NSLocalizedDescriptionKey : description}];
}
void ORTSaveExceptionToError(const Ort::Exception& e, NSError** error) {
ORTSaveCodeAndDescriptionToError(e.GetOrtErrorCode(), e.what(), error);
}
NS_ASSUME_NONNULL_END

37
objectivec/src/ort_env.mm Normal file
View file

@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "src/ort_env_internal.h"
#include <optional>
#include "core/session/onnxruntime_cxx_api.h"
#import "src/error_utils.h"
NS_ASSUME_NONNULL_BEGIN
@implementation ORTEnv {
std::optional<Ort::Env> _env;
}
- (nullable instancetype)initWithError:(NSError**)error {
self = [super init];
if (self) {
try {
_env = Ort::Env{};
} catch (const Ort::Exception& e) {
ORTSaveExceptionToError(e, error);
self = nil;
}
}
return self;
}
- (Ort::Env&)CXXAPIOrtEnv {
return *_env;
}
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "onnxruntime/ort_env.h"
#include "core/session/onnxruntime_cxx_api.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORTEnv ()
- (Ort::Env&)CXXAPIOrtEnv;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,118 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "onnxruntime/ort_session.h"
#include <optional>
#include <vector>
#include "core/session/onnxruntime_cxx_api.h"
#import "src/error_utils.h"
#import "src/ort_env_internal.h"
#import "src/ort_value_internal.h"
NS_ASSUME_NONNULL_BEGIN
@implementation ORTSession {
std::optional<Ort::Session> _session;
}
- (nullable instancetype)initWithEnv:(ORTEnv*)env
modelPath:(NSString*)path
error:(NSError**)error {
self = [super init];
if (self) {
try {
Ort::SessionOptions sessionOptions{}; // TODO make configurable
_session = Ort::Session{[env CXXAPIOrtEnv], path.UTF8String, sessionOptions};
} catch (const Ort::Exception& e) {
ORTSaveExceptionToError(e, error);
self = nil;
}
}
return self;
}
- (BOOL)runWithInputs:(NSDictionary<NSString*, ORTValue*>*)inputs
outputs:(NSDictionary<NSString*, ORTValue*>*)outputs
error:(NSError**)error {
BOOL status = NO;
try {
Ort::RunOptions runOptions{}; // TODO make configurable
std::vector<const char*> inputNames, outputNames;
std::vector<const OrtValue*> inputValues;
std::vector<OrtValue*> outputValues;
for (NSString* inputName in inputs) {
inputNames.push_back(inputName.UTF8String);
inputValues.push_back(static_cast<const OrtValue*>([inputs[inputName] CXXAPIOrtValue]));
}
for (NSString* outputName in outputs) {
outputNames.push_back(outputName.UTF8String);
outputValues.push_back(static_cast<OrtValue*>([outputs[outputName] CXXAPIOrtValue]));
}
Ort::ThrowOnError(Ort::GetApi().Run(*_session, runOptions,
inputNames.data(), inputValues.data(), inputNames.size(),
outputNames.data(), outputNames.size(), outputValues.data()));
status = YES;
} catch (const Ort::Exception& e) {
ORTSaveExceptionToError(e, error);
}
return status;
}
- (nullable NSDictionary<NSString*, ORTValue*>*)runWithInputs:(NSDictionary<NSString*, ORTValue*>*)inputs
outputNames:(NSSet<NSString*>*)outputNameSet
error:(NSError**)error {
try {
NSArray<NSString*>* outputNameArray = outputNameSet.allObjects;
Ort::RunOptions runOptions{}; // TODO make configurable
std::vector<const char*> inputNames, outputNames;
std::vector<const OrtValue*> inputValues;
std::vector<OrtValue*> outputValues;
for (NSString* inputName in inputs) {
inputNames.push_back(inputName.UTF8String);
inputValues.push_back(static_cast<const OrtValue*>([inputs[inputName] CXXAPIOrtValue]));
}
for (NSString* outputName in outputNameArray) {
outputNames.push_back(outputName.UTF8String);
outputValues.push_back(nullptr);
}
Ort::ThrowOnError(Ort::GetApi().Run(*_session, runOptions,
inputNames.data(), inputValues.data(), inputNames.size(),
outputNames.data(), outputNames.size(), outputValues.data()));
NSMutableDictionary<NSString*, ORTValue*>* outputs = [[NSMutableDictionary alloc] init];
for (NSUInteger i = 0; i < outputNameArray.count; ++i) {
ORTValue* outputValue = [[ORTValue alloc] initWithCAPIOrtValue:outputValues[i] externalTensorData:nil error:error];
if (!outputValue) {
// clean up remaining C API OrtValues which haven't been wrapped by an ORTValue yet
for (NSUInteger j = i; j < outputNameArray.count; ++j) {
Ort::GetApi().ReleaseValue(outputValues[j]);
}
return nil;
}
outputs[outputNameArray[i]] = outputValue;
}
return outputs;
} catch (const Ort::Exception& e) {
ORTSaveExceptionToError(e, error);
return nil;
}
}
@end
NS_ASSUME_NONNULL_END

215
objectivec/src/ort_value.mm Normal file
View file

@ -0,0 +1,215 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "src/ort_value_internal.h"
#include <algorithm>
#include <optional>
#include "safeint/SafeInt.hpp"
#include "core/session/onnxruntime_cxx_api.h"
#import "src/error_utils.h"
NS_ASSUME_NONNULL_BEGIN
namespace {
struct ValueTypeInfo {
ORTValueType type;
ONNXType capi_type;
};
// supported ORT value types
// define the mapping from ORTValueType to C API ONNXType here
constexpr ValueTypeInfo kValueTypeInfos[]{
{ORTValueTypeUnknown, ONNX_TYPE_UNKNOWN},
{ORTValueTypeTensor, ONNX_TYPE_TENSOR},
};
struct TensorElementTypeInfo {
ORTTensorElementDataType type;
ONNXTensorElementDataType capi_type;
size_t element_size;
};
// supported ORT tensor element data types
// define the mapping from ORTTensorElementDataType to C API
// ONNXTensorElementDataType here
constexpr TensorElementTypeInfo kElementTypeInfos[]{
{ORTTensorElementDataTypeUndefined, ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED, 0},
{ORTTensorElementDataTypeFloat, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, sizeof(float)},
{ORTTensorElementDataTypeInt32, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, sizeof(int32_t)},
};
ORTValueType CAPIToPublicValueType(ONNXType capi_type) {
const auto it = std::find_if(
std::begin(kValueTypeInfos), std::end(kValueTypeInfos),
[capi_type](const auto& type_info) { return type_info.capi_type == capi_type; });
if (it == std::end(kValueTypeInfos)) {
throw Ort::Exception{"unsupported value type", ORT_NOT_IMPLEMENTED};
}
return it->type;
}
ONNXTensorElementDataType PublicToCAPITensorElementType(ORTTensorElementDataType type) {
const auto it = std::find_if(
std::begin(kElementTypeInfos), std::end(kElementTypeInfos),
[type](const auto& type_info) { return type_info.type == type; });
if (it == std::end(kElementTypeInfos)) {
throw Ort::Exception{"unsupported tensor element type", ORT_NOT_IMPLEMENTED};
}
return it->capi_type;
}
ORTTensorElementDataType CAPIToPublicTensorElementType(ONNXTensorElementDataType capi_type) {
const auto it = std::find_if(
std::begin(kElementTypeInfos), std::end(kElementTypeInfos),
[capi_type](const auto& type_info) { return type_info.capi_type == capi_type; });
if (it == std::end(kElementTypeInfos)) {
throw Ort::Exception{"unsupported tensor element type", ORT_NOT_IMPLEMENTED};
}
return it->type;
}
size_t SizeOfCAPITensorElementType(ONNXTensorElementDataType capi_type) {
const auto it = std::find_if(
std::begin(kElementTypeInfos), std::end(kElementTypeInfos),
[capi_type](const auto& type_info) { return type_info.capi_type == capi_type; });
if (it == std::end(kElementTypeInfos)) {
throw Ort::Exception{"unsupported tensor element type", ORT_NOT_IMPLEMENTED};
}
return it->element_size;
}
}
@interface ORTValue ()
// pointer to any external tensor data to keep alive for the lifetime of the ORTValue
@property(nullable) NSMutableData* externalTensorData;
@end
@implementation ORTValue {
std::optional<Ort::Value> _value;
std::optional<Ort::TypeInfo> _typeInfo;
}
#pragma mark Public
- (nullable instancetype)initTensorWithData:(NSMutableData*)tensorData
elementType:(ORTTensorElementDataType)elementType
shape:(NSArray<NSNumber*>*)shape
error:(NSError**)error {
try {
const auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
const auto ONNXElementType = PublicToCAPITensorElementType(elementType);
const auto shapeVector = [shape]() {
std::vector<int64_t> result{};
result.reserve(shape.count);
for (NSNumber* dim in shape) {
result.push_back(dim.longLongValue);
}
return result;
}();
Ort::Value ortValue = Ort::Value::CreateTensor(
memoryInfo, tensorData.mutableBytes, tensorData.length,
shapeVector.data(), shapeVector.size(), ONNXElementType);
self = [self initWithCAPIOrtValue:ortValue.release()
externalTensorData:tensorData
error:error];
} catch (const Ort::Exception& e) {
ORTSaveExceptionToError(e, error);
self = nil;
}
return self;
}
- (BOOL)valueType:(ORTValueType*)valueType
error:(NSError**)error {
try {
const auto ortValueType = _typeInfo->GetONNXType();
*valueType = CAPIToPublicValueType(ortValueType);
return YES;
} catch (const Ort::Exception& e) {
ORTSaveExceptionToError(e, error);
return NO;
}
}
- (BOOL)tensorElementType:(ORTTensorElementDataType*)elementType
error:(NSError**)error {
try {
const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo();
const auto ortElementType = tensorTypeAndShapeInfo.GetElementType();
*elementType = CAPIToPublicTensorElementType(ortElementType);
return YES;
} catch (const Ort::Exception& e) {
ORTSaveExceptionToError(e, error);
return NO;
}
}
- (nullable NSArray<NSNumber*>*)tensorShapeWithError:(NSError**)error {
try {
const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo();
const std::vector<int64_t> shape = tensorTypeAndShapeInfo.GetShape();
NSMutableArray<NSNumber*>* shapeArray = [[NSMutableArray alloc] initWithCapacity:shape.size()];
for (size_t i = 0; i < shape.size(); ++i) {
shapeArray[i] = @(shape[i]);
}
return shapeArray;
} catch (const Ort::Exception& e) {
ORTSaveExceptionToError(e, error);
return nil;
}
}
- (nullable NSMutableData*)tensorDataWithError:(NSError**)error {
try {
const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo();
const size_t elementCount = tensorTypeAndShapeInfo.GetElementCount();
const size_t elementSize = SizeOfCAPITensorElementType(tensorTypeAndShapeInfo.GetElementType());
size_t rawDataLength;
if (!SafeMultiply(elementCount, elementSize, rawDataLength)) {
throw Ort::Exception{"failed to compute tensor data length", ORT_RUNTIME_EXCEPTION};
}
void* rawData;
Ort::ThrowOnError(Ort::GetApi().GetTensorMutableData(*_value, &rawData));
return [NSMutableData dataWithBytesNoCopy:rawData
length:rawDataLength
freeWhenDone:NO];
} catch (const Ort::Exception& e) {
ORTSaveExceptionToError(e, error);
return nil;
}
}
#pragma mark Internal
- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue
externalTensorData:(nullable NSMutableData*)externalTensorData
error:(NSError**)error {
self = [super init];
if (self) {
try {
_value = Ort::Value{CAPIOrtValue};
_typeInfo = _value->GetTypeInfo();
_externalTensorData = externalTensorData;
} catch (const Ort::Exception& e) {
ORTSaveExceptionToError(e, error);
self = nil;
}
}
return self;
}
- (Ort::Value&)CXXAPIOrtValue {
return *_value;
}
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "onnxruntime/ort_value.h"
#include "core/session/onnxruntime_cxx_api.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORTValue ()
- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue
externalTensorData:(nullable NSMutableData*)externalTensorData
error:(NSError**)error NS_DESIGNATED_INITIALIZER;
- (Ort::Value&)CXXAPIOrtValue;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <XCTest/XCTest.h>
#import "onnxruntime/ort_env.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORTEnvTest : XCTestCase
@end
@implementation ORTEnvTest
- (void)testInitOk {
NSError* err = nil;
ORTEnv* env = [[ORTEnv alloc] initWithError:&err];
XCTAssertNotNil(env);
XCTAssertNil(err);
}
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,162 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <XCTest/XCTest.h>
#import "onnxruntime/ort_env.h"
#import "onnxruntime/ort_session.h"
#import "onnxruntime/ort_value.h"
#include <vector>
NS_ASSUME_NONNULL_BEGIN
@interface ORTSessionTest : XCTestCase
@property(readonly, nullable) ORTEnv* ortEnv;
@end
@implementation ORTSessionTest
- (void)setUp {
[super setUp];
self.continueAfterFailure = NO;
_ortEnv = [[ORTEnv alloc] initWithError:nil];
XCTAssertNotNil(_ortEnv);
}
- (void)tearDown {
_ortEnv = nil;
[super tearDown];
}
+ (NSString*)getTestDataWithRelativePath:(NSString*)relativePath {
NSString* testDataDir = [NSString stringWithFormat:@"%@/Contents/Resources/testdata",
[[NSBundle bundleForClass:[ORTSessionTest class]] bundlePath]];
return [testDataDir stringByAppendingString:relativePath];
}
// model with an Add op
// inputs: A, B
// output: C = A + B
+ (NSString*)getAddModelPath {
return [ORTSessionTest getTestDataWithRelativePath:@"/single_add.onnx"];
}
+ (NSMutableData*)dataWithScalarFloat:(float)value {
NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value length:sizeof(value)];
return data;
}
+ (ORTValue*)ortValueWithScalarFloatData:(NSMutableData*)data {
NSArray<NSNumber*>* shape = @[ @1 ];
NSError* err = nil;
ORTValue* ort_value = [[ORTValue alloc] initTensorWithData:data
elementType:ORTTensorElementDataTypeFloat
shape:shape
error:&err];
XCTAssertNotNil(ort_value);
XCTAssertNil(err);
return ort_value;
}
- (void)testInitAndRunWithPreallocatedOutputOk {
NSMutableData* a_data = [ORTSessionTest dataWithScalarFloat:1.0f];
NSMutableData* b_data = [ORTSessionTest dataWithScalarFloat:2.0f];
NSMutableData* c_data = [ORTSessionTest dataWithScalarFloat:0.0f];
ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:a_data];
ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:b_data];
ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:c_data];
NSError* err = nil;
ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv
modelPath:[ORTSessionTest getAddModelPath]
error:&err];
XCTAssertNotNil(session);
XCTAssertNil(err);
BOOL run_result = [session runWithInputs:@{@"A" : a, @"B" : b}
outputs:@{@"C" : c}
error:&err];
XCTAssertTrue(run_result);
XCTAssertNil(err);
const float c_expected = 3.0f;
float c_actual;
memcpy(&c_actual, c_data.bytes, sizeof(float));
XCTAssertEqual(c_actual, c_expected);
}
- (void)testInitAndRunOk {
NSMutableData* a_data = [ORTSessionTest dataWithScalarFloat:1.0f];
NSMutableData* b_data = [ORTSessionTest dataWithScalarFloat:2.0f];
ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:a_data];
ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:b_data];
NSError* err = nil;
ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv
modelPath:[ORTSessionTest getAddModelPath]
error:&err];
XCTAssertNotNil(session);
XCTAssertNil(err);
NSDictionary<NSString*, ORTValue*>* outputs =
[session runWithInputs:@{@"A" : a, @"B" : b}
outputNames:[NSSet setWithArray:@[ @"C" ]]
error:&err];
XCTAssertNotNil(outputs);
XCTAssertNil(err);
ORTValue* c_output = outputs[@"C"];
XCTAssertNotNil(c_output);
NSData* c_data = [c_output tensorDataWithError:&err];
XCTAssertNotNil(c_data);
XCTAssertNil(err);
const float c_expected = 3.0f;
float c_actual;
memcpy(&c_actual, c_data.bytes, sizeof(float));
XCTAssertEqual(c_actual, c_expected);
}
- (void)testInitFailsWithInvalidPath {
NSString* invalid_model_path = [ORTSessionTest getTestDataWithRelativePath:@"/invalid/path/to/model.onnx"];
NSError* err = nil;
ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv
modelPath:invalid_model_path
error:&err];
XCTAssertNil(session);
XCTAssertNotNil(err);
}
- (void)testRunFailsWithInvalidInput {
NSMutableData* d_data = [ORTSessionTest dataWithScalarFloat:1.0f];
NSMutableData* c_data = [ORTSessionTest dataWithScalarFloat:0.0f];
ORTValue* d = [ORTSessionTest ortValueWithScalarFloatData:d_data];
ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:c_data];
NSError* err = nil;
ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv
modelPath:[ORTSessionTest getAddModelPath]
error:&err];
XCTAssertNotNil(session);
XCTAssertNil(err);
BOOL run_result = [session runWithInputs:@{@"D" : d}
outputs:@{@"C" : c}
error:&err];
XCTAssertFalse(run_result);
XCTAssertNotNil(err);
}
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <XCTest/XCTest.h>
#import "onnxruntime/ort_value.h"
#include <vector>
NS_ASSUME_NONNULL_BEGIN
@interface ORTValueTest : XCTestCase
@end
@implementation ORTValueTest
- (void)setUp {
[super setUp];
self.continueAfterFailure = NO;
}
- (void)testInitTensorOk {
int32_t value = 42;
NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value
length:sizeof(int32_t)];
NSArray<NSNumber*>* shape = @[ @1 ];
NSError* err = nil;
ORTValue* ortValue = [[ORTValue alloc] initTensorWithData:data
elementType:ORTTensorElementDataTypeInt32
shape:shape
error:&err];
XCTAssertNotNil(ortValue);
XCTAssertNil(err);
ORTValueType actualValueType;
XCTAssertTrue([ortValue valueType:&actualValueType error:&err]);
XCTAssertNil(err);
XCTAssertEqual(actualValueType, ORTValueTypeTensor);
ORTTensorElementDataType actualElementType;
XCTAssertTrue([ortValue tensorElementType:&actualElementType error:&err]);
XCTAssertNil(err);
XCTAssertEqual(actualElementType, ORTTensorElementDataTypeInt32);
NSArray<NSNumber*>* actualShape = [ortValue tensorShapeWithError:&err];
XCTAssertNotNil(actualShape);
XCTAssertNil(err);
XCTAssertEqualObjects(shape, actualShape);
NSData* actualData = [ortValue tensorDataWithError:&err];
XCTAssertNotNil(actualData);
XCTAssertNil(err);
XCTAssertEqual(actualData.length, sizeof(int32_t));
int32_t actualValue;
memcpy(&actualValue, actualData.bytes, sizeof(int32_t));
XCTAssertEqual(actualValue, value);
}
- (void)testInitTensorFailsWithDataSmallerThanShape {
std::vector<int32_t> values{1, 2, 3, 4};
NSMutableData* data = [[NSMutableData alloc] initWithBytes:values.data()
length:values.size() * sizeof(int32_t)];
NSArray<NSNumber*>* shape = @[ @2, @3 ]; // too large
NSError* err = nil;
ORTValue* ort_value = [[ORTValue alloc] initTensorWithData:data
elementType:ORTTensorElementDataTypeInt32
shape:shape
error:&err];
XCTAssertNil(ort_value);
XCTAssertNotNil(err);
}
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,16 @@
:S

A
BCAdd"Add SingleAddZ
A

Z
B

b
C

B

View file

@ -0,0 +1,19 @@
import onnx
from onnx import helper
from onnx import TensorProto
graph = helper.make_graph(
[ # nodes
helper.make_node("Add", ["A", "B"], ["C"], "Add"),
],
"SingleAdd", # name
[ # inputs
helper.make_tensor_value_info('A', TensorProto.FLOAT, [1]),
helper.make_tensor_value_info('B', TensorProto.FLOAT, [1]),
],
[ # outputs
helper.make_tensor_value_info('C', TensorProto.FLOAT, [1]),
])
model = helper.make_model(graph)
onnx.save(model, r'single_add.onnx')

View file

@ -1,19 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "core/session/onnxruntime_c_api.h"
#include "core/session/ort_apis.h"
#include "core/framework/tensor_shape.h"
#include "core/framework/tensor_type_and_shape.h"
#include <assert.h>
#include <atomic>
#include <stdexcept>
#include "core/common/safeint.h"
#include "core/framework/error_code_helper.h"
#include "core/framework/ml_value.h"
#include "core/framework/onnxruntime_typeinfo.h"
#include "core/framework/sparse_tensor.h"
#include "core/framework/tensor_type_and_shape.h"
#include "core/framework/tensor_shape.h"
#include "core/graph/onnx_protobuf.h"
#include "core/framework/error_code_helper.h"
#include <assert.h>
#include <stdexcept>
#include <atomic>
#include "core/session/onnxruntime_c_api.h"
#include "core/session/ort_apis.h"
using onnxruntime::BFloat16;
using onnxruntime::DataTypeImpl;
@ -72,8 +74,10 @@ ORT_API_STATUS_IMPL(OrtApis::GetSymbolicDimensions, _In_ const struct OrtTensorT
}
ORT_API_STATUS_IMPL(OrtApis::GetTensorShapeElementCount, _In_ const OrtTensorTypeAndShapeInfo* this_ptr, _Out_ size_t* out) {
*out = static_cast<size_t>(this_ptr->shape.Size());
API_IMPL_BEGIN
*out = SafeInt<size_t>{this_ptr->shape.Size()};
return nullptr;
API_IMPL_END
}
struct OrtValue;

View file

@ -2,6 +2,12 @@
// Licensed under the MIT License.
#pragma once
#include <string>
#include <vector>
#include "core/framework/tensor_shape.h"
#include "core/session/onnxruntime_c_api.h"
struct OrtTensorTypeAndShapeInfo {
public:
ONNXTensorElementDataType type = ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT;

View file

@ -243,6 +243,11 @@ def parse_arguments():
"--build_nodejs", action='store_true',
help="Build Node.js binding and NPM package.")
# Objective-C binding
parser.add_argument(
"--build_objc", action='store_true',
help="Build Objective-C binding.")
# Build a shared lib
parser.add_argument(
"--build_shared_lib", action='store_true',
@ -656,6 +661,7 @@ def generate_build_tree(cmake_path, source_dir, build_dir, cuda_home, cudnn_home
"-Donnxruntime_BUILD_CSHARP=" + ("ON" if args.build_csharp else "OFF"),
"-Donnxruntime_BUILD_JAVA=" + ("ON" if args.build_java else "OFF"),
"-Donnxruntime_BUILD_NODEJS=" + ("ON" if args.build_nodejs else "OFF"),
"-Donnxruntime_BUILD_OBJC=" + ("ON" if args.build_objc else "OFF"),
"-Donnxruntime_BUILD_SHARED_LIB=" + ("ON" if args.build_shared_lib else "OFF"),
"-Donnxruntime_BUILD_APPLE_FRAMEWORK=" + ("ON" if args.build_apple_framework else "OFF"),
"-Donnxruntime_USE_DNNL=" + ("ON" if args.use_dnnl else "OFF"),

View file

@ -2,7 +2,18 @@ jobs:
- template: templates/mac-ci.yml
parameters:
DoNugetPack: 'false'
BuildCommand: 'python3 $(Build.SourcesDirectory)/tools/ci_build/build.py --build_dir $(Build.BinariesDirectory) --build_wheel --skip_submodule_sync --parallel --build_shared_lib --build_java --build_nodejs --enable_language_interop_ops --config Debug'
BuildCommand: >-
python3 $(Build.SourcesDirectory)/tools/ci_build/build.py
--config Debug
--build_dir $(Build.BinariesDirectory)
--build_wheel
--skip_submodule_sync
--parallel
--build_shared_lib
--build_java
--build_nodejs
--build_objc
--enable_language_interop_ops
# Enable unreleased onnx opsets in CI builds
# This facilitates testing the implementation for the new opsets
AllowReleasedOpsetOnly: '0'