Skip to main content

Load TVM-FFI exported object files using LLVM ORC JIT v2

Project description

TVM-FFI OrcJIT

A Python package that enables dynamic loading of compiled object files (.o) using LLVM ORC JIT v2, providing a flexible JIT execution environment for TVM-FFI exported functions.

Features

  • JIT Execution: Load and execute compiled object files at runtime using LLVM's ORC JIT v2
  • Multiple Libraries: Create separate dynamic libraries with independent symbol namespaces
  • Incremental Loading: Add multiple object files to the same library incrementally
  • Symbol Isolation: Different libraries can define the same symbol without conflicts
  • Init/Fini Support: Handles static constructors/destructors across ELF (.init_array/.ctors), Mach-O (__mod_init_func), and COFF (.CRT$XC*/.CRT$XT*)
  • Cross-Platform: Linux (x86_64, aarch64), macOS (arm64), Windows (AMD64)
  • Multi-Compiler: Tested with LLVM Clang, GCC, Apple Clang, MSVC, and clang-cl
  • TVM-FFI Integration: Seamlessly works with TVM-FFI's stable C ABI
  • Python API: Simple Pythonic interface for JIT compilation and execution

Supported Platforms and Compilers

Object files compiled with any of the following compiler/platform combinations can be loaded and executed by the ORC JIT:

Platform Compilers C C++
Linux (x86_64, aarch64) LLVM Clang, GCC yes yes
macOS (arm64) LLVM Clang, Apple Clang yes yes
Windows (AMD64) LLVM Clang, MSVC, clang-cl yes no

Windows is C-only across all compilers. C++ objects compiled with TVM_FFI_DLL_EXPORT_TYPED_FUNC use try/catch (via TVM_FFI_SAFE_CALL_BEGIN/END), which requires Itanium exception ABI symbols (__cxa_begin_catch, __gxx_personality_v0, etc.) that the MSVC-built host process cannot provide. Pure C objects using the TVMFFISafeCallType ABI work on all platforms.

Installation

Install from PyPI

pip install apache-tvm-ffi apache-tvm_ffi_orcjit

Build from Source

Prerequisites

  • Python 3.10+, CMake 3.20+, C++17 compiler
  • LLVM 22+ development libraries (llvmdev, llvm-config)
  • Static zlib and zstd libraries (in the same prefix as LLVM)

Install LLVM via conda-forge

The easiest way to get all dependencies is via conda-forge:

conda create -p /opt/llvm -c conda-forge \
  llvmdev=22.1.0 clangdev=22.1.0 compiler-rt=22.1.0 zlib zstd-static -y
export LLVM_PREFIX=/opt/llvm

On Windows:

conda create -p C:\opt\llvm -c conda-forge llvmdev=22.1.0 zlib zstd-static -y
set LLVM_PREFIX=C:\opt\llvm

Build and install

git clone --recursive https://github.com/apache/tvm-ffi.git
cd tvm-ffi

# Install tvm-ffi first
pip install -e .

# Build and install the orcjit addon
cd addons/tvm_ffi_orcjit
pip install -e .

The LLVM_PREFIX environment variable tells CMake where to find LLVM. If LLVM is installed in a conda env or a standard system path, CMake can auto-discover it and LLVM_PREFIX is not needed.

Usage

Basic Example

from tvm_ffi_orcjit import ExecutionSession

# Create an execution session
session = ExecutionSession()

# Create a dynamic library
lib = session.create_library()

# Load an object file
lib.add("example.o")

# Get and call a function
add_func = lib.get_function("add")
result = add_func(1, 2)
print(f"Result: {result}")  # Output: Result: 3

Multiple Libraries with Symbol Isolation

session = ExecutionSession()

lib1 = session.create_library("lib1")
lib2 = session.create_library("lib2")

lib1.add("implementation_v1.o")
lib2.add("implementation_v2.o")

add_v1 = lib1.get_function("add")
add_v2 = lib2.get_function("add")

print(add_v1(5, 3))  # Uses implementation from lib1
print(add_v2(5, 3))  # Uses implementation from lib2

Cross-Library Linking

session = ExecutionSession()

base_lib = session.create_library("base")
base_lib.add("math_ops.o")

caller_lib = session.create_library("caller")
caller_lib.set_link_order(base_lib)  # Can resolve symbols from base_lib
caller_lib.add("caller.o")

result = caller_lib.get_function("call_math")(10, 20)

Writing Functions for OrcJIT

C++ (Linux/macOS)

#include <tvm/ffi/function.h>

TVM_FFI_DLL_EXPORT_TYPED_FUNC(add, [](int a, int b) {
    return a + b;
});

Compile: clang++ -std=c++17 -fPIC -O2 -c -o example.o example.cc

Pure C (all platforms including Windows)

#include <tvm/ffi/c_api.h>

TVM_FFI_DLL_EXPORT int __tvm_ffi_add(
    void* self, const TVMFFIAny* args, int32_t num_args, TVMFFIAny* result) {
  result->type_index = kTVMFFIInt;
  result->v_int64 = args[0].v_int64 + args[1].v_int64;
  return 0;
}

Compile: clang -O2 -c -o example.o example.c

How It Works

  • LLJIT: Built on LLVM's ORC JIT v2 with ObjectLinkingLayer (JITLink) for all platforms.
  • InitFiniPlugin: Custom ObjectLinkingLayer::Plugin that collects function pointers from init/fini sections (ELF .init_array/.ctors/.fini_array/.dtors, Mach-O __mod_init_func/__mod_term_func, COFF .CRT$XC*/.CRT$XT*) and runs them in priority order at symbol lookup / library teardown.
  • DLL Import Stubs (Windows): Custom DefinitionGenerator that resolves host process symbols from all loaded DLLs and creates __imp_* pointer stubs in JIT memory, keeping all fixups within PCRel32 range.
  • SEH Stripping (Windows): ObjectTransformLayer strips .pdata/.xdata relocations from COFF objects before JITLink graph building, working around a JITLink limitation with COMDAT section symbols.

