Skip to content

Experimental C API support#28746

Merged
edgchen1 merged 28 commits into
mainfrom
edgchen1/experimental_c_api
Jun 10, 2026
Merged

Experimental C API support#28746
edgchen1 merged 28 commits into
mainfrom
edgchen1/experimental_c_api

Conversation

@edgchen1

@edgchen1 edgchen1 commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Description

This pull request introduces a mechanism for exposing experimental C API functions in ONNX Runtime. The new system enables the addition, iteration, and eventual promotion of experimental APIs without impacting the stable ABI, using a name-based function pointer lookup and a generated header for type safety and ergonomics. The changes include documentation, build integration, header generation, implementation, and test coverage for the new experimental API flow.

Experimental C API Framework

  • Added a design doc (Experimental_C_API.md) detailing the motivation, design decisions, and usage patterns for the experimental C API mechanism.
  • Introduced a central declaration file (onnxruntime_experimental_c_api.inc) using X-macros to define experimental API functions and their lifecycle rules. The X-macro signature uses ORT_EXPERIMENTAL_API(VER, RET, NAME, ...) ordering (return type before name) to match the convention used by ORT_API_T in the stable API.
  • Added a generated consumer header (onnxruntime_experimental_c_api.h) that provides C typedefs, name constants, and C++ typed accessors for experimental functions. Experimental function names follow the pattern <TargetStruct>_<Name>_SinceV<APIVersion> to unambiguously convey availability and avoid collision.
  • Updated the stable C API struct (OrtApi in onnxruntime_c_api.h) to include a single function pointer, GetExperimentalFunction, for name-based experimental function lookup. The OrtExperimentalFnPtr generic function pointer type (rather than void*) is used as the return type to avoid undefined behavior when casting between function pointers.
  • Integrated the new headers into the build system so they are installed and available to consumers.

Implementation and Test Coverage

  • Implemented the runtime support for experimental API lookup and function registration (experimental_c_api.cc), including a test-only function (OrtApi_ExperimentalApiTest) to exercise the mechanism end-to-end.
  • Registered the new experimental API entry point in the exported API table (onnxruntime_c_api.cc).
  • Added a unit test source file for experimental API coverage.

Motivation and Context

Enable support for experimental C APIs.

edgchen1 and others added 13 commits May 29, 2026 13:00
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
… .inc

- Use ExpSinceV<version>_<TargetStruct>_<Name> naming convention
- Version prefix guarantees uniqueness, eliminating need for retired .inc
- Merge C and C++ headers into single file with #ifdef __cplusplus guard
- C++ accessors reuse C typedefs directly (no duplicate typedef)
- Add SinceVersion as first X-macro argument for mechanical name construction

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Implement a single stable OrtApi entry point (GetExperimentalFunction) that retrieves experimental function pointers by name. This allows new APIs to be iterated on before promotion to the stable ABI surface, with minimal stable API cost (one slot).

- Add OrtExperimentalFnPtr typedef and GetExperimentalFunction slot to OrtApi
- Add X-macro .inc file as single source of truth for experimental functions
- Add consumer header with C typedefs, name constants, and C++ typed accessors
- Add runtime registration table with linear scan lookup in experimental_c_api.cc
- Add test-only OrtApi_ExperimentalApiTest function to exercise the mechanism
- Add shared_lib tests for lookup (null/unknown/known name, typed call, consistency)
- Wire new public headers into CMake packaging (onnxruntime.cmake)
- Wire test file into onnxruntime_unittests.cmake

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Align file names, _FnName suffix, and namespace syntax in code examples with the actual implementation.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
The macro name now matches the naming convention used by the generated symbols (which all use Fn/FnName suffixes to describe what they are, while the macro describes an API entry).

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…_c_api.cc

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can commit the suggested changes from lintrunner.

Comment thread include/onnxruntime/core/session/onnxruntime_experimental_c_api.h Outdated
Comment thread include/onnxruntime/core/session/onnxruntime_experimental_c_api.h Outdated
Comment thread include/onnxruntime/core/session/onnxruntime_experimental_c_api.h Fixed
Comment thread include/onnxruntime/core/session/onnxruntime_experimental_c_api.inc Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a name-based experimental C API mechanism for ONNX Runtime. A single new stable OrtApi::GetExperimentalFunction(name) slot is added; experimental functions are declared centrally in an X-macro .inc file that is expanded by a consumer header (to produce C typedefs/name constants and C++ typed accessors) and by the runtime registration table. A test-only experimental function plus design doc and unit tests are included.

