Kwker compatibility
What each Kwker package is built against and what it needs at run time. Measured on the build host: Ubuntu 24.04, glibc 2.39, GCC 13.3, Rust stable, CPython 3.11, torch 2.14.0+cpu, NumPy 2.4.
Versioning policy for 0.1.x
Kwker is pre-1.0: versions are 0.MINOR.PATCH. A patch release (0.1.0 -> 0.1.1) never breaks a caller; a minor release
(0.1.x -> 0.2.0) may, and lists every break under "Breaking" in CHANGELOG.md with the replacement. From 1.0 on, semantic
versioning applies to every surface below.
What "never breaks" means within 0.1.x, per surface (checked by ss abi against the committed snapshots in rust/abi/ before
every release; ss release refuses a break):
| Surface | Stable within 0.1.x | Not covered |
|---|---|---|
C ABI (kwker.h) |
every exported kwker_* function keeps its name, signature, return codes and semantics; types, struct layouts and constants keep their values; new functions, enum values and flags are additions |
kwker_ (dev builds only) |
C++ header (kwker.hpp) |
header-only templates over the C ABI: the same rules; it adds no C++ ABI of its own | names in detail namespaces |
Rust crate kwker |
no public item removed, no signature changed (rustdoc JSON snapshot); new items, trait impls and enum variants of #[non_ enums are additions |
_, items marked #[doc(hidden)] |
Python kwker |
every public name (rust/abi/python.txt, userdocs/reference-python.md) keeps its signature; new keyword arguments get defaults that keep the old behaviour | names starting with _ |
PyTorch operators (torch.ops.kwker.*) |
operator schemas without a leading underscore; torch.compile(backend="kwker") keeps accepting every graph Inductor accepts |
_-prefixed operators, the kernels a self-check may turn off |
| Environment variables | the ones in userdocs/cpu-runtime.md (KWKER_, KWKER_, KWKER_, KWKER_, KWKER_, KWKER_, KWKER_, KWKER_) |
every other KWKER_* variable: development knobs (KWKER_, KWKER_, KWKER_, ...) that can change or disappear in any release |
Results are part of the contract: sorts, selections and stable key-value sorts return the same output on every engine
and in every 0.1.x release (one total order per key type - API.md); index operations break ties by index. Unstable
key-value sorts promise only that equal keys keep their values in some order. The CPU backend's reduced-precision modes
(bf16, int8, int4) promise their documented error bounds, not bit-identical outputs across releases; its float32 paths
and the bitwise torch overrides stay bitwise. Speed is not part of the contract, but a confirmed slowdown is a bug
(ss regress gates releases on it).
Deprecation: a public name to be removed is first marked deprecated for at least one minor release. Rust uses
#[deprecated(since, note)], C / C++ a KWKER_DEPRECATED("use ...") attribute on the declaration, Python a
DeprecationWarning naming the replacement, and torch operators a warning at first call. The CHANGELOG entry names
the release that removes it. Nothing is deprecated in 0.1.0.
Supported toolchains and runtimes for 0.1.x are the versions tested on every release. Older ones may work but are not tested.
- Rust stable (declared
rust-version1.77). - GCC 13 or Clang 18+ to build the engines. On Windows, clang++ for the MSVC target: MSVC's cl.exe cannot build them.
- glibc 2.34+, macOS 15 (arm64), Windows 10/11 x64.
- CPython 3.9+ (3.13t free-threaded included) with NumPy 1.21+.
- PyTorch 2.12, 2.13 and 2.14 for the compiled operators: one extension build and one wheel per torch minor release. Another torch release falls back to the Python-registered operators.
- JAX with its XLA FFI headers.
Raising one of these minimums is a minor-release change, listed in the CHANGELOG.
The shared library's SONAME is libkwker_c.so today; from 0.1.0 it is planned to carry the minor version
(libkwker_c.so.0.1, with the unversioned name as the development symlink), so programs linked against 0.1.x never
load a 0.2 library by accident.
C library (libkwker_c.so / .a, kwker.h, kwker.hpp)
- The ABI is plain C: fixed-width integer and pointer arguments,
intreturn codes, no structs passed by value. The exceptions arekwker_column, passed by pointer, and the opaquekwker_workspace. The C++ header is header-only templates over that ABI, so it adds no C++ ABI of its own and builds as C++17 or C++20. - Policy before 1.0: see "Versioning policy for 0.1.x" above.
- Exported symbols: only
kwker_*. The engines' C++ symbols are localized, so the library links into C++ programs built with any standard library or compiler. - The engine is chosen at run time from CPUID: AVX-512, AVX2 or portable (on ARM64: NEON / SVE). One binary therefore
runs on every x86-64 CPU.
KWKER_ISAcaps the level. - Run-time needs (the shared library's NEEDED entries and symbol versions): libc (GLIBC_2.34 or newer), libstdc++.so.6 (GLIBCXX_3.4, CXXABI_1.3.8: any GCC 4.9+ runtime), libgcc_s. Nothing else: no network, no files.
- Release tarball (
ss release):kwker-c-<version>-linux-x86_64.tar.gzholds include/, lib/libkwker_c.{a,so}, a relocatable pkg-config file (its prefix taken from its own location) and the CMake package, plus the notices, this file, the changelog and an SPDX SBOM in share/doc/kwker. It works from any directory it is unpacked to:ss releaseunpacks it to a fresh directory and builds and runs the C and C++ tests there through pkg-config (shared, static) and find_package. The archive is deterministic (sorted names, fixed owner and dates). - Other platforms (
ss --ci release, built natively on CircleCI runners and checked there - a C program compiled against the unpacked package alone, shared and static, and the wheel's test suite in a fresh virtual environment):kwker-c-<version>-linux-aarch64.tar.gz(glibc 2.34+, wheelmanylinux_2_34_aarch64; NEON, SVE where the CPU has it, portable),kwker-c-<version>-macos-aarch64.tar.gz(lib/libkwker_c.dylib with an @rpath install name, macOS 15 wheelmacosx_15_0_arm64; NEON) andkwker-c-<version>-windows-x86_64.zip(MSVC: bin/kwker_c.dll, its import library lib/kwker_c.dll.lib and the static lib/kwker_c_static.lib; AVX-512, AVX2 and portable engines since 2026-10-02 - the AVX2 group's symbols renamed with llvm-objcopy so the linker keeps both groups). The CMake package names each platform's files; pkg-config files ship outside Windows.
Python package (kwker)
- The core is pure Python over ctypes and the bundled C library. The wheel is tagged
py3-none-manylinux_2_34_x86_64(auditwheel sets the platform tag from the bundled libraries' symbol versions; nothing is grafted in): one wheel covers every CPython from 3.9 on, with no Python ABI dependency, on any x86-64 Linux with glibc 2.34 or newer (Ubuntu 22.04, Debian 12, RHEL 9 and later). NumPy >= 1.21 is required (tested with NumPy 2.4).ml_dtypesis optional, for bfloat16 / FP8 arrays. - Free-threaded CPython (3.13t) is tested (
ss py --ft): the per-call fast path builds a second time without the stable ABI (_fast.cpython-313t-*.so) and declares that it needs no GIL, so importing kwker leaves the GIL off.
PyTorch extensions (_torch_ops.so, _torch_gemm.so)
- These are C++ extensions (TORCH_LIBRARY), so each build is tied to one torch minor release and its C++ ABI
(
_GLIBCXX_USE_CXX11_ABI). The build writes both intokwker/_torch_build.txt. Their glibc floor is 2.34 too (a local integer parser replaces atoi / atoll, which glibc 2.38 headers redirect to __isoc23 symbols); the torch wheel keeps libtorch_cpu / libc10 / libgomp external - torch itself provides them. - At import,
kwker.torch_ops.built_for_this_torch()compares that stamp with the running torch. On a mismatch (another minor release or another ABI) it warns and keeps the Python-registered operators (torch.library.custom_op: torch 2.4 or later; tested on 2.14). A mismatched extension is never loaded, so a torch upgrade cannot crash the process. - The torch wheel (
ss py --wheel --torch) bundles both extensions. It is versioned0.1.0+torch<major>.<minor>and depends ontorch>=<major>.<minor>,<<major>.<minor + 1>, the same scheme as torchvision / torchaudio. It is tested by importing it from an unpacked copy (compiled operators loaded, CPU backend available) and running the torch operator test suite against it.ss py --wheel --torch --torch-version 2.12,2.13,2.14builds and tests one wheel per release (each in its own venv with that torch and its torchvision) into target/wheels/torch. /. - The extensions run on CPU tensors only. Under
torch.compile(backend="kwker"), graphs whose tensors all live on CUDA / XPU / MPS go to plain Inductor unchanged. - Within a minor release the bitwise overrides still depend on torch's internals (rounding orders, vector tails, random
streams, output layouts), the C library (log1p) and the CPU path. So the first
kwker.torch_ops.install()of a process checks each of them against the running torch's own kernel: a small probe per kernel through both, compared bit for bit (self_check(); torchvision's kernels when torchvision is imported, the fused Adam / SGD steps too). A kernel that differs stays off - its calls take torch's kernel - and a RuntimeWarning names it. The result is cached per torch build, extension build, probe code, CPU and C library (KWKER_CACHE_DIR, default~/.cache/kwker), so only the first process on a new configuration pays for the probes (~0.1 s warm, ~0.5 s in a fresh process);KWKER_SELF_CHECK=0skips the check,=forcereruns it. The patched torchvision transforms are checked the same way against torchvision's functions (values; their layouts are no contract) and stay unpatched if they differ, cached with torchvision's and Pillow's builds in the key. - Built and tested, one wheel each: torch 2.12, 2.13 and 2.14 (CPU builds, CXX11 ABI 1) with torchvision 0.27, 0.28 and 0.29, Pillow 12.3.
JAX (_jax_ffi.so)
- XLA FFI handlers, built against the installed jaxlib's FFI headers (
ss py --jaxrebuilds them). Without the compiled library,jax.pure_callbackserves the same functions.
Other bindings
- Go (cgo), Java (JNI, any JDK; FFM on 22+), C# (P/Invoke, net8.0), Node / Bun / Deno 2 (Node-API, ABI-stable across Node
versions), R, Perl (XS), Ruby (C extension), PHP (extension, built per PHP minor version; or the Composer package
zhyted/smartsort over FFI, no build), Fortran (ISO_C_BINDING), COBOL and assembly: each binds the C ABI above.
Interpreter extensions (Perl, Ruby, PHP, R) are built per interpreter version against the installed C package (
ss capi --install).