feat(ecosystem): compliant Praxis/Hexis integration + vendored build

Bring the Nexus/Praxis/Hexis integration in line with
MAVEN_ECOSYSTEM_ARCHITECTURE.md:

- Praxis over HTTP: drop the in-process praxis.db open (praxisstore/
  praxistools) and call praxisd's /api/v1/tools/* API via a new praxisClient.
  Honors the "no component reads another's DB" invariant (AC#12).
  PraxisConfig.DBPath -> URL.
- Hexis confirmation gate: mutating capabilities (ReadOnly=false) now park a
  bound pendingHexis confirmation and require a spoken "да" before executing;
  read-only run immediately (AC#7, no auto attention->action).
- Capability safety: >1 verb match is ambiguous -> ask instead of firing the
  first; ambiguous Nexus resolution asks for clarification (AC#2).
- Correlation IDs on Hexis execute, recorded in the cross-service trace.
- Bug: importance arrives as JSON float64 over HTTP, not int.
- Tests: confirm-gate, decline, read-only, and ambiguity paths.

Build: vendor/ bakes in the hexis client (replace-directed at a sibling repo
outside the Docker context); Dockerfile builds from vendor and no longer
`go mod download`s the unreachable replace paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
kami
2026-07-19 19:32:05 +04:00
parent 0c65387a5f
commit 6c92f85d10
2071 changed files with 3915438 additions and 61 deletions
+3
View File
@@ -0,0 +1,3 @@
onnxruntime_c_api.h linguist-vendored
onnxruntime_ep_c_api.h linguist-vendored
+136
View File
@@ -0,0 +1,136 @@
Contribution Guidelines
=======================
This library began as a personal project, and is primarily still maintained as
such. The following list of guidelines is not necessarily exhaustive, and,
ultimately, any contribution is subject to the maintainer's discretion. That
being said, contributions are welcome, and most recent new features have been
added by users who need them!
Coding Style
------------
- Go code must be formatted using the official `gofmt` tool.
- C code should adhere to the portions of Google's C++ style guide that
apply to C.
- If at all possible, any Go or C code should have at most 80 character lines.
(This may not be enforced very strictly.)
- Purely stylistic changes are unlikely to be accepted. Instead, the
maintainer or other contributers may make small stylistic adjustments to
surrounding code as part of other contributions.
- Attempt to mimic the existing style of the surrounding code.
Documentation
-------------
- All Go types, public-facing functions, and nontrivial internal functions
must include a comment on their intended usage, to be parsed by godoc.
- As per the google C++ style guide, all C functions must be documented with a
comment as well. If a C function is defined in a header file, the comment
should appear with the definition in the header. If it's a static function
in a `.c` file, the comment should appear with the function definition.
Tests
-----
- All new features and bugfixes must include a basic unit test (in
`onnxruntime_test.go`) to serve as a sanity check.
- If a test is for a platform-dependent or execution-provider-dependent
feature, the test must be skipped if run on an unsupported system.
- No tests should panic. Always check errors and fail rather than allowing
tests to panic.
- Every change must ensure that `go test -v -bench=.` passes.
- Every test failure should be accompanied by a message containing the reason,
either using `t.Logf()`, `t.Errorf()`, or `t.Fatalf()`.
Adding New Files
----------------
- Apart from testing data, try not to add new source files.
- Do not add third-party code or headers. The only exceptions for now are
`onnxruntime_c_api.h` and `onnxruntime_ep_c_api.h`.
- No C++ at all. Developing Go-to-C wrappers is annoying enough as it is.
- Do not add any new `onnxruntime` shared libraries under `test_data`. I know
there are additional platforms that would be nice to include (such as
`x86_64` Linux), but I do not want this project turning into an unofficial
distribution channel for onnxruntime libraries. It also clogs up the git
repo with large files, and increases the size of the history every time
these files are updated. The libraries that are included were only intended
to allow a majority of users to run `go test -v -bench=.` without further
setup or modification. Currently: amd64 Windows, arm64 Linux (I wish I
hadn't included this!), and arm64 osx. All other users must set the
`ONNXRUNTIME_SHARED_LIBRARY_PATH` environment variable to a valid path
to the correct `onnxruntime` shared library file prior to running tests.
- If you need to add a .onnx file for a test, place both the .onnx file
_and_ the script used to generate it into `test_data/`.
- Keep any testing .onnx files as small as possible.
- Without a good reason (i.e., implementing an entire class of APIs such as
training), avoid adding new Go files---just add to `onnxruntime_go.go`.
Dependencies
------------
- Avoid Go or C dependencies outside of the language's standard libraries.
This package currently does not depend on any third-party Go modules, and
it would be great to keep it this way.
- Python scripts within `test_data/` can use whatever dependencies they need,
because end users should not be required to run the python files, and the
`.onnx` file they produce should already be included.
C-Specific Stuff
----------------
- Minimize Go management of C-allocated memory as much as possible. For
example, see the `convertORTString` function on `onnxruntime_go.go`, which
copies a C-allocated string into a garbage-collected go `string`.
- If you need to use a `OrtAllocator` in onnxruntime's C API, always use the
default `OrtAllocator` returned by
`ort_api->GetAllocatorWithDefaultOptions()`.
- ONNXRuntime APIs requiring file paths typically use `ORTCHAR_T*`
strings. On Linux/OSX/etc, these should be UTF-8, but on Windows they will
be wide-character strings. (Our tricks with `#include` to make them look
like `char*` to C code even on Windows, but the DLL still expects a
`wchar_t*`.) The important takeaway: when passing `ORTCHAR_T*`
values to the onnxruntime C API, use the `createOrtCharString(...)`
function. It converts a Go string to a C string, but unlike `C.CString`, it
will do UTF8 to UTF16 conversion on Windows. (On Linux, it simply wraps
`C.CString`.)
A Few Notes on Organization
---------------------------
- The `onnxruntime` C API uses a struct containing function pointers. Cgo
can't directly invoke functions via pointers, so `onnxruntime_wrapper.c`
(along with the associated header file) are used to provide top-level C
functions that call the function pointers within the `OrtApi` struct.
- Linux and OSX use `dlopen` to load the onnxruntime shared library, but this
isn't possible on Windows, which instead can use the `syscall.LoadLibrary()`
function from Go's standard library. This different behavior is locked
behind build constraints in `setup_env.go` and `setup_env_windows.go`,
respectively.
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2023 Nathan Otterness
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+219
View File
@@ -0,0 +1,219 @@
Cross-Platform `onnxruntime` Wrapper for Go
===========================================
About
-----
This library seeks to provide an interface for loading and executing neural
networks from Go(lang) code, while remaining as simple to use as possible.
A few example applications using this library can be found in the
[`onnxruntime_go_examples` repository](https://github.com/yalue/onnxruntime_go_examples).
The [onnxruntime](https://github.com/microsoft/onnxruntime) library provides a
way to load and execute ONNX-format neural networks, though the library
primarily supports C and C++ APIs. Several efforts exist to have written
Go(lang) wrappers for the `onnxruntime` library, but as far as I can tell, none
of these existing Go wrappers support Windows. This is due to the fact that
Microsoft's `onnxruntime` library assumes the user will be using the MSVC
compiler on Windows systems, while CGo on Windows requires using Mingw.
This wrapper works around the issues by manually loading the `onnxruntime`
shared library, removing any dependency on the `onnxruntime` source code beyond
the header files. Naturally, this approach works equally well on non-Windows
systems.
Additionally, this library uses Go's recent addition of generics to support
multiple Tensor data types; see the `NewTensor` or `NewEmptyTensor` functions.
Several accelerated execution providers (including TensorRT, CUDA and CoreML)
are tested and confirmed to work with `onnxruntime_go`. The "Requirements"
portion of this README (below) has a few more details.
Note on onnxruntime Library Versions
------------------------------------
At the time of writing, this library uses version 1.26.0 of the onnxruntime
C API headers. So, it will probably only work with version 1.26.0 of the
onnxruntime shared libraries, as well. If you need to use a different version,
or if I get behind on updating this repository, updating or changing the
onnxruntime version should be fairly easy:
1. Replace the `onnxruntime_c_api.h` and `onnxruntime_ep_c_api.h` files with
the versions corresponding to the onnxruntime version you wish to use.
2. Replace the `test_data/onnxruntime.dll` (or `test_data/onnxruntime*.so`,
`test_data/onnxruntime*.dylib`) file with the version corresponding to the
onnxruntime version you wish to use.
3. (If you care about DirectML support) Verify that the entries in the
`DummyOrtDMLAPI` struct in `onnxruntime_wrapper.c` match the order in which
they appear in the `OrtDmlApi` struct from the `dml_provider_factory.h`
header in the official repo. See the comment on this struct in
`onnxruntime_wrapper.c` for more information.
Note that both the C API headers and the shared library files are available to
download from the releases page in the
[official repo](https://github.com/microsoft/onnxruntime). Download the archive
for the release you want to use, and extract it. The header files are located
in the "include" subdirectory, and the shared library will be located in the
"lib" subdirectory. (On Linux systems, you'll need the version of the .so with
the appended version numbers, e.g., `libonnxruntime.so.1.26.0`, and _not_ the
`libonnxruntime.so`, which is just a symbolic link.) The archive will contain
several other files containing C++ headers, debug symbols, and so on, but you
shouldn't need anything other than the single onnxruntime shared library and
the two `_c_api.h` header files. (The exception is if you're wanting to enable
GPU support, where you may need other shared-library files, such as
`execution_providers_cuda.dll` and `execution_providers_shared.dll` (or their
equivalents for Linux or OSX).
Requirements
------------
To use this library, you'll need a version of Go with cgo support. You'll also
need a copy of the correct version of the onnxruntime shared library or DLL for
your operating system and architecture. Prior to initializing
`onnxruntime_go`, you need to provide a path to this shared library. See the
first couple lines (i.e., `ort.SetSharedLibraryPath(...)`) of the following
example.
If you want to use CUDA, you'll need to be using a version of the onnxruntime
shared library with CUDA support, as well as be using a CUDA version supported
by the underlying version of your onnxruntime library. For example, version
1.23.2 of the onnxruntime library only supports CUDA versions 12.x. See
[the onnxruntime CUDA support documentation](https://onnxruntime.ai/docs/execution-providers/CUDA-ExecutionProvider.html)
for more specifics.
Similarly to CUDA, other execution providers have their own separate
requirements. All of these requirements are too numerous to document in this
README. Please ensure that you are successfully able to use your execution
provider of choice in a python script before raising issues about it here.
Example Usage
-------------
The full documentation can be found at [pkg.go.dev](https://pkg.go.dev/github.com/yalue/onnxruntime_go).
Additionally, several example command-line applications complete with necessary
networks and data can be found in the
[`onnxruntime_go_examples` repository](https://github.com/yalue/onnxruntime_go_examples).
The following example illustrates how this library can be used to load and run
an ONNX network taking a single input tensor and producing a single output
tensor, both of which contain 32-bit floating point values. Note that error
handling is omitted; each of the functions returns an err value, which will be
non-nil in the case of failure.
```go
import (
"fmt"
ort "github.com/yalue/onnxruntime_go"
"os"
)
func main() {
// This line _may_ be optional; by default the library will try to load
// "onnxruntime.dll" on Windows, and "onnxruntime.so" on any other system.
// For stability, programs should always set this explicitly.
ort.SetSharedLibraryPath("path/to/onnxruntime.so")
err := ort.InitializeEnvironment()
if err != nil {
panic(err)
}
defer ort.DestroyEnvironment()
// For a slight performance boost and convenience when re-using existing
// tensors, this library expects the user to create all input and output
// tensors prior to creating the session. If this isn't ideal for your use
// case, see the DynamicAdvancedSession type in the documnentation, which
// allows input and output tensors to be specified when calling Run()
// rather than when initializing a session.
inputData := []float32{0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9}
inputShape := ort.NewShape(2, 5)
inputTensor, err := ort.NewTensor(inputShape, inputData)
defer inputTensor.Destroy()
// This hypothetical network maps a 2x5 input -> 2x3x4 output.
outputShape := ort.NewShape(2, 3, 4)
outputTensor, err := ort.NewEmptyTensor[float32](outputShape)
defer outputTensor.Destroy()
session, err := ort.NewAdvancedSession("path/to/network.onnx",
[]string{"Input 1 Name"}, []string{"Output 1 Name"},
[]ort.Value{inputTensor}, []ort.Value{outputTensor}, nil)
defer session.Destroy()
// Calling Run() will run the network, reading the current contents of the
// input tensors and modifying the contents of the output tensors.
err = session.Run()
// Get a slice view of the output tensor's data.
outputData := outputTensor.GetData()
// If you want to run the network on a different input, all you need to do
// is modify the input tensor data (available via inputTensor.GetData())
// and call Run() again.
// ...
}
```
Deprecated APIs
---------------
**Typed `Session[t]`:** Older versions of this library used a typed
`Session[T]` struct to keep track of sessions. In retrospect, associating type
parameters with Sessions was unnecessary, and the `AdvancedSession` type, along
with its associated APIs, was added to rectify this mistake. For backwards
compatibility, the old typed `Session[T]` and `DynamicSession[T]` types are
still included and unlikely to be removed. However, they now delegate their
functionality to `AdvancedSession` internally. New code should always favor
using `AdvancedSession` directly.
**Onnxruntime's training API:** The training API has been deprecated as of
onnxruntime version 1.20. Rather than continuing to maintain wrappers for a
deprecated API, `onnxruntime_go` has replaced the wrapper functions for the
training API with stubs that return an error. Users who need to continue to
use the training API will need to use an older version. For example the
following versions should be compatible with training:
- Version `v1.12.1` of `onnxruntime_go`, and
- Version 1.19.2 of `onnxruntime`.
Running Tests and System Compatibility for Testing
--------------------------------------------------
Navigate to this directory and run `go test -v`, or optionally
`go test -v -bench=.`. All tests should pass; tests relating to CUDA or other
accelerator support will be skipped on systems or onnxruntime builds that don't
support them.
Currently, this repository includes a copy of the onnxruntime shared libraries
for a few systems, including AMD64 windows, ARM64 Linux, and ARM64 darwin.
These should allow tests to pass on those systems without users needing to copy
additional libraries beyond cloning this repository. In the future, however,
this may change if support for more systems are added or removed.
You may want to use a different version of the `onnxruntime` shared library for
a couple reasons. In particular:
1. The included shared library copies do not include support for CUDA or other
accelerated execution providers, so CUDA-related tests will always be
skipped if you use the default libraries in this repo.
2. Many systems, including AMD64 and i386 Linux, and x86 osx, do not currently
have shared libraries included in `test_data/` in the first place. (I would
like to keep this directory, and the overall repo, smaller by keeping the
number of shared libraries small.)
If these or other reasons apply to you, the test code will check the
`ONNXRUNTIME_SHARED_LIBRARY_PATH` environment variable before attempting to
load a library from `test_data/`. So, if you are using one of these systems or
want accelerator-related tests to run, you should set the environment variable
to the path to the onnxruntime shared library. Afterwards, `go test -v` should
run and pass.
+225
View File
@@ -0,0 +1,225 @@
package onnxruntime_go
// This file contains code and types that we maintain for compatibility
// purposes, but is not expected to be regularly maintained or udpated.
import (
"fmt"
"os"
)
// #include "onnxruntime_wrapper.h"
import "C"
// DEPRECATED: This type was written with a type parameter despite the fact
// that a type parameter is not necessary for any of its underlying
// implementation. It is preserved only for compatibility with older code, and
// new users should use AdvancedSession instead. Despite the name,
// AdvancedSession is equally simple to use and far more flexible.
type Session[T TensorData] struct {
// We now delegate all of the implementation to an AdvancedSession here.
s *AdvancedSession
}
// DEPRECATED: See the notes on Session[T]. Use DynamicAdvancedSession instead.
type DynamicSession[In TensorData, Out TensorData] struct {
s *DynamicAdvancedSession
}
// DEPRECATED: See the notes on Session[T]. Use NewAdvancedSessionWithONNXData
// instead.
func NewSessionWithONNXData[T TensorData](onnxData []byte, inputNames,
outputNames []string, inputs, outputs []*Tensor[T]) (*Session[T], error) {
// Unfortunately, a slice of pointers that satisfy an interface don't count
// as a slice of interfaces (at least, as I write this), so we'll make the
// conversion here.
tmpInputs := make([]Value, len(inputs))
tmpOutputs := make([]Value, len(outputs))
for i, t := range inputs {
tmpInputs[i] = t
}
for i, t := range outputs {
tmpOutputs[i] = t
}
s, e := NewAdvancedSessionWithONNXData(onnxData, inputNames, outputNames,
tmpInputs, tmpOutputs, nil)
if e != nil {
return nil, e
}
return &Session[T]{
s: s,
}, nil
}
// DEPRECATED: See the notes on Session[T]. Use
// NewDynamicAdvancedSessionWithONNXData instead.
func NewDynamicSessionWithONNXData[in TensorData, out TensorData](onnxData []byte,
inputNames, outputNames []string) (*DynamicSession[in, out], error) {
s, e := NewDynamicAdvancedSessionWithONNXData(onnxData, inputNames,
outputNames, nil)
if e != nil {
return nil, e
}
return &DynamicSession[in, out]{
s: s,
}, nil
}
// DEPRECATED: See the notes on Session[T]. Use NewAdvancedSession instead.
func NewSession[T TensorData](onnxFilePath string, inputNames,
outputNames []string, inputs, outputs []*Tensor[T]) (*Session[T], error) {
fileContent, e := os.ReadFile(onnxFilePath)
if e != nil {
return nil, fmt.Errorf("Error reading %s: %w", onnxFilePath, e)
}
toReturn, e := NewSessionWithONNXData[T](fileContent, inputNames,
outputNames, inputs, outputs)
if e != nil {
return nil, fmt.Errorf("Error creating session from %s: %w",
onnxFilePath, e)
}
return toReturn, nil
}
// DEPRECATED: See the notes on Session[T]. Use NewDynamicAdvancedSession
// instead.
func NewDynamicSession[in TensorData, out TensorData](onnxFilePath string,
inputNames, outputNames []string) (*DynamicSession[in, out], error) {
fileContent, e := os.ReadFile(onnxFilePath)
if e != nil {
return nil, fmt.Errorf("Error reading %s: %w", onnxFilePath, e)
}
toReturn, e := NewDynamicSessionWithONNXData[in, out](fileContent,
inputNames, outputNames)
if e != nil {
return nil, fmt.Errorf("Error creating session from %s: %w",
onnxFilePath, e)
}
return toReturn, nil
}
func (s *Session[_]) Destroy() error {
return s.s.Destroy()
}
func (s *DynamicSession[_, _]) Destroy() error {
return s.s.Destroy()
}
func (s *Session[T]) Run() error {
return s.s.Run()
}
func (s *DynamicSession[in, out]) Run(inputs []*Tensor[in],
outputs []*Tensor[out]) error {
if len(inputs) != len(s.s.s.inputNames) {
return fmt.Errorf("The session specified %d input names, but Run() "+
"was called with %d input tensors", len(s.s.s.inputNames),
len(inputs))
}
if len(outputs) != len(s.s.s.outputNames) {
return fmt.Errorf("The session specified %d output names, but Run() "+
"was called with %d output tensors", len(s.s.s.outputNames),
len(outputs))
}
inputValues := make([]*C.OrtValue, len(inputs))
for i, v := range inputs {
inputValues[i] = v.GetInternals().ortValue
}
outputValues := make([]*C.OrtValue, len(outputs))
for i, v := range outputs {
outputValues[i] = v.GetInternals().ortValue
}
status := C.RunOrtSession(s.s.s.ortSession, &inputValues[0],
&s.s.s.inputNames[0], C.int(len(inputs)), &outputValues[0],
&s.s.s.outputNames[0], C.int(len(outputs)))
if status != nil {
return fmt.Errorf("Error running network: %w", statusToError(status))
}
return nil
}
// This type alias is included to avoid breaking older code, where the inputs
// and outputs to session.Run() were ArbitraryTensors rather than Values.
type ArbitraryTensor = Value
// As with the ArbitraryTensor type, this type alias only exists to facilitate
// renaming an old type without breaking existing code.
type TensorInternalData = ValueInternalData
var TrainingAPIRemovedError error = fmt.Errorf("Support for the training " +
"API has been removed from onnxruntime_go following its deprecation in " +
"onnxruntime versions 1.19.2 and later. The last revision of " +
"onnxruntime_go supporting the training API is version v1.12.1")
// Support for TrainingSessions has been removed from onnxruntime_go following
// the deprecation of the training API in onnxruntime 1.20.0.
type TrainingSession struct{}
// Always returns TrainingAPIRemovedError.
func (s *TrainingSession) ExportModel(path string, outputNames []string) error {
return TrainingAPIRemovedError
}
// Always returns TrainingAPIRemovedError.
func (s *TrainingSession) SaveCheckpoint(path string,
saveOptimizerState bool) error {
return TrainingAPIRemovedError
}
// Always returns TrainingAPIRemovedError.
func (s *TrainingSession) Destroy() error {
return TrainingAPIRemovedError
}
// Always returns TrainingAPIRemovedError.
func (s *TrainingSession) TrainStep() error {
return TrainingAPIRemovedError
}
// Always returns TrainingAPIRemovedError.
func (s *TrainingSession) OptimizerStep() error {
return TrainingAPIRemovedError
}
// Always returns TrainingAPIRemovedError.
func (s *TrainingSession) LazyResetGrad() error {
return TrainingAPIRemovedError
}
// Support for TrainingInputOutputNames has been removed from onnxruntime_go
// following the deprecation of the training API in onnxruntime 1.20.0.
type TrainingInputOutputNames struct {
TrainingInputNames []string
EvalInputNames []string
TrainingOutputNames []string
EvalOutputNames []string
}
// Always returns (nil, TrainingAPIRemovedError).
func GetInputOutputNames(checkpointStatePath string, trainingModelPath string,
evalModelPath string) (*TrainingInputOutputNames, error) {
return nil, TrainingAPIRemovedError
}
// Always returns false.
func IsTrainingSupported() bool {
return false
}
// Always returns (nil, TrainingAPIRemovedError).
func NewTrainingSessionWithOnnxData(checkpointData, trainingData, evalData,
optimizerData []byte, inputs, outputs []Value,
options *SessionOptions) (*TrainingSession, error) {
return nil, TrainingAPIRemovedError
}
// Always returns (nil, TrainingAPIRemovedError).
func NewTrainingSession(checkpointStatePath, trainingModelPath, evalModelPath,
optimizerModelPath string, inputs, outputs []Value,
options *SessionOptions) (*TrainingSession, error) {
return nil, TrainingAPIRemovedError
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+655
View File
@@ -0,0 +1,655 @@
#include "onnxruntime_wrapper.h"
static const OrtApi *ort_api = NULL;
static const char *ORT_VERSION = NULL;
static AppendCoreMLProviderFn append_coreml_provider_fn = NULL;
// The dml_provider_factory.h header for using DirectML is annoying to include
// here for a couple reasons:
// - It contains C++
// - It includes d3d12.h and DirectML.h, both of which may be hard to set up
// under mingw
// Fortunately, the basic AppendExecutionProvider_DML function from the
// OrtDmlApi struct does not rely on any of these things, but we still need the
// struct definition itself. Obviously, copying it here is not perfect, and
// we'll need to keep an eye on it to make sure it doesn't change between
// updates. Most importantly, we need to make sure that the one function we
// care about remains at the same place in the struct. Since it's first,
// hopefully it's unlikely to change.
typedef OrtStatus* (*AppendDirectMLProviderFn)(OrtSessionOptions*, int);
typedef struct {
AppendDirectMLProviderFn SessionOptionsAppendExecutionProvider_DML;
// All of these functions pointers should be irrelevant (and they depend on
// other definitions from dml_provider_factory.h), but I'll copy them here
// regardless as plain void*s. GetExecutionProviderApi shouldn't write to
// this struct anyway, as it only provides a const pointer to it.
void *SessionOptionsAppendExecutionProvider_DML1;
void *CreateGPUAllocationFromD3DResource;
void *FreeGPUAllocation;
void *GetD3D12ResourceFromAllocation;
void *SessionOptionsAppendExecutionProvider_DML2;
void *GetDMLDevice;
void *GetDMLCommandQueue;
} DummyOrtDMLAPI;
int SetAPIFromBase(OrtApiBase *api_base) {
if (!api_base) return 1;
ort_api = api_base->GetApi(ORT_API_VERSION);
ORT_VERSION = api_base->GetVersionString();
if (!ort_api) return 2;
return 0;
}
const char *GetVersion() {
return ORT_VERSION;
}
void SetCoreMLProviderFunctionPointer(void *ptr) {
append_coreml_provider_fn = (AppendCoreMLProviderFn) ptr;
}
void ReleaseOrtStatus(OrtStatus *status) {
ort_api->ReleaseStatus(status);
}
OrtStatus *CreateOrtEnv(char *name, OrtEnv **env) {
return ort_api->CreateEnv(ORT_LOGGING_LEVEL_ERROR, name, env);
}
OrtStatus *UpdateEnvWithCustomLogLevel(OrtEnv *ort_env,
OrtLoggingLevel log_severity_level) {
return ort_api->UpdateEnvWithCustomLogLevel(ort_env, log_severity_level);
}
OrtStatus *DisableTelemetry(OrtEnv *env) {
return ort_api->DisableTelemetryEvents(env);
}
OrtStatus *EnableTelemetry(OrtEnv *env) {
return ort_api->EnableTelemetryEvents(env);
}
void ReleaseOrtEnv(OrtEnv *env) {
ort_api->ReleaseEnv(env);
}
OrtStatus *CreateOrtMemoryInfo(OrtMemoryInfo **mem_info) {
return ort_api->CreateCpuMemoryInfo(OrtArenaAllocator, OrtMemTypeDefault,
mem_info);
}
void ReleaseOrtMemoryInfo(OrtMemoryInfo *info) {
ort_api->ReleaseMemoryInfo(info);
}
const char *GetErrorMessage(OrtStatus *status) {
if (!status) return "No error (NULL status)";
return ort_api->GetErrorMessage(status);
}
OrtStatus *CreateSessionOptions(OrtSessionOptions **o) {
return ort_api->CreateSessionOptions(o);
}
void ReleaseSessionOptions(OrtSessionOptions *o) {
ort_api->ReleaseSessionOptions(o);
}
OrtStatus *SetSessionExecutionMode(OrtSessionOptions *o, int new_mode) {
return ort_api->SetSessionExecutionMode(o, new_mode);
}
OrtStatus *SetSessionGraphOptimizationLevel(OrtSessionOptions *o, int level) {
return ort_api->SetSessionGraphOptimizationLevel(o, level);
}
OrtStatus *SetSessionLogSeverityLevel(OrtSessionOptions *o, int level) {
return ort_api->SetSessionLogSeverityLevel(o, level);
}
OrtStatus *AddSessionConfigEntry(OrtSessionOptions *o, char *key,
char *value) {
return ort_api->AddSessionConfigEntry(o, key, value);
}
OrtStatus *HasSessionConfigEntry(OrtSessionOptions *o, char *key,
int *result) {
return ort_api->HasSessionConfigEntry(o, key, result);
}
// Wraps ort_api->GetSessionConfigEntry
OrtStatus *GetSessionConfigEntry(OrtSessionOptions *o, char *key, char *result,
size_t *required_size) {
return ort_api->GetSessionConfigEntry(o, key, result, required_size);
}
OrtStatus *SetIntraOpNumThreads(OrtSessionOptions *o, int n) {
return ort_api->SetIntraOpNumThreads(o, n);
}
OrtStatus *SetInterOpNumThreads(OrtSessionOptions *o, int n) {
return ort_api->SetInterOpNumThreads(o, n);
}
OrtStatus *SetCpuMemArena(OrtSessionOptions *o, int use_arena){
if (use_arena)
return ort_api->EnableCpuMemArena(o);
return ort_api->DisableCpuMemArena(o);
}
OrtStatus *SetMemPattern(OrtSessionOptions *o, int use_mem_pattern){
if (use_mem_pattern)
return ort_api->EnableMemPattern(o);
return ort_api->DisableMemPattern(o);
}
OrtStatus *AppendExecutionProviderCUDAV2(OrtSessionOptions *o,
OrtCUDAProviderOptionsV2 *cuda_options) {
return ort_api->SessionOptionsAppendExecutionProvider_CUDA_V2(o,
cuda_options);
}
OrtStatus *CreateCUDAProviderOptions(OrtCUDAProviderOptionsV2 **o) {
return ort_api->CreateCUDAProviderOptions(o);
}
void ReleaseCUDAProviderOptions(OrtCUDAProviderOptionsV2 *o) {
ort_api->ReleaseCUDAProviderOptions(o);
}
OrtStatus *UpdateCUDAProviderOptions(OrtCUDAProviderOptionsV2 *o,
const char **keys, const char **values, int num_keys) {
return ort_api->UpdateCUDAProviderOptions(o, keys, values, num_keys);
}
OrtStatus *CreateTensorRTProviderOptions(OrtTensorRTProviderOptionsV2 **o) {
return ort_api->CreateTensorRTProviderOptions(o);
}
void ReleaseTensorRTProviderOptions(OrtTensorRTProviderOptionsV2 *o) {
ort_api->ReleaseTensorRTProviderOptions(o);
}
OrtStatus *UpdateTensorRTProviderOptions(OrtTensorRTProviderOptionsV2 *o,
const char **keys, const char **values, int num_keys) {
return ort_api->UpdateTensorRTProviderOptions(o, keys, values, num_keys);
}
OrtStatus *AppendExecutionProviderTensorRTV2(OrtSessionOptions *o,
OrtTensorRTProviderOptionsV2 *tensor_rt_options) {
return ort_api->SessionOptionsAppendExecutionProvider_TensorRT_V2(o,
tensor_rt_options);
}
OrtStatus *AppendExecutionProviderCoreML(OrtSessionOptions *o,
uint32_t flags) {
if (!append_coreml_provider_fn) {
return ort_api->CreateStatus(ORT_NOT_IMPLEMENTED, "Your platform or "
"onnxruntime library does not support CoreML");
}
return append_coreml_provider_fn(o, flags);
}
OrtStatus *AppendExecutionProviderCoreMLV2(OrtSessionOptions *o,
const char **keys, const char **values, size_t num_options) {
if (!append_coreml_provider_fn) {
return ort_api->CreateStatus(ORT_NOT_IMPLEMENTED, "Your platform or "
"onnxruntime library does not support CoreML");
}
return ort_api->SessionOptionsAppendExecutionProvider(o, "CoreML", keys, values, num_options);
}
OrtStatus *AppendExecutionProviderDirectML(OrtSessionOptions *o,
int device_id) {
DummyOrtDMLAPI *dml_api = NULL;
OrtStatus *status = NULL;
status = ort_api->GetExecutionProviderApi("DML", ORT_API_VERSION,
(const void **) (&dml_api));
if (status) return status;
status = dml_api->SessionOptionsAppendExecutionProvider_DML(o, device_id);
return status;
}
OrtStatus *AppendExecutionProviderOpenVINOV2(OrtSessionOptions *o,
const char **keys, const char **values, int num_keys) {
return ort_api->SessionOptionsAppendExecutionProvider_OpenVINO_V2(o, keys,
values, num_keys);
}
OrtStatus *AppendExecutionProvider(OrtSessionOptions *o,
const char *provider_name, const char **keys, const char **values,
int num_keys) {
return ort_api->SessionOptionsAppendExecutionProvider(o, provider_name,
keys, values, num_keys);
}
OrtStatus *SetOptimizedModelFilePath(OrtSessionOptions *o,
char *path) {
return ort_api->SetOptimizedModelFilePath(o, (const ORTCHAR_T*) path);
}
OrtStatus *EnableProfiling(OrtSessionOptions *o, char *path) {
return ort_api->EnableProfiling(o, (const ORTCHAR_T*) path);
}
OrtStatus *DisableProfiling(OrtSessionOptions *o) {
return ort_api->DisableProfiling(o);
}
OrtStatus *RegisterExecutionProviderLibrary(OrtEnv *env,
const char *registration_name, char *path) {
return ort_api->RegisterExecutionProviderLibrary(env, registration_name,
(const ORTCHAR_T *) path);
}
OrtStatus *UnregisterExecutionProviderLibrary(OrtEnv *env,
const char *registration_name) {
return ort_api->UnregisterExecutionProviderLibrary(env, registration_name);
}
OrtStatus *RegisterCustomOpsLibraryV2(
OrtSessionOptions *o,
const char *library_path) {
return ort_api->RegisterCustomOpsLibrary_V2(o, library_path);
}
OrtStatus *GetEpDevices(OrtEnv *env,
const OrtEpDevice * const **out_devices, size_t *out_count) {
return ort_api->GetEpDevices(env, out_devices, out_count);
}
const char *EpDeviceEpName(const OrtEpDevice *device) {
return ort_api->EpDevice_EpName(device);
}
const char *EpDeviceEpVendor(const OrtEpDevice *device) {
return ort_api->EpDevice_EpVendor(device);
}
OrtStatus *AppendExecutionProviderV2(OrtSessionOptions *o, OrtEnv *env,
const OrtEpDevice * const *ep_devices, size_t num_ep_devices,
const char **keys, const char **values, size_t num_keys) {
return ort_api->SessionOptionsAppendExecutionProvider_V2(o, env, ep_devices,
num_ep_devices, keys, values, num_keys);
}
OrtStatus *CreateArenaCfg(size_t max_mem, int arena_extend_strategy,
int initial_chunk_size_bytes, int max_dead_bytes_per_chunk,
OrtArenaCfg **out) {
return ort_api->CreateArenaCfg(max_mem, arena_extend_strategy,
initial_chunk_size_bytes, max_dead_bytes_per_chunk, out);
}
OrtStatus *CreateArenaCfgV2(const char *const *arena_config_keys,
const size_t *arena_config_values, size_t num_keys, OrtArenaCfg **out) {
return ort_api->CreateArenaCfgV2(arena_config_keys, arena_config_values,
num_keys, out);
}
void ReleaseArenaCfg(OrtArenaCfg *ptr) {
ort_api->ReleaseArenaCfg(ptr);
}
OrtStatus *CreateAndRegisterAllocator(OrtEnv *env,
const OrtMemoryInfo *mem_info, const OrtArenaCfg *arena_cfg) {
return ort_api->CreateAndRegisterAllocator(env, mem_info, arena_cfg);
}
OrtStatus *CreateAndRegisterAllocatorV2(OrtEnv *env,
const char *provider_type, const OrtMemoryInfo *mem_info,
const OrtArenaCfg *arena_cfg, const char *const *provider_options_keys,
const char *const *provider_options_values, size_t num_keys) {
return ort_api->CreateAndRegisterAllocatorV2(env, provider_type, mem_info,
arena_cfg, provider_options_keys, provider_options_values, num_keys);
}
OrtStatus *RegisterAllocator(OrtEnv *env, OrtAllocator *allocator) {
return ort_api->RegisterAllocator(env, allocator);
}
OrtStatus *UnregisterAllocator(OrtEnv *env, const OrtMemoryInfo *mem_info) {
return ort_api->UnregisterAllocator(env, mem_info);
}
OrtStatus *CreateSession(void *model_data, size_t model_data_length,
OrtEnv *env, OrtSession **out, OrtSessionOptions *options) {
OrtStatus *status = NULL;
int default_options = 0;
if (!options) {
default_options = 1;
status = ort_api->CreateSessionOptions(&options);
if (status) return status;
}
status = ort_api->CreateSessionFromArray(env, model_data, model_data_length,
options, out);
if (default_options) {
// If we created a default, empty, options struct, we don't need to keep it
// after creating the session.
ort_api->ReleaseSessionOptions(options);
}
return status;
}
OrtStatus *CreateSessionFromFile(char *model_path, OrtEnv *env,
OrtSession **out, OrtSessionOptions *options) {
// Nearly identical to CreateSession, except invokes ort_api->CreateSession
// rather than ort_api->CreateSessionFromArray.
OrtStatus *status = NULL;
int default_options = 0;
if (!options) {
default_options = 1;
status = ort_api->CreateSessionOptions(&options);
if (status) return status;
}
status = ort_api->CreateSession(env, (const ORTCHAR_T*) model_path, options,
out);
if (default_options) ort_api->ReleaseSessionOptions(options);
return status;
}
OrtStatus *RunOrtSession(OrtSession *session,
OrtValue **inputs, char **input_names, int input_count,
OrtValue **outputs, char **output_names, int output_count) {
OrtStatus *status = NULL;
status = ort_api->Run(session, NULL, (const char* const*) input_names,
(const OrtValue* const*) inputs, input_count,
(const char* const*) output_names, output_count, outputs);
return status;
}
OrtStatus *RunOrtSessionWithOptions(OrtSession *session,
OrtValue **inputs, char **input_names, int input_count,
OrtValue **outputs, char **output_names, int output_count,
OrtRunOptions *run_options) {
OrtStatus *status = NULL;
status = ort_api->Run(session, run_options, (const char* const*) input_names,
(const OrtValue* const*) inputs, input_count,
(const char* const*) output_names, output_count, outputs);
return status;
}
OrtStatus *CreateRunOptions(OrtRunOptions **o) {
return ort_api->CreateRunOptions(o);
}
void ReleaseRunOptions(OrtRunOptions *o) {
ort_api->ReleaseRunOptions(o);
}
OrtStatus *RunOptionsSetTerminate(OrtRunOptions *o) {
return ort_api->RunOptionsSetTerminate(o);
}
OrtStatus *RunOptionsUnsetTerminate(OrtRunOptions *o) {
return ort_api->RunOptionsUnsetTerminate(o);
}
OrtStatus *RunSessionWithBinding(OrtSession *session, OrtIoBinding *b) {
return ort_api->RunWithBinding(session, NULL, b);
}
void ReleaseOrtSession(OrtSession *session) {
ort_api->ReleaseSession(session);
}
OrtStatus *CreateIoBinding(OrtSession *session, OrtIoBinding **out) {
return ort_api->CreateIoBinding(session, out);
}
void ReleaseIoBinding(OrtIoBinding *b) {
ort_api->ReleaseIoBinding(b);
}
OrtStatus *BindInput(OrtIoBinding *b, char *name, OrtValue *value) {
return ort_api->BindInput(b, name, value);
}
OrtStatus *BindOutput(OrtIoBinding *b, char *name, OrtValue *value) {
return ort_api->BindOutput(b, name, value);
}
OrtStatus *GetBoundOutputNames(OrtIoBinding *b, char **buffer,
size_t **lengths, size_t *count) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->GetBoundOutputNames(b, allocator, buffer, lengths, count);
}
OrtStatus *SessionGetInputCount(OrtSession *session, size_t *result) {
return ort_api->SessionGetInputCount(session, result);
}
OrtStatus *GetBoundOutputValues(OrtIoBinding *b, OrtValue ***buffer,
size_t *count) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->GetBoundOutputValues(b, allocator, buffer, count);
}
void ClearBoundInputs(OrtIoBinding *b) {
ort_api->ClearBoundInputs(b);
}
void ClearBoundOutputs(OrtIoBinding *b) {
ort_api->ClearBoundOutputs(b);
}
OrtStatus *SessionGetOutputCount(OrtSession *session, size_t *result) {
return ort_api->SessionGetOutputCount(session, result);
}
void ReleaseOrtValue(OrtValue *value) {
ort_api->ReleaseValue(value);
}
OrtStatus *CreateOrtTensorWithShape(void *data, size_t data_size,
int64_t *shape, int64_t shape_size, OrtMemoryInfo *mem_info,
ONNXTensorElementDataType dtype, OrtValue **out) {
OrtStatus *status = NULL;
status = ort_api->CreateTensorWithDataAsOrtValue(mem_info, data, data_size,
shape, shape_size, dtype, out);
return status;
}
OrtStatus *CreateTensorAsOrtValue(int64_t *shape, int64_t shape_size,
ONNXTensorElementDataType dtype, OrtValue **out) {
OrtStatus *status = NULL;
OrtAllocator *allocator = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
status = ort_api->CreateTensorAsOrtValue(allocator, shape, shape_size, dtype,
out);
return status;
}
OrtStatus *GetTensorTypeAndShape(const OrtValue *value, OrtTensorTypeAndShapeInfo **out) {
return ort_api->GetTensorTypeAndShape(value, out);
}
OrtStatus *GetDimensionsCount(const OrtTensorTypeAndShapeInfo *info, size_t *out) {
return ort_api->GetDimensionsCount(info, out);
}
OrtStatus *GetDimensions(const OrtTensorTypeAndShapeInfo *info, int64_t *dim_values, size_t dim_values_length) {
return ort_api->GetDimensions(info, dim_values, dim_values_length);
}
OrtStatus *GetTensorElementType(const OrtTensorTypeAndShapeInfo *info, enum ONNXTensorElementDataType *out) {
return ort_api->GetTensorElementType(info, out);
}
void ReleaseTensorTypeAndShapeInfo(OrtTensorTypeAndShapeInfo *input) {
ort_api->ReleaseTensorTypeAndShapeInfo(input);
}
OrtStatus *GetTensorMutableData(OrtValue *value, void **out) {
return ort_api->GetTensorMutableData(value, out);
}
OrtStatus *SessionGetInputName(OrtSession *session, size_t i, char **name) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->SessionGetInputName(session, i, allocator, name);
}
OrtStatus *SessionGetOutputName(OrtSession *session, size_t i, char **name) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->SessionGetOutputName(session, i, allocator, name);
}
OrtStatus *FreeWithDefaultORTAllocator(void *to_free) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->AllocatorFree(allocator, to_free);
}
OrtStatus *SessionGetInputTypeInfo(OrtSession *session, size_t i,
OrtTypeInfo **out) {
return ort_api->SessionGetInputTypeInfo(session, i, out);
}
OrtStatus *SessionGetOutputTypeInfo(OrtSession *session, size_t i,
OrtTypeInfo **out) {
return ort_api->SessionGetOutputTypeInfo(session, i, out);
}
void ReleaseTypeInfo(OrtTypeInfo *o) {
ort_api->ReleaseTypeInfo(o);
}
OrtStatus *GetONNXTypeFromTypeInfo(OrtTypeInfo *info, enum ONNXType *out) {
return ort_api->GetOnnxTypeFromTypeInfo(info, out);
}
OrtStatus *CastTypeInfoToTensorInfo(OrtTypeInfo *type_info,
OrtTensorTypeAndShapeInfo **out) {
return ort_api->CastTypeInfoToTensorInfo(type_info,
(const OrtTensorTypeAndShapeInfo **) out);
}
OrtStatus *SessionGetModelMetadata(OrtSession *s, OrtModelMetadata **m) {
return ort_api->SessionGetModelMetadata(s, m);
}
void ReleaseModelMetadata(OrtModelMetadata *m) {
return ort_api->ReleaseModelMetadata(m);
}
OrtStatus *ModelMetadataGetProducerName(OrtModelMetadata *m, char **name) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->ModelMetadataGetProducerName(m, allocator, name);
}
OrtStatus *ModelMetadataGetGraphName(OrtModelMetadata *m, char **name) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->ModelMetadataGetGraphName(m, allocator, name);
}
OrtStatus *ModelMetadataGetDomain(OrtModelMetadata *m, char **domain) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->ModelMetadataGetDomain(m, allocator, domain);
}
OrtStatus *ModelMetadataGetDescription(OrtModelMetadata *m, char **desc) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->ModelMetadataGetDescription(m, allocator, desc);
}
OrtStatus *ModelMetadataLookupCustomMetadataMap(OrtModelMetadata *m, char *key,
char **value) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->ModelMetadataLookupCustomMetadataMap(m, allocator, key,
value);
}
OrtStatus *ModelMetadataGetCustomMetadataMapKeys(OrtModelMetadata *m,
char ***keys, int64_t *num_keys) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->ModelMetadataGetCustomMetadataMapKeys(m, allocator, keys,
num_keys);
}
OrtStatus *ModelMetadataGetVersion(OrtModelMetadata *m, int64_t *version) {
return ort_api->ModelMetadataGetVersion(m, version);
}
OrtStatus *GetValue(OrtValue *container, int index, OrtValue **dst) {
OrtAllocator *allocator = NULL;
OrtStatus *status = NULL;
status = ort_api->GetAllocatorWithDefaultOptions(&allocator);
if (status) return status;
return ort_api->GetValue(container, index, allocator, dst);
}
OrtStatus *GetValueType(OrtValue *v, enum ONNXType *out) {
return ort_api->GetValueType(v, out);
}
OrtStatus *GetValueCount(OrtValue *v, size_t *out) {
return ort_api->GetValueCount(v, out);
}
OrtStatus *CreateOrtValue(OrtValue **in, size_t num_values,
enum ONNXType value_type, OrtValue **out) {
return ort_api->CreateValue((const OrtValue* const*) in, num_values,
value_type, out);
}
OrtStatus *FillStringTensor(OrtValue *v, char **strings, size_t num_strings) {
return ort_api->FillStringTensor(v, (const char* const*) strings,
num_strings);
}
OrtStatus *GetStringTensorDataLength(OrtValue *v, size_t *length) {
return ort_api->GetStringTensorDataLength(v, length);
}
OrtStatus *GetStringTensorContent(OrtValue *v, void *data_buffer,
size_t data_size, size_t *offsets_buffer, size_t offsets_length) {
return ort_api->GetStringTensorContent(v, data_buffer, data_size,
offsets_buffer, offsets_length);
}
OrtStatus *FillStringTensorElement(OrtValue *v, char *s, size_t index) {
return ort_api->FillStringTensorElement(v, s, index);
}
OrtStatus *GetStringTensorElementLength(OrtValue *v, size_t index,
size_t *result) {
return ort_api->GetStringTensorElementLength(v, index, result);
}
OrtStatus *GetStringTensorElement(OrtValue *v, size_t buffer_length,
size_t index, void *buffer) {
return ort_api->GetStringTensorElement(v, buffer_length, index, buffer);
}
+438
View File
@@ -0,0 +1,438 @@
#ifndef ONNXRUNTIME_WRAPPER_H
#define ONNXRUNTIME_WRAPPER_H
// We want to always use the unix-like onnxruntime C APIs, even on Windows, so
// we need to undefine _WIN32 before including onnxruntime_c_api.h. However,
// this requires a careful song-and-dance.
// First, include these common headers, as they get transitively included by
// onnxruntime_c_api.h. We need to include them ourselves, first, so that the
// preprocessor will skip them while _WIN32 is undefined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Next, we actually include the header.
#undef _WIN32
#include "onnxruntime_c_api.h"
// ... However, mingw will complain if _WIN32 is *not* defined! So redefine it.
#define _WIN32
#ifdef __cplusplus
extern "C" {
#endif
// Used for the OrtSessionOptionsAppendExecutionProvider_CoreML function
// pointer on supported systems. Must match the signature in
// coreml_provider_factory.h provided along with the onnxruntime releases for
// Apple platforms.
typedef OrtStatus* (*AppendCoreMLProviderFn)(OrtSessionOptions*, uint32_t);
// Takes a pointer to the api_base struct in order to obtain the OrtApi
// pointer. Intended to be called from Go. Returns nonzero on error.
int SetAPIFromBase(OrtApiBase *api_base);
// Get the version of the Onnxruntime library for logging.
const char *GetVersion();
// OrtSessionOptionsAppendExecutionProvider_CoreML is exported directly from
// the Apple .dylib, so we call this function on Apple platforms to set the
// function pointer to the correct address. On other platforms, the function
// pointer should remain NULL.
void SetCoreMLProviderFunctionPointer(void *ptr);
// Wraps ort_api->ReleaseStatus(status)
void ReleaseOrtStatus(OrtStatus *status);
// Wraps calling ort_api->CreateEnv. Returns a non-NULL status on error.
OrtStatus *CreateOrtEnv(char *name, OrtEnv **env);
// Wraps calling ort_api->UpdateEnvWithCustomLogLevel. Return a non-NULL status
// on error.
OrtStatus *UpdateEnvWithCustomLogLevel(OrtEnv *ort_env,
OrtLoggingLevel log_severity_level);
// Wraps ort_api->DisableTelemetryEvents. Returns a non-NULL status on error.
OrtStatus *DisableTelemetry(OrtEnv *env);
// Wraps ort_api->EnableTelemetryEvents. Returns a non-NULL status on error.
OrtStatus *EnableTelemetry(OrtEnv *env);
// Wraps ort_api->ReleaseEnv
void ReleaseOrtEnv(OrtEnv *env);
// Wraps ort_api->CreateCpuMemoryInfo with some basic, default settings.
OrtStatus *CreateOrtMemoryInfo(OrtMemoryInfo **mem_info);
// Wraps ort_api->ReleaseMemoryInfo
void ReleaseOrtMemoryInfo(OrtMemoryInfo *info);
// Returns the message associated with the given ORT status.
const char *GetErrorMessage(OrtStatus *status);
// Wraps ort_api->CreateSessionOptions
OrtStatus *CreateSessionOptions(OrtSessionOptions **o);
// Wraps ort_api->ReleaseSessionOptions
void ReleaseSessionOptions(OrtSessionOptions *o);
// Wraps ort_api->SetSessionExecutionMode
OrtStatus *SetSessionExecutionMode(OrtSessionOptions *o, int new_mode);
// Wraps ort_api->SetSessionGraphOptimizationLevel
OrtStatus *SetSessionGraphOptimizationLevel(OrtSessionOptions *o, int level);
// Wraps ort_api->SetSessionLogSeverityLevel
OrtStatus *SetSessionLogSeverityLevel(OrtSessionOptions *o, int level);
// Wraps ort_api->AddSessionConfigEntry
OrtStatus *AddSessionConfigEntry(OrtSessionOptions *o, char *key, char *value);
// Wraps ort_api->HasSessionConfigEntry
OrtStatus *HasSessionConfigEntry(OrtSessionOptions *o, char *key, int *result);
// Wraps ort_api->GetSessionConfigEntry
OrtStatus *GetSessionConfigEntry(OrtSessionOptions *o, char *key, char *result,
size_t *required_size);
// Wraps ort_api->SetIntraOpNumThreads
OrtStatus *SetIntraOpNumThreads(OrtSessionOptions *o, int n);
// Wraps ort_api->SetInterOpNumThreads
OrtStatus *SetInterOpNumThreads(OrtSessionOptions *o, int n);
// Wraps ort_api->EnableCpuMemArena & ort_api->DisableCpuMemArena
OrtStatus *SetCpuMemArena(OrtSessionOptions *o, int use_arena);
// Wraps ort_api->EnableMemPattern & ort_api->DisableMemPattern
OrtStatus *SetMemPattern(OrtSessionOptions *o, int use_mem_pattern);
// Wraps ort_api->SessionOptionsAppendExecutionProvider_CUDA_V2
OrtStatus *AppendExecutionProviderCUDAV2(OrtSessionOptions *o,
OrtCUDAProviderOptionsV2 *cuda_options);
// Wraps ort_api->CreateCUDAProviderOptions
OrtStatus *CreateCUDAProviderOptions(OrtCUDAProviderOptionsV2 **o);
// Wraps ort_api->ReleaseCUDAProviderOptions
void ReleaseCUDAProviderOptions(OrtCUDAProviderOptionsV2 *o);
// Wraps ort_api->UpdateCUDAProviderOptions
OrtStatus *UpdateCUDAProviderOptions(OrtCUDAProviderOptionsV2 *o,
const char **keys, const char **values, int num_keys);
// Wraps ort_api->CreateTensorRTProviderOptions
OrtStatus *CreateTensorRTProviderOptions(OrtTensorRTProviderOptionsV2 **o);
// Wraps ort_api->ReleaseTensorRTProviderOptions
void ReleaseTensorRTProviderOptions(OrtTensorRTProviderOptionsV2 *o);
// Wraps ort_api->UpdateTensorRTProviderOptions
OrtStatus *UpdateTensorRTProviderOptions(OrtTensorRTProviderOptionsV2 *o,
const char **keys, const char **values, int num_keys);
// Wraps ort_api->SessionOptionsAppendExecutionProvider_TensorRT_V2
OrtStatus *AppendExecutionProviderTensorRTV2(OrtSessionOptions *o,
OrtTensorRTProviderOptionsV2 *tensor_rt_options);
// Wraps OrtSessionOptionsAppendExecutionProvider_CoreML, exported from the
// dylib on Apple devices. Safely returns a non-NULL status on other platforms.
OrtStatus *AppendExecutionProviderCoreML(OrtSessionOptions *o,
uint32_t flags);
// Wraps OrtApi method SessionOptionsAppendExecutionProvider specifically for CoreML
// with the new options-based API while including the check that coreml is supported.
OrtStatus *AppendExecutionProviderCoreMLV2(OrtSessionOptions *o,
const char **keys, const char **values, size_t num_options);
// Wraps getting the OrtDmlApi struct and calling
// dml_api->SessionOptionsAppendExecutionProvider_DML.
OrtStatus *AppendExecutionProviderDirectML(OrtSessionOptions *o,
int device_id);
// Wraps ort_api->AppendExecutionProvider_OpenVINO_V2
OrtStatus *AppendExecutionProviderOpenVINOV2(OrtSessionOptions *o,
const char **keys, const char **values, int num_keys);
// Wraps ort_api->SessionOptionsAppendExecutionProvider
OrtStatus *AppendExecutionProvider(OrtSessionOptions *o,
const char *provider_name, const char **keys, const char **values,
int num_keys);
// Wraps ort_api->SetOptimizedModelFilePath. NOTE: takes an ORTCHAR_T*.
OrtStatus *SetOptimizedModelFilePath(OrtSessionOptions *o,
char *path);
// Wraps ort_api->EnableProfiling. NOTE: takes an ORTCHAR_T*.
OrtStatus *EnableProfiling(OrtSessionOptions *o, char *path);
// Wraps ort_api->DisableProfiling.
OrtStatus *DisableProfiling(OrtSessionOptions *o);
// Wraps ort_api->RegisterExecutionProviderLibrary
OrtStatus *RegisterExecutionProviderLibrary(OrtEnv *env,
const char *registration_name, char *path);
// Wraps ort_api->RegisterCustomOpsLibraryV2
OrtStatus *RegisterCustomOpsLibraryV2(OrtSessionOptions *o,
const char *library_name);
// Wraps ort_api->UnregisterExecutionProviderLibrary
OrtStatus *UnregisterExecutionProviderLibrary(OrtEnv *env,
const char *registration_name);
// Wraps ort_api->GetEpDevices. The returned array is owned by the OrtEnv and
// must NOT be freed by the caller; the pointers inside it remain valid until
// the corresponding plugin library is unregistered or the env is released.
OrtStatus *GetEpDevices(OrtEnv *env,
const OrtEpDevice * const **out_devices, size_t *out_count);
// Wraps ort_api->EpDevice_EpName.
const char *EpDeviceEpName(const OrtEpDevice *device);
// Wraps ort_api->EpDevice_EpVendor.
const char *EpDeviceEpVendor(const OrtEpDevice *device);
// Wraps ort_api->SessionOptionsAppendExecutionProvider_V2.
OrtStatus *AppendExecutionProviderV2(OrtSessionOptions *o, OrtEnv *env,
const OrtEpDevice * const *ep_devices, size_t num_ep_devices,
const char **keys, const char **values, size_t num_keys);
// Wraps ort_api->CreateArenaCfg
OrtStatus *CreateArenaCfg(size_t max_mem, int arena_extend_strategy,
int initial_chunk_size_bytes, int max_dead_bytes_per_chunk,
OrtArenaCfg **out);
// Wraps ort_api->CreateArenaCfgV2
OrtStatus *CreateArenaCfgV2(const char *const *arena_config_keys,
const size_t *arena_config_values, size_t num_keys, OrtArenaCfg **out);
// Wraps ort_api->ReleaseArenaCfg
void ReleaseArenaCfg(OrtArenaCfg *ptr);
// Wraps ort_api->CreateAndRegisterAllocator
OrtStatus *CreateAndRegisterAllocator(OrtEnv *env,
const OrtMemoryInfo *mem_info, const OrtArenaCfg *arena_cfg);
// Wraps ort_api->CreateAndRegisterAllocatorV2
OrtStatus *CreateAndRegisterAllocatorV2(OrtEnv *env,
const char *provider_type, const OrtMemoryInfo *mem_info,
const OrtArenaCfg *arena_cfg, const char *const *provider_options_keys,
const char *const *provider_options_values, size_t num_keys);
// Wraps ort_api->RegisterAllocator
OrtStatus *RegisterAllocator(OrtEnv *env, OrtAllocator *allocator);
// Wraps ort_api->UnregisterAllocator
OrtStatus *UnregisterAllocator(OrtEnv *env, const OrtMemoryInfo *mem_info);
// Creates an ORT session using the given model. The given options pointer may
// be NULL; if it is, then we'll use default options.
OrtStatus *CreateSession(void *model_data, size_t model_data_length,
OrtEnv *env, OrtSession **out, OrtSessionOptions *options);
// Like the CreateSession function, but takes a path to a model rather than a
// buffer containing it.
OrtStatus *CreateSessionFromFile(char *model_path, OrtEnv *env,
OrtSession **out, OrtSessionOptions *options);
// Runs an ORT session with the given input and output tensors, along with
// their names.
OrtStatus *RunOrtSession(OrtSession *session,
OrtValue **inputs, char **input_names, int input_count,
OrtValue **outputs, char **output_names, int output_count);
// Runs an ORT session with explicit OrtRunOptions.
OrtStatus *RunOrtSessionWithOptions(OrtSession *session,
OrtValue **inputs, char **input_names, int input_count,
OrtValue **outputs, char **output_names, int output_count,
OrtRunOptions *run_options);
// RunOptions helpers
// Wraps ort_api->CreateRunOptions
OrtStatus *CreateRunOptions(OrtRunOptions **o);
// Wraps ort_api->ReleaseRunOptions
void ReleaseRunOptions(OrtRunOptions *o);
// Wraps ort_api->RunOptionsSetTerminate
OrtStatus *RunOptionsSetTerminate(OrtRunOptions *o);
// Wraps ort_api->RunOptionsUnsetTerminate
OrtStatus *RunOptionsUnsetTerminate(OrtRunOptions *o);
// Wraps ort_api->RunWithBinding.
OrtStatus *RunSessionWithBinding(OrtSession *session, OrtIoBinding *b);
// Wraps ort_api->ReleaseSession
void ReleaseOrtSession(OrtSession *session);
// Wraps ort_api->CreateIoBinding
OrtStatus *CreateIoBinding(OrtSession *session, OrtIoBinding **out);
// Wraps ort_api->ReleaseIoBinding
void ReleaseIoBinding(OrtIoBinding *b);
// Wraps ort_api->BindInput
OrtStatus *BindInput(OrtIoBinding *b, char *name, OrtValue *value);
// Wraps ort_api->BindOutput
OrtStatus *BindOutput(OrtIoBinding *b, char *name, OrtValue *value);
// Wraps ort_api->GetBoundOutputNames. Uses the default allocator. The caller
// must free the buffer and lengths using FreeWithDefaultOrtAllocator after
// this is done.
OrtStatus *GetBoundOutputNames(OrtIoBinding *b, char **buffer,
size_t **lengths, size_t *count);
// Wraps ort_api->GetBoundOutputNames. Uses the default allocator, and the
// caller must free the buffer of values using FreeWithDefaultOrtAllocator.
OrtStatus *GetBoundOutputValues(OrtIoBinding *b, OrtValue ***buffer,
size_t *count);
// Wraps ort_api->ClearBoundInputs.
void ClearBoundInputs(OrtIoBinding *b);
// Wraps ort_api->ClearBoundOutputs.
void ClearBoundOutputs(OrtIoBinding *b);
// Wraps ort_api->SessionGetInputCount.
OrtStatus *SessionGetInputCount(OrtSession *session, size_t *result);
// Wraps ort_api->SessionGetOutputCount.
OrtStatus *SessionGetOutputCount(OrtSession *session, size_t *result);
// Used to free OrtValue instances, such as tensors.
void ReleaseOrtValue(OrtValue *value);
// Creates an OrtValue tensor with the given shape, and backed by the user-
// supplied data buffer.
OrtStatus *CreateOrtTensorWithShape(void *data, size_t data_size,
int64_t *shape, int64_t shape_size, OrtMemoryInfo *mem_info,
ONNXTensorElementDataType dtype, OrtValue **out);
// Creates an OrtValue managed by onnxruntime's default allocator rather than
// using Go-managed memory. Wraps ort_api->CreateTensorAsOrtValue.
OrtStatus *CreateTensorAsOrtValue(int64_t *shape, int64_t shape_size,
ONNXTensorElementDataType dtype, OrtValue **out);
// Wraps ort_api->GetTensorTypeAndShape
OrtStatus *GetTensorTypeAndShape(const OrtValue *value,
OrtTensorTypeAndShapeInfo **out);
// Wraps ort_api->GetDimensionsCount
OrtStatus *GetDimensionsCount(const OrtTensorTypeAndShapeInfo *info,
size_t *out);
// Wraps ort_api->GetDimensions
OrtStatus *GetDimensions(const OrtTensorTypeAndShapeInfo *info,
int64_t *dim_values, size_t dim_values_length);
// Wraps ort_api->GetTensorElementType
OrtStatus *GetTensorElementType(const OrtTensorTypeAndShapeInfo *info,
enum ONNXTensorElementDataType *out);
// Wraps ort_api->ReleaseTensorTypeAndShapeInfo
void ReleaseTensorTypeAndShapeInfo(OrtTensorTypeAndShapeInfo *input);
// Wraps ort_api->GetTensorMutableData
OrtStatus *GetTensorMutableData(OrtValue *value, void **out);
// Wraps ort_api->SessionGetInputName, using the default allocator.
OrtStatus *SessionGetInputName(OrtSession *session, size_t i, char **name);
// Wraps ort_api->SessionGetOutputName, using the default allocator.
OrtStatus *SessionGetOutputName(OrtSession *session, size_t i, char **name);
// Frees anything that was allocated using the default ORT allocator.
OrtStatus *FreeWithDefaultORTAllocator(void *to_free);
// Wraps ort_api->SessionGetInputTypeInfo.
OrtStatus *SessionGetInputTypeInfo(OrtSession *session, size_t i,
OrtTypeInfo **out);
// Wraps ort_api->SessionGetOutputTypeInfo.
OrtStatus *SessionGetOutputTypeInfo(OrtSession *session, size_t i,
OrtTypeInfo **out);
// If the type_info is for a tensor, sets out to the a pointer to the tensor's
// NameAndTypeInfo. Do _not_ free the out pointer; it will be freed when
// type_info is released.
//
// Wraps ort_api->CastTypeInfoToTensorInfo.
OrtStatus *CastTypeInfoToTensorInfo(OrtTypeInfo *type_info,
OrtTensorTypeAndShapeInfo **out);
// Wraps ort_api->GetOnnxTypeFromTypeInfo.
OrtStatus *GetONNXTypeFromTypeInfo(OrtTypeInfo *info, enum ONNXType *out);
// Wraps ort_api->FreeTypeInfo.
void ReleaseTypeInfo(OrtTypeInfo *o);
// Wraps ort_spi->SessionGetModelMetadata.
OrtStatus *SessionGetModelMetadata(OrtSession *s, OrtModelMetadata **out);
// Wraps ort_api->ReleaseModelMetadata.
void ReleaseModelMetadata(OrtModelMetadata *m);
// Wraps ort_api->ModelMetadataGetProducerName, using the default allocator.
OrtStatus *ModelMetadataGetProducerName(OrtModelMetadata *m, char **name);
// Wraps ort_api->ModelMetadataGetGraphName, using the default allocator.
OrtStatus *ModelMetadataGetGraphName(OrtModelMetadata *m, char **name);
// Wraps ort_api->ModelMetadataGetDomain, using the default allocator.
OrtStatus *ModelMetadataGetDomain(OrtModelMetadata *m, char **domain);
// Wraps ort_api->ModelMetadataGetDescription, using the default allocator.
OrtStatus *ModelMetadataGetDescription(OrtModelMetadata *m, char **desc);
// Wraps ort_api->ModelMetadataLookupCustomMetadataMap, using the default
// allocator.
OrtStatus *ModelMetadataLookupCustomMetadataMap(OrtModelMetadata *m, char *key,
char **value);
// Wraps ort_api->ModelMetadataGetCustomMetadataMapKeys, using the default
// allocator.
OrtStatus *ModelMetadataGetCustomMetadataMapKeys(OrtModelMetadata *m,
char ***keys, int64_t *num_keys);
// Wraps ort_api->ModelMetadataGetVersion.
OrtStatus *ModelMetadataGetVersion(OrtModelMetadata *m, int64_t *version);
// Wraps ort_api->GetValue. Uses the default allocator.
OrtStatus *GetValue(OrtValue *container, int index, OrtValue **dst);
// Wraps ort_api->GetValueType.
OrtStatus *GetValueType(OrtValue *v, enum ONNXType *out);
// Wraps ort_api->GetValueCount.
OrtStatus *GetValueCount(OrtValue *v, size_t *out);
// Wraps ort_api->CreateValue to create a map or a sequence.
OrtStatus *CreateOrtValue(OrtValue **in, size_t num_values,
enum ONNXType value_type, OrtValue **out);
// Wraps ort_api->FillStringTensor
OrtStatus *FillStringTensor(OrtValue *v, char **strings, size_t num_strings);
// Wraps ort_api->GetStringTensorDataLength
OrtStatus *GetStringTensorDataLength(OrtValue *v, size_t *length);
// Wraps ort_api->GetStringTensorContent
OrtStatus *GetStringTensorContent(OrtValue *v, void *data_buffer,
size_t data_size, size_t *offsets_buffer, size_t offsets_length);
// Wraps ort_api->FillStringTensorElement
OrtStatus *FillStringTensorElement(OrtValue *v, char *s, size_t index);
// Wraps ort_api->GetStringTensorElementLength
OrtStatus *GetStringTensorElementLength(OrtValue *v, size_t index,
size_t *result);
// Wraps ort_api->GetStringTensorElement
OrtStatus *GetStringTensorElement(OrtValue *v, size_t buffer_length,
size_t index, void *buffer);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // ONNXRUNTIME_WRAPPER_H
+109
View File
@@ -0,0 +1,109 @@
//go:build !windows
package onnxruntime_go
import (
"fmt"
"runtime"
"unsafe"
)
/*
#cgo LDFLAGS: -ldl
#include <dlfcn.h>
#include "onnxruntime_wrapper.h"
typedef OrtApiBase* (*GetOrtApiBaseFunction)(void);
// Since Go can't call C function pointers directly, we just use this helper
// when calling GetApiBase
OrtApiBase *CallGetAPIBaseFunction(void *fn) {
OrtApiBase *to_return = ((GetOrtApiBaseFunction) fn)();
return to_return;
}
*/
import "C"
// This file includes the code for loading the onnxruntime and setting up the
// environment on non-Windows systems. For now, it has been tested on Linux and
// arm64 OSX.
// This will contain the handle to the onnxruntime shared library if it has
// been loaded successfully.
var libraryHandle unsafe.Pointer
func platformCleanup() error {
v, e := C.dlclose(libraryHandle)
if v != 0 {
return fmt.Errorf("Error closing the library: %w", e)
}
return nil
}
// Should only be called on Apple systems; looks up the CoreML provider
// function which should only be exported on apple onnxruntime dylib files.
func setAppendCoreMLFunctionPointer(libraryHandle unsafe.Pointer) error {
// This function name must match the name in coreml_provider_factory.h,
// which is provided in the onnxruntime release's include/ directory on for
// Apple platforms.
fnName := "OrtSessionOptionsAppendExecutionProvider_CoreML"
cFunctionName := C.CString(fnName)
defer C.free(unsafe.Pointer(cFunctionName))
appendCoreMLProviderProc := C.dlsym(libraryHandle, cFunctionName)
if appendCoreMLProviderProc == nil {
msg := C.GoString(C.dlerror())
return fmt.Errorf("Error looking up %s: %s", fnName, msg)
}
C.SetCoreMLProviderFunctionPointer(appendCoreMLProviderProc)
return nil
}
func platformInitializeEnvironment() error {
if onnxSharedLibraryPath == "" {
onnxSharedLibraryPath = "onnxruntime.so"
}
cName := C.CString(onnxSharedLibraryPath)
defer C.free(unsafe.Pointer(cName))
handle := C.dlopen(cName, C.RTLD_LAZY)
if handle == nil {
msg := C.GoString(C.dlerror())
return fmt.Errorf("Error loading ONNX shared library \"%s\": %s",
onnxSharedLibraryPath, msg)
}
cFunctionName := C.CString("OrtGetApiBase")
defer C.free(unsafe.Pointer(cFunctionName))
getAPIBaseProc := C.dlsym(handle, cFunctionName)
if getAPIBaseProc == nil {
C.dlclose(handle)
msg := C.GoString(C.dlerror())
return fmt.Errorf("Error looking up OrtGetApiBase in \"%s\": %s",
onnxSharedLibraryPath, msg)
}
ortAPIBase := C.CallGetAPIBaseFunction(getAPIBaseProc)
tmp := C.SetAPIFromBase((*C.OrtApiBase)(unsafe.Pointer(ortAPIBase)))
if tmp != 0 {
C.dlclose(handle)
return fmt.Errorf("Error setting ORT API base: %d", tmp)
}
if (runtime.GOOS == "darwin") || (runtime.GOOS == "ios") {
setAppendCoreMLFunctionPointer(handle)
// We'll silently ignore potential errors returned by
// setAppendCoreMLFunctionPointer (for now at least). Even though we're
// on Apple hardware, it's possible that the user will have compiled
// the onnxruntime library from source without CoreML support.
// A failure here will only leave the coreml function pointer as NULL
// in our C code, which will be detected and result in an error at
// runtime.
}
libraryHandle = handle
return nil
}
// Converts the given path to an ORTCHAR_T string, pointed to by a *C.char. The
// returned string must be freed using C.free when no longer needed. This
// wrapper is used for source compatibility with onnxruntime API functions
// requiring paths, which must be UTF-16 on Windows but UTF-8 elsewhere.
func createOrtCharString(str string) (*C.char, error) {
return C.CString(str), nil
}
+103
View File
@@ -0,0 +1,103 @@
//go:build windows
package onnxruntime_go
// This file includes the Windows-specific code for loading the onnxruntime
// library and setting up the environment.
import (
"fmt"
"syscall"
"unicode/utf16"
"unicode/utf8"
"unsafe"
)
// #include "onnxruntime_wrapper.h"
import "C"
// This will contain the handle to the onnxruntime dll if it has been loaded
// successfully.
var libraryHandle syscall.Handle
func platformCleanup() error {
e := syscall.FreeLibrary(libraryHandle)
libraryHandle = 0
return e
}
func platformInitializeEnvironment() error {
if onnxSharedLibraryPath == "" {
onnxSharedLibraryPath = "onnxruntime.dll"
}
handle, e := syscall.LoadLibrary(onnxSharedLibraryPath)
if e != nil {
return fmt.Errorf("Error loading ONNX shared library \"%s\": %w",
onnxSharedLibraryPath, e)
}
getApiBaseProc, e := syscall.GetProcAddress(handle, "OrtGetApiBase")
if e != nil {
syscall.FreeLibrary(handle)
return fmt.Errorf("Error finding OrtGetApiBase function in %s: %w",
onnxSharedLibraryPath, e)
}
ortApiBase, _, e := syscall.SyscallN(uintptr(getApiBaseProc), 0)
if ortApiBase == 0 {
syscall.FreeLibrary(handle)
if e != nil {
return fmt.Errorf("Error calling OrtGetApiBase: %w", e)
} else {
return fmt.Errorf("Error calling OrtGetApiBase")
}
}
tmp := C.SetAPIFromBase((*C.OrtApiBase)(unsafe.Pointer(ortApiBase)))
if tmp != 0 {
syscall.FreeLibrary(handle)
return fmt.Errorf("Error setting ORT API base: %d", tmp)
}
libraryHandle = handle
return nil
}
// Converts the given string to a UTF-16 string, pointed to by a raw
// *C.char. Note that we actually keep ORTCHAR_T defined to char even
// on Windows, so do _not_ index into this string from Cgo code and expect to
// get correct characters! Instead, this should only be used to obtain pointers
// that are passed to onnxruntime windows DLL functions expecting ORTCHAR_T*
// args. This is required because we undefine _WIN32 for cgo compatibility when
// including onnxruntime_c_api.h, but still interact with a DLL that was
// compiled assuming _WIN32 was defined.
//
// The pointer returned by this function must still be freed using C.free when
// no longer needed. This will return an error if the given string contains
// non-UTF8 characters.
func createOrtCharString(str string) (*C.char, error) {
src := []uint8(str)
// Assumed common case: the utf16 buffer contains one uint16 per utf8 byte
// plus one more for the required null terminator in the C buffer.
dst := make([]uint16, 0, len(src)+1)
// Convert UTF-8 to UTF-16 by reading each subsequent rune from src and
// appending it as UTF-16 to dst.
for len(src) > 0 {
r, size := utf8.DecodeRune(src)
if r == utf8.RuneError {
return nil, fmt.Errorf("Invalid UTF-8 rune found in \"%s\"", str)
}
src = src[size:]
dst = utf16.AppendRune(dst, r)
}
// Make sure dst contains the null terminator. Additionally this will cause
// us to return an empty string if the original string was empty.
dst = append(dst, 0)
// Finally, we need to copy dst into a C array for compatibility with
// C.CString.
toReturn := C.calloc(C.size_t(len(dst)), 2)
if toReturn == nil {
return nil, fmt.Errorf("Error allocating buffer for the utf16 string")
}
C.memcpy(toReturn, unsafe.Pointer(&(dst[0])), C.size_t(len(dst))*2)
return (*C.char)(toReturn), nil
}
+56
View File
@@ -0,0 +1,56 @@
package onnxruntime_go
// This file contains definitions for the generic tensor data types we support.
// #include "onnxruntime_wrapper.h"
import "C"
import (
"reflect"
)
type FloatData interface {
~float32 | ~float64
}
type IntData interface {
~int8 | ~uint8 | ~int16 | ~uint16 | ~int32 | ~uint32 | ~int64 | ~uint64
}
// This is used as a type constraint for the generic Tensor type.
type TensorData interface {
FloatData | IntData | ~bool
}
// Returns the ONNX enum value used to indicate TensorData type T.
func GetTensorElementDataType[T TensorData]() C.ONNXTensorElementDataType {
// Sadly, we can't do type assertions to get underlying types, so we need
// to use reflect here instead.
var v T
kind := reflect.ValueOf(v).Kind()
switch kind {
case reflect.Float64:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE
case reflect.Float32:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT
case reflect.Int8:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8
case reflect.Uint8:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8
case reflect.Int16:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16
case reflect.Uint16:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT16
case reflect.Int32:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32
case reflect.Uint32:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32
case reflect.Int64:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64
case reflect.Uint64:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64
case reflect.Bool:
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL
}
return C.ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED
}