Changes:

  • New stable API entry GetExperimentalFunction plus OrtExperimentalFnPtr typedef; runtime implementation with a name-keyed lookup table populated from onnxruntime_experimental_c_api.inc.
  • Generated consumer header onnxruntime_experimental_c_api.h providing C typedefs/name constants and Ort::Experimental::Get_* C++ accessors via X-macro expansion.
  • Design doc, build/install plumbing for the new headers, and a shared-lib gtest suite exercising null/unknown/empty/known lookups and end-to-end call.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.

Show a summary per file
File Description
docs/design/Experimental_C_API.md New design document explaining motivation, alternatives, and lifecycle rules.
docs/design/readme.md Brief readme describing the design docs directory.
include/onnxruntime/core/session/onnxruntime_c_api.h Adds OrtExperimentalFnPtr typedef and GetExperimentalFunction slot to OrtApi.
include/onnxruntime/core/session/onnxruntime_experimental_c_api.h New consumer header expanding the X-macro into typedefs/name constants and C++ accessors.
include/onnxruntime/core/session/onnxruntime_experimental_c_api.inc Central X-macro declaration list with one test-only experimental entry.
onnxruntime/core/session/ort_apis.h Declares OrtApis::GetExperimentalFunction.
onnxruntime/core/session/onnxruntime_c_api.cc Wires GetExperimentalFunction into the ort_api_1_to_27 table.
onnxruntime/core/session/experimental_c_api.cc Implements the registration table, lookup function, and the test experimental function.
onnxruntime/test/shared_lib/test_experimental_api.cc New gtest suite for null/unknown/empty/known lookup and end-to-end call.
cmake/onnxruntime.cmake Installs the new experimental headers (.h and .inc) as public API.
cmake/onnxruntime_unittests.cmake Adds test_experimental_api.cc to the shared-lib test sources.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@edgchen1 edgchen1 marked this pull request as ready for review June 2, 2026 17:28
@skottmckay

skottmckay commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Will we enable other language bindings on demand?

There's a few things to consider for C# to make this more usable if we want to enable that now. e.g. the native handle for ORT types exposed in the C# bindings is internal, so there's no way to pass one of those objects in to an experimental function. if I had a C# OrtValue instance I couldn't use that as an arg to the experimental function as you'd need to pass the IntPtr for the handle in. The helper to check an OrtStatus was successful is also internal.

Comment thread include/onnxruntime/core/session/onnxruntime_c_api.h Outdated
Comment thread include/onnxruntime/core/session/onnxruntime_experimental_c_api.h Outdated
Comment thread onnxruntime/test/shared_lib/test_experimental_api.cc Outdated
Comment thread include/onnxruntime/core/session/onnxruntime_experimental_c_api.inc

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Comment thread onnxruntime/core/session/onnxruntime_c_api.cc
Comment thread include/onnxruntime/core/session/onnxruntime_c_api.h Outdated
Comment thread onnxruntime/core/session/ort_apis.h
Comment thread onnxruntime/core/session/experimental_c_api.cc
Comment thread include/onnxruntime/core/session/onnxruntime_experimental_c_api.inc Outdated
edgchen1 and others added 7 commits June 9, 2026 14:23
- Shorten generated names: ExpSinceV<ver> -> V<ver> throughout

- Reorder ORT_EXPERIMENTAL_API macro params: (VER, NAME, RET, ...) -> (VER, RET, NAME, ...) to match ORT_API_T convention

- Add comment on OrtExperimentalFnPtr explaining why it is a function pointer rather than void* (casting between function pointers and void* is UB)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Link to AGENTS.md for codebase conventions and document that ORT_API_VERSION bumps, new ort_api tables, and static_assert updates happen only during release preparation, not when individual APIs are added.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Change the version suffix in experimental API names from _V<ver> to _SinceV<ver> to avoid ambiguity (_V27 could be misread as version 2 of function 7). The _SinceV suffix clearly conveys 'introduced in API version N'.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
ORT_API_VERSION was bumped to 28 in main. Update the experimental API test function and all comments/examples from SinceV27 to SinceV28.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Add warning that SinceVersion must be a numeric literal, not a macro

