Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 79 additions & 28 deletions include/onnxruntime/core/session/onnxruntime_cxx_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,17 @@ struct Exception : std::exception {
throw Ort::Exception(string, code)
#endif

// This is used internally by the C++ API. This class holds the global variable that points to the OrtApi,
// it's in a template so that we can define a global variable in a header and make
// it transparent to the users of the API.
template <typename T>
struct Global {
static const OrtApi* api_;
};

// If macro ORT_API_MANUAL_INIT is defined, no static initialization will be performed. Instead, user must call InitApi() before using it.
template <typename T>
#ifdef ORT_API_MANUAL_INIT
const OrtApi* Global<T>::api_{};
inline void InitApi() noexcept { Global<void>::api_ = OrtGetApiBase()->GetApi(ORT_API_VERSION); }

// Used by custom operator libraries that are not linked to onnxruntime. Sets the global API object, which is
// required by C++ APIs.
// If macro ORT_API_MANUAL_INIT is defined, no static initialization will be
// performed. Instead, users must call InitApi() before using ORT.
//
// InitApi() sets the global API object using the default initialization
// logic. Users call this to initialize the ORT C++ APIs at a time that
// makes sense in their program.
inline void InitApi() noexcept;
Comment thread
chwarr marked this conversation as resolved.

// InitApi(const OrtApi*) is used by custom operator libraries that are not
// linked to onnxruntime. It sets the global API object, which is required
// by the ORT C++ APIs.
//
// Example mycustomop.cc:
//
Expand All @@ -107,22 +102,78 @@ inline void InitApi() noexcept { Global<void>::api_ = OrtGetApiBase()->GetApi(OR
// // ...
// }
//
inline void InitApi(const OrtApi* api) noexcept { Global<void>::api_ = api; }
#else
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(push)
// "Global initializer calls a non-constexpr function." Therefore you can't use ORT APIs in the other global initializers.
// Please define ORT_API_MANUAL_INIT if it conerns you.
#pragma warning(disable : 26426)
#endif
const OrtApi* Global<T>::api_ = OrtGetApiBase()->GetApi(ORT_API_VERSION);
#if defined(_MSC_VER) && !defined(__clang__)
#pragma warning(pop)
inline void InitApi(const OrtApi* api) noexcept;

namespace detail {
// This is used internally by the C++ API. This class holds the global
// variable that points to the OrtApi.
struct Global {
static const OrtApi* GetApi() noexcept {
if (!api_) {
api_ = DefaultInit();
}

return api_;
}

private:
inline static const OrtApi* api_ = nullptr;
Comment thread
chwarr marked this conversation as resolved.
Outdated

// Has different definitions based on ORT_API_MANUAL_INIT
static const OrtApi* DefaultInit() noexcept;

// Public APIs to set the OrtApi* to use.
friend void ::Ort::InitApi() noexcept;
friend void ::Ort::InitApi(const OrtApi*) noexcept;
};
} // namespace detail

#ifdef ORT_API_MANUAL_INIT

inline void InitApi(const OrtApi* api) noexcept { detail::Global::api_ = api; }
Comment thread
chwarr marked this conversation as resolved.
Outdated
inline void InitApi() noexcept { InitApi(OrtGetApiBase()->GetApi(ORT_API_VERSION)); }

#ifdef _MSC_VER
// If you get a linker error about a mismatch here, you are trying to
// link two compilation units that have different definitions for
// ORT_API_MANUAL_INIT together. All compilation units must agree on the
// definition of ORT_API_MANUAL_INIT.
#pragma detect_mismatch("ORT_API_MANUAL_INIT", "enabled")
#endif

inline const OrtApi* detail::Global::DefaultInit() noexcept {
// When ORT_API_MANUAL_INIT is defined, there's no default init that can
// be done.
return nullptr;
}

#else // ORT_API_MANUAL_INIT

#ifdef _MSC_VER
// If you get a linker error about a mismatch here, you are trying to link
// two compilation units that have different definitions for
// ORT_API_MANUAL_INIT together. All compilation units must agree on the
// definition of ORT_API_MANUAL_INIT.
#pragma detect_mismatch("ORT_API_MANUAL_INIT", "disabled")
#endif

inline const OrtApi* detail::Global::DefaultInit() noexcept {
// This block-level static will be initialized once when this function is
// first executed, delaying the call to OrtGetApiBase()->GetApi() until it
// is first needed. This helps avoid issues with static initialization
// order and dynamic libraries loading other dynamic libraries.
//
// This makes it safe to have a Ort::Env constructed as a static member.
//
// This DOES NOT make it safe to _use_ arbitrary ORT C++ APIs when
// initializaing static members, however.
Comment thread
chwarr marked this conversation as resolved.
Outdated
static const OrtApi* api = OrtGetApiBase()->GetApi(ORT_API_VERSION);
return api;
}
#endif // ORT_API_MANUAL_INIT

/// This returns a reference to the ORT C API.
inline const OrtApi& GetApi() noexcept { return *Global<void>::api_; }
inline const OrtApi& GetApi() noexcept { return *detail::Global::GetApi(); }

/// <summary>
/// This function returns the onnxruntime version string
Expand Down
2 changes: 1 addition & 1 deletion js/node/src/inference_session_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Napi::Object InferenceSessionWrap::Init(Napi::Env env, Napi::Object exports) {
// create ONNX runtime env
Ort::InitApi();
ORT_NAPI_THROW_ERROR_IF(
Ort::Global<void>::api_ == nullptr, env,
&Ort::GetApi() == nullptr, env,
"Failed to initialize ONNX Runtime API. It could happen when this nodejs binding was built with a higher version "
"ONNX Runtime but now runs with a lower version ONNX Runtime DLL(or shared library).");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ std::once_flag init;
} // namespace

void InitProviderOrtApi() {
std::call_once(init, []() { Ort::Global<void>::api_ = Provider_GetHost()->OrtGetApiBase()->GetApi(ORT_API_VERSION); });
std::call_once(init, []() { Ort::InitApi(Provider_GetHost()->OrtGetApiBase()->GetApi(ORT_API_VERSION)); });
}

} // namespace onnxruntime
} // namespace onnxruntime
4 changes: 2 additions & 2 deletions onnxruntime/core/providers/vitisai/imp/global_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@
struct MyCustomOpKernel : OpKernel {
MyCustomOpKernel(const OpKernelInfo& info, const OrtCustomOp& op) : OpKernel(info), op_(op) {
op_kernel_ =
op_.CreateKernel(&op_, Ort::Global<void>::api_, reinterpret_cast<const OrtKernelInfo*>(&info));
op_.CreateKernel(&op_, &Ort::GetApi() _, reinterpret_cast<const OrtKernelInfo*>(&info));

Check failure on line 232 in onnxruntime/core/providers/vitisai/imp/global_api.cc

View workflow job for this annotation

GitHub Actions / build_x64_release_vitisai

syntax error: ')'

Check failure on line 232 in onnxruntime/core/providers/vitisai/imp/global_api.cc

View workflow job for this annotation

GitHub Actions / build_x64_release_vitisai

'_': undeclared identifier

Check failure on line 232 in onnxruntime/core/providers/vitisai/imp/global_api.cc

View workflow job for this annotation

GitHub Actions / build_x64_release_vitisai

syntax error: missing ';' before identifier '_'

Check failure on line 232 in onnxruntime/core/providers/vitisai/imp/global_api.cc

View workflow job for this annotation

GitHub Actions / build_x64_release_vitisai

'void *(__cdecl *const )(const OrtCustomOp *,const OrtApi *,const OrtKernelInfo *)': too few arguments for call

Check failure on line 232 in onnxruntime/core/providers/vitisai/imp/global_api.cc

View workflow job for this annotation

GitHub Actions / build_x64_release_vitisai

syntax error: missing ')' before identifier '_'
Comment thread
chwarr marked this conversation as resolved.
Outdated
}

~MyCustomOpKernel() override { op_.KernelDestroy(op_kernel_); }
Expand Down Expand Up @@ -333,7 +333,7 @@
set_version_info(the_global_api);
the_global_api.host_ = Provider_GetHost();
assert(Ort::Global<void>::api_ != nullptr);
Comment thread
chwarr marked this conversation as resolved.
Outdated
the_global_api.ort_api_ = Ort::Global<void>::api_;
the_global_api.ort_api_ = &Ort::GetApi();
the_global_api.model_load = [](const std::string& filename) -> Model* {
auto model_proto = ONNX_NAMESPACE::ModelProto::Create();
auto& logger = logging::LoggingManager::DefaultLogger();
Expand Down
3 changes: 3 additions & 0 deletions onnxruntime/test/autoep/library/ep_arena.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ limitations under the License.
#include <mutex>
#include <set>

#define ORT_API_MANUAL_INIT
#include "onnxruntime_cxx_api.h"
#undef ORT_API_MANUAL_INIT
Comment thread
chwarr marked this conversation as resolved.

#include "ep_allocator.h"
#include "example_plugin_ep_utils.h"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static void AddOrtCustomOpDomainToContainer(Ort::CustomOpDomain&& domain) {
}

OrtStatus* ORT_API_CALL RegisterCustomOps(OrtSessionOptions* options, const OrtApiBase* api) {
Ort::Global<void>::api_ = api->GetApi(ORT_API_VERSION);
Ort::InitApi(api->GetApi(ORT_API_VERSION));
OrtStatus* result = nullptr;

ORT_TRY {
Expand Down
Loading