fix(void): report pywhispercpp 1.5.0 and load CPU variants at runtime
CI / security (pull_request) Successful in 1m11s
CI / lint (pull_request) Successful in 25s
CI / ai-review (pull_request) Successful in 8s

python3-pywhispercpp was installed as 0.0.0. setup.py passes no version to
setup() and takes it from setuptools-scm, which the Void build did not
install; the template's PYWHISPERCPP_VERSION export is never read. The app
read 0.0.0 as an old binding and skipped GPU device selection. Install
setuptools-scm, pin the version with SETUPTOOLS_SCM_PRETEND_VERSION, and
make the app treat a 0.0.0 distribution as unknown so the runtime feature
probe decides.

The CPU backend was built with every SIMD option off, so the real-time
factor on an AVX2 host was about 1.7. Build with GGML_BACKEND_DL and
GGML_CPU_ALL_VARIANTS instead: one CPU library per instruction-set level,
with the x86-64 baseline always shipped. The binding loads the variants
from its own directory (patches/), and pre_install places them beside the
extension. The app's library preloader skips those variants: they export
identical symbols, so preloading them RTLD_GLOBAL would let one variant
serve every other. The install smoke asserts that the installed package
reports 1.5.0, that the baseline variant holds no AVX code, that the AVX2
variant does, and that the CPU and Vulkan backends load from the package.

Fixes #43
Fixes #44
This commit is contained in:
2026-11-07 00:03:22 +05:30
parent a4a831c3c6
commit 97f93e9492
11 changed files with 376 additions and 66 deletions
@@ -0,0 +1,39 @@
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -16,6 +16,10 @@
#include <pybind11/numpy.h>
#include "whisper.h"
+#include "ggml-backend.h"
+
+#include <dlfcn.h>
+#include <string>
#define STRINGIFY(x) #x
@@ -850,7 +854,25 @@
////////////
+// With GGML_BACKEND_DL the CPU and GPU backends are libraries next to this
+// extension, and whisper.cpp cannot create a context until a CPU device is
+// registered. ggml searches the executable's directory (the interpreter's, for
+// Python) and the working directory, so load them from this module's directory.
+static void load_ggml_backends_beside_module() {
+ Dl_info info;
+ if (dladdr(reinterpret_cast<void *>(&load_ggml_backends_beside_module), &info) == 0 ||
+ info.dli_fname == nullptr) {
+ ggml_backend_load_all();
+ return;
+ }
+ const std::string path(info.dli_fname);
+ const std::size_t slash = path.find_last_of('/');
+ const std::string dir = slash == std::string::npos ? std::string(".") : path.substr(0, slash);
+ ggml_backend_load_all_from_path(dir.c_str());
+}
+
PYBIND11_MODULE(_pywhispercpp, m) {
+ load_ggml_backends_beside_module();
m.doc() = R"pbdoc(
Pywhispercpp: Python binding to whisper.cpp
-----------------------