- Add lifecycle note: test function is kept permanently for regression coverage

- Add comment noting C++ accessor nullptr path is covered by C-side test

- Use ORT_API_T macro for GetExperimentalFunction declaration

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Comment thread onnxruntime/test/shared_lib/test_experimental_api.cc
@edgchen1

Copy link
Copy Markdown
Contributor Author

Will we enable other language bindings on demand?

There's a few things to consider for C# to make this more usable if we want to enable that now. e.g. the native handle for ORT types exposed in the C# bindings is internal, so there's no way to pass one of those objects in to an experimental function. if I had a C# OrtValue instance I couldn't use that as an arg to the experimental function as you'd need to pass the IntPtr for the handle in. The helper to check an OrtStatus was successful is also internal.

I think other language bindings can be enabled later, on demand. is there anything with the existing setup that would make things more difficult for supporting C# later?

Comment thread include/onnxruntime/core/session/onnxruntime_experimental_c_api.inc Outdated
@edgchen1 edgchen1 merged commit 0f30014 into main Jun 10, 2026
86 of 87 checks passed
@edgchen1 edgchen1 deleted the edgchen1/experimental_c_api branch June 10, 2026 16:09
jambayk added a commit that referenced this pull request Jun 10, 2026
Move the model package C surface off the stable OrtApi onto the
experimental name-based lookup added in #28746. Each function is
registered individually in onnxruntime_experimental_c_api.inc with
the OrtModelPackageApi_ prefix and the _SinceV28 version suffix,
matching the lifecycle rules in docs/design/Experimental_C_API.md.

- Drop the OrtModelPackageApi struct, OrtApi::GetModelPackageApi,
  the OrtModelPackageAPI namespace, model_package_api.h, and the
  C++ wrappers/release glue in onnxruntime_cxx_api.h.
- Move the OrtModelPackageOptions/Context/ComponentContext opaque
  handle decls into onnxruntime_experimental_c_api.h.
- Add forward decls in experimental_c_api.cc so the registration
  table can take addresses of bodies defined in model_package_api.cc.
- Rename impls into namespace OrtExperimentalApis with the
  _SinceV28 suffix; bodies unchanged.
- Drop the Python bindings; per the design doc we start the
  experimental API in C/C++ only and prove it out before exposing
  it to Python.
- Update the autoep gtest to use a local ModelPackageFns struct
  populated through Ort::Experimental::Get_*_Fn lookups.
- Rewrite onnxruntime/core/session/model_package/README.md for the
  experimental API surface.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GopalakrishnanN pushed a commit that referenced this pull request Jun 10, 2026
Convert the six EPContext read/write callback C APIs from stable APIs to experimental APIs using the mechanism introduced in PR #28746:

- OrtApi_SessionOptions_SetEpContextDataReadFunc
- OrtCompileApi_ModelCompilationOptions_SetEpContextDataWriteFunc
- OrtEpApi_SessionOptions_GetEpContextConfig
- OrtEpApi_ReleaseEpContextConfig
- OrtEpApi_EpContextConfig_GetEpContextDataReadFunc
- OrtEpApi_EpContextConfig_GetEpContextDataWriteFunc

Remove the C++ convenience wrappers and move the auxiliary types (OrtEpContextConfig, OrtReadNamedBufferFunc, OrtWriteNamedBufferFunc) into onnxruntime_experimental_c_api.h. Update the example plugin EP, sample helper utilities, and tests to use the generated experimental accessors.
GopalakrishnanN pushed a commit that referenced this pull request Jun 10, 2026
Convert the six EPContext read/write callback C APIs from stable APIs to experimental APIs using the mechanism introduced in PR #28746:

- OrtApi_SessionOptions_SetEpContextDataReadFunc
- OrtCompileApi_ModelCompilationOptions_SetEpContextDataWriteFunc
- OrtEpApi_SessionOptions_GetEpContextConfig
- OrtEpApi_ReleaseEpContextConfig
- OrtEpApi_EpContextConfig_GetEpContextDataReadFunc
- OrtEpApi_EpContextConfig_GetEpContextDataWriteFunc