Please refers to ORCJIT_PRIMER.md to learn more about object file, linking, llvm orcjit v2, and how the addon works.

Project Structure

tvm_ffi_orcjit/
├── CMakeLists.txt              # Build configuration
├── pyproject.toml              # Python package metadata
├── src/ffi/
│   ├── orcjit_session.cc       # ExecutionSession (LLJIT setup, plugins)
│   ├── orcjit_session.h
│   ├── orcjit_dylib.cc         # DynamicLibrary (object loading, symbol lookup)
│   ├── orcjit_dylib.h
│   └── orcjit_utils.h          # LLVM error handling utilities
├── python/tvm_ffi_orcjit/
│   ├── __init__.py             # Module exports and library loading
│   ├── session.py              # Python ExecutionSession wrapper
│   └── dylib.py                # Python DynamicLibrary wrapper
├── tests/                      # See tests/README.md
└── examples/quick-start/       # Complete example with CMake

CI

Runs on Linux (x86_64, aarch64), macOS (arm64), Windows (AMD64) via cibuildwheel. Each platform builds test objects with multiple compilers and runs the full test suite. See .github/workflows/tvm_ffi_orcjit.yml.

Troubleshooting

"Cannot find global function" error

The shared library wasn't loaded. Reinstall: pip install --force-reinstall apache-tvm_ffi_orcjit

"Duplicate definition of symbol" error

Use separate libraries for different implementations of the same symbol.

"Symbol not found" error

Ensure functions are exported with TVM-FFI macros (TVM_FFI_DLL_EXPORT_TYPED_FUNC for C++, or __tvm_ffi_ prefix for C).

Relocation errors on Windows

MSVC/clang-cl objects must be compiled with /GS- to disable buffer security checks (__security_cookie) which are CRT symbols the JIT cannot resolve.

LLVM version mismatch

The package requires LLVM 22+. Set LLVM_PREFIX to the LLVM install prefix:

export LLVM_PREFIX=/path/to/llvm

License

Apache License 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

apache_tvm_ffi_orcjit-0.1.0-py3-none-win_amd64.whl (12.5 MB view details)

Uploaded Python 3Windows x86-64

apache_tvm_ffi_orcjit-0.1.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl (23.4 MB view details)

Uploaded Python 3manylinux: glibc 2.27+ x86-64manylinux: glibc 2.28+ x86-64

apache_tvm_ffi_orcjit-0.1.0-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl (22.3 MB view details)

Uploaded Python 3manylinux: glibc 2.27+ ARM64manylinux: glibc 2.28+ ARM64

apache_tvm_ffi_orcjit-0.1.0-py3-none-macosx_11_0_arm64.whl (14.9 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file apache_tvm_ffi_orcjit-0.1.0-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for apache_tvm_ffi_orcjit-0.1.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 8ef9a49ae9a4660c0e1555ae6526a3f9b89ad3adfaa14010b9520946f4c56800
MD5 699dda3c0235f849ef32ebb98fa82992
BLAKE2b-256 c886cc2ba70db1bc6f53e2eb8854ad4f12ff52c8f764f82c7fbe2db919d77346

See more details on using hashes here.

Provenance

The following attestation bundles were made for apache_tvm_ffi_orcjit-0.1.0-py3-none-win_amd64.whl:

Publisher: publish_orcjit_wheel.yml on apache/tvm-ffi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file apache_tvm_ffi_orcjit-0.1.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for apache_tvm_ffi_orcjit-0.1.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ce3ac5c06ee1d500615bf0b4b22ff536b2ddee28f538c0001c81132452cd50be
MD5 fd6e8a7f3be7b886707232dbe7cea535
BLAKE2b-256 17d3e9523c16cf0081fe2f2d130af0be5f384f5109e226372929d507c6397671

See more details on using hashes here.

Provenance

The following attestation bundles were made for apache_tvm_ffi_orcjit-0.1.0-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:

Publisher: publish_orcjit_wheel.yml on apache/tvm-ffi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file apache_tvm_ffi_orcjit-0.1.0-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for apache_tvm_ffi_orcjit-0.1.0-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 f64f172b5e8d77a9dc8abd6cedf4a63b7a28a974ddc8cee6268b1cb810dad87b
MD5 d0259ca1ddf66cb9bdbdb74d8bbb6466
BLAKE2b-256 d77fa22fd8665e2bcd7af31094b99e5cedfedbc3d7a0e90a3b3acda9d5f36de6

See more details on using hashes here.

Provenance

The following attestation bundles were made for apache_tvm_ffi_orcjit-0.1.0-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl:

Publisher: publish_orcjit_wheel.yml on apache/tvm-ffi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file apache_tvm_ffi_orcjit-0.1.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for apache_tvm_ffi_orcjit-0.1.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 1caf8a3b0a74cebba23d6e89652256f38181fa85aedfd19c3dae05d3f17f427c
MD5 e066d6b1822d61d41d21eea525d852d5
BLAKE2b-256 14e6a02bd0a656150f38583ffb8b9b8fb1f360fe6e26c7979b293ca8b5b72c81

See more details on using hashes here.

Provenance

The following attestation bundles were made for apache_tvm_ffi_orcjit-0.1.0-py3-none-macosx_11_0_arm64.whl:

Publisher: publish_orcjit_wheel.yml on apache/tvm-ffi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page