Files
voculinux/tests/test_pywhispercpp_loader.py
T
xavierk 97f93e9492
CI / security (pull_request) Successful in 1m11s
CI / lint (pull_request) Successful in 25s
CI / ai-review (pull_request) Successful in 8s
fix(void): report pywhispercpp 1.5.0 and load CPU variants at runtime
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
2026-11-07 00:03:22 +05:30

51 lines
1.7 KiB
Python

"""Preloading must leave ggml's runtime-selected CPU variants to ggml (#44)."""
from pathlib import Path
from unittest.mock import patch
from vocalinux.utils import pywhispercpp_loader
def _preload_names(tmp_path: Path, *names: str) -> list[str]:
"""Run the preloader over ``names`` in one directory and return what it dlopens."""
for name in names:
(tmp_path / name).write_bytes(b"")
loaded: list[str] = []
def record(path: str, mode: int = 0) -> object:
loaded.append(Path(path).name)
return object()
with (
patch.object(pywhispercpp_loader, "find_shared_library_dirs", return_value=[str(tmp_path)]),
patch.object(pywhispercpp_loader, "_PRELOADED_LIBS", []),
patch.object(pywhispercpp_loader.ctypes, "CDLL", side_effect=record),
):
pywhispercpp_loader.preload_shared_libraries()
return loaded
def test_preload_leaves_runtime_cpu_variants_to_ggml(tmp_path: Path) -> None:
"""Variants share one symbol table; preloading them RTLD_GLOBAL would interpose them."""
loaded = _preload_names(
tmp_path,
"libggml.so.0",
"libggml-base.so.0",
"libggml-cpu-x64.so",
"libggml-cpu-haswell.so",
"libggml-vulkan.so",
"libwhisper.so.1",
)
assert not [name for name in loaded if name.startswith("libggml-cpu-")]
assert {"libggml.so.0", "libggml-base.so.0", "libggml-vulkan.so", "libwhisper.so.1"} <= set(
loaded
)
def test_preload_keeps_the_single_cpu_library_of_a_non_variant_build(tmp_path: Path) -> None:
"""Without GGML_CPU_ALL_VARIANTS the CPU backend is a dependency and must be preloaded."""
loaded = _preload_names(tmp_path, "libggml.so.0", "libggml-cpu.so")
assert "libggml-cpu.so" in loaded