Remove the C++ convenience wrappers and move the auxiliary types (OrtEpContextConfig, OrtReadNamedBufferFunc, OrtWriteNamedBufferFunc) into onnxruntime_experimental_c_api.h. Update the example plugin EP, sample helper utilities, and tests to use the generated experimental accessors.
jambayk added a commit that referenced this pull request Jun 11, 2026
### Description

Move the existing model package C API off the stable `OrtApi` onto the
experimental name-based lookup mechanism added in #28746. Each model
package function is registered individually in
`include/onnxruntime/core/session/onnxruntime_experimental_c_api.inc`
with the `OrtModelPackageApi_` prefix and the `_SinceV28` version
suffix, following the lifecycle rules in
`docs/design/Experimental_C_API.md`.

Headline changes:

- `OrtApi::GetModelPackageApi`, the `OrtModelPackageApi` struct,
`OrtApis::GetModelPackageApi`, the `OrtModelPackageAPI` namespace,
`onnxruntime/core/session/model_package_api.h`, and the C++ wrappers
(`Ort::GetModelPackageApi`,
`ORT_DEFINE_RELEASE_FROM_API_STRUCT(ModelPackage*)`,
`ModelPackageOptions/Context/ComponentContext`) are removed.
- Opaque handle types (`OrtModelPackageOptions`,
`OrtModelPackageContext`, `OrtModelPackageComponentContext`) move into
`onnxruntime_experimental_c_api.h`.
- All 15 model package functions are registered in
`onnxruntime_experimental_c_api.inc`. Impls move into `namespace
OrtExperimentalApis` with `_SinceV28`-suffixed names in
`model_package_api.cc`; bodies are unchanged.
- `experimental_c_api.cc` gains a forward-decl block (driven by the same
`.inc` X-macro) so the auto-generated registration table can take the
address of every entry, even those defined in `model_package_api.cc`.
- The Python bindings (`PyModelPackageContext` / `PyModelPackageOptions`
/ `PyModelPackageComponentContext` and their `onnxruntime.__init__`
exports) are removed. Per the design doc we start the experimental API
in C/C++ only.
- `onnxruntime/test/autoep/test_model_package.cc` switches to a local
`ModelPackageFns` struct populated through the
`Ort::Experimental::Get_OrtModelPackageApi_*_Fn(api)` typed accessors.

Consumer usage going forward, in C++:

```cpp
#include "onnxruntime_c_api.h"
#include "onnxruntime_experimental_c_api.h"

const OrtApi* ort = OrtGetApiBase()->GetApi(ORT_API_VERSION);

if (auto* fn = Ort::Experimental::Get_OrtModelPackageApi_CreateModelPackageContext_SinceV28_Fn(ort)) {
  OrtModelPackageContext* ctx = nullptr;
  Ort::ThrowOnError(fn(ORT_TSTR("/path/to/pkg"), &ctx));
  // ...
}
```

### Motivation and Context

The model package API was added to the stable `OrtApi` in 1.27 but has
not shipped in a release yet. Now that #28746 has landed the
experimental C API framework, the right home for an iterating preview
surface like model package is behind `OrtApi::GetExperimentalFunction`,
not on the stable struct.

Moving it to experimental:

- frees us to change signatures (each name is uniquely versioned)
without breaking the stable ABI;
- gives consumers a clear "is this specific thing available?" contract
instead of a struct that *looks* stable but isn't;
- lets the surface be promoted to stable cleanly later (move entries to
`OrtApi`, drop the `_SinceV<N>` suffix, remove the experimental
entries).

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GopalakrishnanN pushed a commit that referenced this pull request Jun 12, 2026
Convert the six EPContext read/write callback C APIs from stable APIs to experimental APIs using the mechanism introduced in PR #28746:

- OrtApi_SessionOptions_SetEpContextDataReadFunc
- OrtCompileApi_ModelCompilationOptions_SetEpContextDataWriteFunc
- OrtEpApi_SessionOptions_GetEpContextConfig
- OrtEpApi_ReleaseEpContextConfig
- OrtEpApi_EpContextConfig_GetEpContextDataReadFunc
- OrtEpApi_EpContextConfig_GetEpContextDataWriteFunc

Remove the C++ convenience wrappers and move the auxiliary types (OrtEpContextConfig, OrtReadNamedBufferFunc, OrtWriteNamedBufferFunc) into onnxruntime_experimental_c_api.h. Update the example plugin EP, sample helper utilities, and tests to use the generated experimental accessors.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants