Development#
Build against onnx-light main#
The default CMake configuration fetches onnx-light’s main branch.
Python bindings are disabled for native-only builds; Python test options
automatically enable the matching onnx-light model bindings. Upstream tests,
benchmarks and built-in operator kernels remain disabled.
The outgoing common library compiles only
the existing LeakyRelu kernel source alongside the core; unused targets are
excluded from the default build.
Plugin builds additionally fetch onnx-light-cpu at
054cdd984d9f85a7692dc4f678b2f13275e8ede1 and configure only its standalone
ml_cpu_compute subproject. No onnx-light-cpu Python package or additional
onnx-light build is needed. Its runtime SIMD dispatch remains enabled; do not
add target-wide native/AVX compiler flags. To supply that same source checkout,
set FETCHCONTENT_SOURCE_DIR_ONNX_LIGHT_CPU=/path/to/onnx-light-cpu.
Dependency headers are treated as system headers; warnings remain errors in
this project’s own sources.
Set Python3_EXECUTABLE to select an interpreter explicitly. The same
interpreter is forwarded to the onnx-light bindings build.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel "$(nproc)"
ctest --test-dir build --output-on-failure
On Windows or other multi-configuration generators, also pass
--config Release to the build and -C Release to CTest.
On macOS use sysctl -n hw.logicalcpu in place of nproc.
Keep one build tree; reconfigure it rather than maintaining stale parallel
compiled copies.
Build either direction independently:
cmake -S . -B build -DONNX_LIGHT_ORT_BUILD_HOST=ON \
-DONNX_LIGHT_ORT_BUILD_PLUGIN=OFF
cmake --build build --parallel "$(nproc)"
ctest --test-dir build --output-on-failure
Reverse the two options for a plugin-only build; both are enabled by default.
The plugin option selects custom_ops, both *_light_to_ort bridges and
common_light_to_ort. The host option selects both *_ort_to_light bridges
and common_ort_to_light. Unimplemented EP bridges remain interface targets;
they do not acquire fake runtime implementations just by being enabled.
The EP entry-point library will have its own target when implemented.
ONNX_LIGHT_ORT_BUILD_TESTS=OFF disables native integration tests.
When switching to a host-only build, also turn
ONNX_LIGHT_ORT_TEST_WITH_ORT=OFF if previously enabled.
To use an existing checkout explicitly:
git -C /path/to/onnx-light fetch origin main
cmake -S . -B build \
-DFETCHCONTENT_SOURCE_DIR_ONNX_LIGHT=/path/to/onnx-light
The override uses the checkout exactly as supplied and does not switch
branches. Ensure it contains the desired main revision; CMake logs its HEAD.
CI explicitly checks out upstream main and passes this override so its
resolved commit appears in the job logs. Fresh CI runs and the daily schedule
exercise new upstream main changes without a release.
Component tests and examples#
Each implemented component owns its native tests. Select CTest labels
custom_ops, bridge_ops_light_called_by_ort, common_light_to_ort or
common_ort_to_light or bridge_ops_ort_called_by_light to run a component’s tests.
The unit label selects native unit suites. Outgoing units use a minimal
explicit C API host, not a mocking framework or an ORT installation. Incoming
native tests load an independent ORT LeakyRelu custom-op library into the real standalone
host; the dependency-contract smoke test is retained. EP bridges and the EP
entry-point library have no executable tests.
See Projects for each component’s page and precise coverage.
The C++ custom-op example is built by default when plugins are enabled,
without linking ORT. ONNX_LIGHT_ORT_BUILD_EXAMPLES=OFF disables it.
Both Custom ops examples run inference in a real ORT host.
To additionally execute the C++ example through CTest, pass an existing runtime:
cmake -S . -B build -DONNX_LIGHT_ORT_TEST_WITH_ORT=ON \
-DONNX_LIGHT_ORT_RUNTIME_LIBRARY=/absolute/path/to/libonnxruntime.so
cmake --build build --parallel "$(nproc)"
ctest --test-dir build -L example --output-on-failure
Test in a real ORT host#
The native build never needs an ORT runtime. Enable the separate integration tests explicitly with Python 3.12 or later:
python -m pip install -r requirements/ort-tests.txt
cmake -S . -B build -DONNX_LIGHT_ORT_BUILD_PLUGIN=ON \
-DONNX_LIGHT_ORT_BUILD_TESTS=ON -DONNX_LIGHT_ORT_TEST_WITH_ORT=ON
cmake --build build --parallel "$(nproc)"
ctest --test-dir build --output-on-failure
The tests build models with custom domain onnx_light, opset 1, operator
LeakyRelu and an explicit float alpha. They load the produced shared
library with SessionOptions.register_custom_ops_library and verify repeated
dynamic/scalar/empty shapes, read-only input preservation, preallocated output
buffers, independent sessions, and invalid attributes, arity, types, rank and
alignment or overlapping buffers. Expected values come from NumPy, not a
substitute native kernel.
They also execute onnx_light_cpu::Log and check its special values and SIMD
tails against a NumPy float64 reference, rounded to float32, with relative
tolerance 2e-6 and zero absolute tolerance.
Both operators also run in float16, bfloat16 and float64 through real ORT and
the standalone host, preserving dtype. The float64 cases include values
that would lose precision or overflow if routed through float32.
On Linux the loadable library is
build/onnx_light_ort/custom_ops/libonnx_light_ort_custom_ops.so.
CTest resolves the platform-specific path from the custom-op target, including
multi-configuration build directories.
The real-host CI job uses ORT
1.18.1 with NumPy below 2 to exercise the requested API-18 baseline.
Models are created and checked with onnx_light.onnx, never the onnx
Python package.
Documentation and style#
Sphinx builds the matching onnx-light Python bindings and native gallery
libraries in the existing build tree, then executes both gallery examples.
The standard command below also works from a fresh checkout without setting
PYTHONPATH or library environment variables. It requires Python 3.12 or later,
a C++20 compiler, Git and network access to fetch the native dependencies.
No local project artifacts are installed into site-packages.
python -m pip install -r requirements/style.txt -r docs/requirements.txt
black . && ruff check .
git ls-files -z '*.cc' '*.cpp' '*.h' '*.hpp' | xargs -0 clang-format -i
git ls-files -z '*.cc' '*.cpp' '*.h' '*.hpp' | xargs -0 clang-format --dry-run --Werror
python -m sphinx -b html -W --keep-going docs build/docs
The build and style tools ignore downloaded dependencies and generated output. Native tests use the real onnx-light core without mocking libraries or an installed Python package. Reverse-direction units use explicit test-owned opaque values and API callbacks. Nothing is installed into site-packages by the native build.
Standalone Python custom-op tests#
Use the source checkout through PYTHONPATH; do not install the project.
The incoming host uses NumPy and the onnx-light Python model bindings,
not the onnx package or an ONNX Runtime installation:
python -m pip install -r requirements/host-tests.txt
cmake -S . -B build -DONNX_LIGHT_ORT_BUILD_HOST=ON \
-DONNX_LIGHT_ORT_BUILD_PLUGIN=OFF -DONNX_LIGHT_ORT_TEST_WITH_ORT=OFF \
-DONNX_LIGHT_ORT_TEST_PYTHON=ON
cmake --build build --parallel "$(nproc)"
ctest --test-dir build -L bridge_ops_ort_called_by_light --output-on-failure
The build places the onnx-light model package under build/python and CTest
adds it to PYTHONPATH. It uses the same source revision as the native host;
no project artifacts are installed into site-packages. For direct Python use,
set PYTHONPATH="$PWD:$PWD/build/python:$PYTHONPATH".
On Windows, CTest additionally registers the native test PATH directories
with os.add_dll_directory for the lifetime of each Python script. Python
3.8 and later do not search PATH when loading extension-module dependencies.
This includes external DLLs needed by the onnx-light libraries, not just the
libraries placed under build/python. Direct Windows invocations can use
python cmake/run_python_with_dll_paths.py path/to/script.py ... as well.
CustomOpSession accepts an onnx-light ModelProto or serialized model
bytes and explicit plugin/host library
paths. Its audited single-node floating-point profile is documented in
Custom-op bridge: ORT custom ops called by onnx-light; it is not a general plugin host.
Executable Python gallery#
The Examples gallery gallery runs both custom-op directions. Sphinx prepares its prerequisites automatically. To also run the integration tests or execute the scripts directly on Linux, build both sides and set the three library paths:
python -m pip install -r docs/requirements.txt
cmake -S . -B build -DONNX_LIGHT_ORT_BUILD_HOST=ON \
-DONNX_LIGHT_ORT_BUILD_PLUGIN=ON -DONNX_LIGHT_ORT_TEST_PYTHON=ON \
-DONNX_LIGHT_ORT_TEST_WITH_ORT=ON
cmake --build build --parallel "$(nproc)"
ctest --test-dir build --output-on-failure
export PYTHONPATH="$PWD:$PWD/build/python:$PYTHONPATH"
export ONNX_LIGHT_ORT_PLUGIN_LIBRARY="$PWD/build/onnx_light_ort/custom_ops/libonnx_light_ort_custom_ops.so"
export ONNX_LIGHT_ORT_HOST_LIBRARY="$PWD/build/onnx_light_ort/bridge_ops_ort_called_by_light/libonnx_light_ort_bridge_ops_ort_called_by_light.so"
export ONNX_LIGHT_ORT_INCOMING_CUSTOM_OP_LIBRARY="$PWD/build/onnx_light_ort/bridge_ops_ort_called_by_light/libonnx_light_ort_ort_custom_ops.so"
python -m sphinx -b html -W --keep-going docs build/docs
On macOS use the corresponding .dylib paths; on Windows use the .dll
paths under the selected build configuration. CTest resolves these paths
automatically. The gallery_custom_ops_light_called_by_ort and
gallery_custom_ops_ort_called_by_light
tests execute the same gallery scripts in separate Python processes.
The incoming example never imports ORT; the outgoing example uses a real
ORT session. No EP is involved, and failures are not skipped or hidden.
Sphinx builds only the model bindings and the three gallery libraries, not the native tests. Existing CMake dependency-source overrides are preserved, and explicitly supplied gallery library environment variables take precedence.
The gallery_benchmark_log_custom_ops test executes the Log benchmark gallery.
It compares NumPy, all four synchronous ORT calling interfaces with built-in
and CPU custom operators, and the standalone single-node host. It uses one
Log or ten consecutive Logs, checks results before and after timing, and
reports median microseconds per graph over several input sizes. Ten Logs
produce NaNs in float32; this measures the literal chain, including special
values. The standalone host cannot execute that topology and is marked
unavailable. Measurements run in separate processes to keep ORT out of the
standalone host. Use the same library environment variables shown above.
All benchmark code lives in docs/examples/plot_benchmark_log_custom_ops.py,
including model construction, timing, isolated workers and the CLI entry point.
The command-line benchmark also accepts --nodes 1|10 and
--api run|ortvalues|iobinding|ortvaluevector.
CI and documentation publishing#
Native CI covers Linux, Windows and macOS, including host-only, plugin-only
and combined configurations. It uses a compiler cache, cancels superseded
branch runs, and builds against upstream main. A Linux check rejects an ORT
shared-library dependency in the native test executable and plugin library.
Real-host tests run in a separate Linux job; host-only jobs do not install ORT.
Release publication is handled separately by .github/workflows/releases.yml;
ordinary native CI does not create releases.
Tagged releases#
The Releases workflow starts automatically when a tag is pushed.
For version 0.2.0, both 0.2.0 and v0.2.0 are accepted. It checks that the
tag, CMake project, Python metadata and __version__ agree before building.
It resolves onnx-light’s main revision once and uses that immutable commit in
every release job; onnx-light-cpu remains independently pinned. Each package
includes release-build-info.txt and the dependency licenses.
The targets match onnx-light’s release matrix:
Platform |
Architectures |
CPython wheels |
|---|---|---|
Linux, manylinux 2.28 |
x86_64, aarch64 |
3.12, 3.13, 3.14 |
Windows |
AMD64, ARM64 |
3.12, 3.13, 3.14 |
macOS 13.3+ |
universal2 (arm64 + x86_64) |
3.12, 3.13, 3.14 |
There are fifteen wheels and five native C++ archives. Native archives use
Ubuntu 24.04 on Linux; they are not the portable manylinux wheels.
Windows archives are ZIP files; Linux and macOS archives are gzip-compressed
tar files. All builds enable both custom-op directions and use all available
processors. No ORT runtime or onnx Python package is bundled.
Native archive builds disable Python and optional OpenSSL support. They contain the two shared libraries with statically linked onnx-light/CPU dependencies, public host and ORT API headers, and a relocatable CMake package. Each job moves the installation and builds/runs an independent downstream consumer:
find_package(onnx_light_ort 0.2 CONFIG REQUIRED)
target_link_libraries(my_host PRIVATE onnx_light_ort::bridge_ops_ort_called_by_light)
onnx_light_ort::custom_ops is the installed plugin target.
Wheels bundle the host, plugin and their native runtime dependencies under
onnx_light_ort/_native. Bundled dependency libraries use private names to
avoid ABI collisions with a separately installed onnx-light model package.
The matching onnx-light model bindings are built
in the same tree for wheel smoke tests, but are not copied into this package.
The tests load the installed libraries first and execute LeakyRelu and CPU Log
without ORT. Dependency repair uses auditwheel, delvewheel or delocate as
appropriate; Windows repair preserves already bundled DLLs.
Success on one platform does not publish a partial release: publication waits
for every wheel and native job, then attaches all artifacts and SHA256SUMS.
A retry can replace artifacts on the same release.
workflow_dispatch without a tag builds and tests artifacts without
publishing. With an existing tag it can retry a release. This workflow publishes
to GitHub Releases, not PyPI; pushing a tag is an explicit maintainer action.
To build a wheel locally without installing it, use the existing build tree.
Set CMAKE_GENERATOR to its current generator (Unix Makefiles in this
Linux example), rather than creating another compiled tree:
CMAKE_GENERATOR="Unix Makefiles" CMAKE_BUILD_PARALLEL_LEVEL="$(nproc)" \
python -m pip wheel . --no-deps -w build/wheelhouse
For source-checkout work, continue using PYTHONPATH rather than installing
local artifacts. Wheel builds reconfigure build; restore the desired native
options and -DSKBUILD=OFF before returning to a plain CMake development build.
Daily coverage#
The Coverage workflow runs every day at 07:00 UTC on main and can
also be started manually. It builds both native directions with GCC coverage
instrumentation and runs all native CTest tests. Coverage includes the C++
implementation and headers under onnx_light_ort/, excluding test sources,
downloaded dependencies, generated files and examples. Python and opt-in
real-ORT tests are not included.
The workflow uploads the Cobertura XML report to
Codecov using GitHub OIDC.
Enable this repository in Codecov before the first upload; no
CODECOV_TOKEN secret is required. Upload failures fail the workflow.
The README and documentation badges show the latest main coverage.
HTML and XML reports are also retained as the coverage Actions artifact
for 14 days. Relevant pull requests generate these artifacts without
publishing to Codecov, so they do not replace the daily main report.
To reproduce the native report locally, reconfigure the existing build tree:
python -m pip install -r requirements/coverage.txt
CC=gcc CXX=g++ cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS="--coverage -O0 -g" \
-DCMAKE_EXE_LINKER_FLAGS="--coverage" \
-DCMAKE_SHARED_LINKER_FLAGS="--coverage" \
-DONNX_LIGHT_ORT_BUILD_HOST=ON -DONNX_LIGHT_ORT_BUILD_PLUGIN=ON \
-DONNX_LIGHT_ORT_BUILD_TESTS=ON -DONNX_LIGHT_ORT_TEST_WITH_ORT=OFF
cmake --build build --parallel "$(nproc)"
ctest --test-dir build --output-on-failure
mkdir -p build/coverage
python -m gcovr build --root . \
--filter 'onnx_light_ort/' --exclude '.*/tests/.*' \
--xml-pretty --xml build/coverage/coverage.xml \
--html-details build/coverage/index.html --print-summary
Fuzzing onnx-light#
The optional fuzz targets are provided by the fetched onnx-light dependency and require Clang with libFuzzer support:
CC=clang CXX=clang++ cmake -S . -B build-fuzz \
-DONNX_LIGHT_ORT_BUILD_FUZZERS=ON \
-DONNX_LIGHT_ORT_BUILD_TESTS=OFF
cmake --build build-fuzz --parallel "$(nproc)"
./build-fuzz/_deps/onnx_light-build/fuzz_checker -runs=2000
Fuzzing is disabled by default. The fuzz GitHub Actions workflow builds
the available upstream harnesses and runs short smoke campaigns; it does not
replace longer coverage-guided fuzzing.
Documentation builds on pull requests, main pushes and manual dispatch. Only successful main-branch documentation builds deploy to GitHub Pages. Workflow tokens are read-only by default. Pages write permission is restricted to documentation deployment; OIDC write permission is granted to documentation deployment and the coverage job for Codecov authentication.