srdatalog.ir.codegen.cuda.build.loader

Python ↔ C++ bridge: dlopen a compiled .so and call into it.

Phase 9 — closes the end-to-end loop started by Phases 6-8:

  • main_file.py emits the C++ source

  • cache.py writes the tree to disk

  • compiler.py turns it into a .so

  • THIS module turns that .so into callable Python.

The C++ runner methods (<Ruleset>_Runner::run, load_data, etc.) are templates and can’t be called directly from ctypes. Instead, the user generates a small extern "C" shim that wraps the templated calls into C-ABI entry points; this module handles the Python side of that contract.

Public API:

  • EntryPoint — argtypes/restype spec for one C symbol.

  • gen_runtime_shim_template(...) — produces a starter shim.cpp the user fills in. Returned as a string so the caller can write it into the cache dir alongside main.cpp / jit_batch_N.cpp.

  • JitRuntime — ctypes.CDLL wrapper. Resolves symbols, applies the argspec, exposes typed .call(name, *args) / attribute shortcuts.

  • build_and_load(...) — one-shot: takes the project_result dict from cache.write_jit_project + a CompilerConfig, runs the full build, returns a ready JitRuntime on success.

Thread-safety: a single JitRuntime wraps one dlopen’d handle. ctypes serializes calls through the C ABI so concurrent calls from multiple Python threads are safe iff the underlying C function is. We don’t protect against that — it’s the user’s shim.

Module Contents

Classes

EntryPoint

Binding spec for one extern "C" function in the loaded .so.

JitRuntime

Wrapper around ctypes.CDLL with a declared entry-point map.

Functions

build_and_load

Compile the Phase-7 project tree (via Phase 8) and dlopen the resulting .so.

gen_runtime_shim_template

Emit a starter runtime_shim.cpp with extern "C" entry points the Python loader binds.

API

class srdatalog.ir.codegen.cuda.build.loader.EntryPoint[source]

Binding spec for one extern "C" function in the loaded .so.

name — the exported symbol name (post-extern "C" name-mangling). argtypes — ctypes argument types, in positional order. restype — return type. Default c_int suits “return 0 on success”. errcheck — optional callable run after the call for result mapping / error translation. Same protocol as ctypes.Function.errcheck: (result, func, arguments) -> final_result_or_raise.

argtypes: list[Any]

‘field(…)’

errcheck: Any

None

name: str

None

restype: Any

None

class srdatalog.ir.codegen.cuda.build.loader.JitRuntime(lib_path: str, entry_points: collections.abc.Sequence[srdatalog.ir.codegen.cuda.build.loader.EntryPoint] = (), *, mode: int = ctypes.RTLD_GLOBAL)[source]

Wrapper around ctypes.CDLL with a declared entry-point map.

Usage: rt = JitRuntime(“libmyproj.so”, entry_points=[ EntryPoint(“srdatalog_init”, restype=ctypes.c_int), EntryPoint(“srdatalog_run”, argtypes=[ctypes.c_char_p]), EntryPoint(“srdatalog_get_size”, argtypes=[ctypes.c_char_p], restype=ctypes.c_uint64, errcheck=None), ]) rt.srdatalog_init() rt.srdatalog_run(b”/data”) n = rt.srdatalog_get_size(b”Path”)

Initialization

__getattr__(name: str) Any[source]

Attribute-style access to bound entry points.

rt.some_fn(args...) resolves through the CDLL the first time and caches the typed function. Unbound symbols still surface as untyped ctypes functions — mirrors CDLL’s default behavior.

bind(ep: srdatalog.ir.codegen.cuda.build.loader.EntryPoint) Any[source]

Resolve ep.name in the library and apply argtypes / restype / errcheck. Returns the bound ctypes function.

close() None[source]

Drop the ctypes reference. Actual dlclose timing depends on Python’s garbage collector — ctypes doesn’t expose direct dlclose, so this is best-effort.

srdatalog.ir.codegen.cuda.build.loader.build_and_load(project_result: srdatalog.ir.codegen.cuda.build.cache.JitProjectLayout, entry_points: collections.abc.Sequence[srdatalog.ir.codegen.cuda.build.loader.EntryPoint], compiler_config: Any | None = None, *, required_artifact: str | None = None) srdatalog.ir.codegen.cuda.build.loader.JitRuntime[source]

Compile the Phase-7 project tree (via Phase 8) and dlopen the resulting .so.

Raises on compile/link failure with the captured stderr in the message — the common failure mode during dev.

required_artifact lets the caller override the default artifact name (e.g. the runner library name for a well-known runtime).

srdatalog.ir.codegen.cuda.build.loader.gen_runtime_shim_template(ruleset_name: str, db_blueprint_name: str, dest_relations: collections.abc.Sequence[tuple[str, str]] = ()) str[source]

Emit a starter runtime_shim.cpp with extern "C" entry points the Python loader binds.

Args: ruleset_name: matches the _Runner struct name (so the shim calls <ruleset>_Runner::load_data, run). db_blueprint_name: user-declared blueprint type (e.g., “TriangleDBBlueprint”). dest_relations: list of (symbol_suffix, cpp_type_name) tuples exposing per-relation size queries. For each entry, the shim emits uint64_t srdatalog_size_<suffix>().

The template is a STARTING POINT — the caller may hand-edit the body (e.g., to add custom result-extraction logic) before handing it to cache.write_jit_project.

The shim assumes the user has already included the main file (which defines the _Runner struct and DB blueprint) via #include "main.cpp" or similar — callers that shard the build differently need to adjust that line.