#2274

[BUG] Linux (Arch/CachyOS), built from source: crash with "undefined symbol: cblas_sgemm" - libtranscribe linked against Netlib libblas.so.3

OpenElWazyopened 17d ago

Before You Submit

Searched issues for cblas_sgemm, libblas, symbol lookup error: no existing issue. Related open PR: #2102 (addresses this same error; it has no linked issue, so this report provides one with an independent reproduction and a comparison against the official package).

Bug Description

When Handy v0.9.8 is built from source on an Arch-based distro without OpenBLAS present at build time, it crashes as soon as transcription starts with Nemotron 3.5 Streaming:

handy: symbol lookup error: /usr/bin/../lib/Handy/libtranscribe.so.0.2: undefined symbol: cblas_sgemm

This is the last log line, right after Live streaming transcription started.

The official v0.9.8 .deb is not affected. Both builds import the same CBLAS symbols, but they link different BLAS libraries:

Official v0.9.8 .deb (CI, Ubuntu)Source build (CachyOS)
DT_NEEDED BLASlibopenblas.so.0libblas.so.3
Undefined CBLAS symbolscblas_sgemm, cblas_sgemvcblas_sgemm, cblas_sgemv
Result on ArchWorks (OpenBLAS exports CBLAS)Crashes (Netlib blas exports only the Fortran API)

On Arch, libblas.so.3 is owned by the Netlib reference BLAS (blas), which exports only the Fortran BLAS API. The CBLAS symbols live in the separate cblas package (libcblas.so), which libtranscribe never links.

Evidence — source build

$ readelf -d /usr/lib/Handy/libtranscribe.so.0.2 | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libggml.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libblas.so.3]
 0x0000000000000001 (NEEDED)             Shared library: [libggml-base.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]

$ nm -D /usr/lib/Handy/libtranscribe.so.0.2 | grep cblas
                 U cblas_sgemm
                 U cblas_sgemv

$ pacman -Qo /usr/lib/libblas.so.3
/usr/lib/libblas.so.3 is owned by blas 3.12.1-2.1

$ nm -D /usr/lib/libblas.so.3 | grep cblas_sgemm
(no output)

Evidence — official v0.9.8 .deb (extracted, not installed)

$ readelf -d usr/lib/Handy/libtranscribe.so.0.2 | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libggml.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libopenblas.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libggml-base.so.0]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [ld-linux-x86-64.so.2]

$ nm -D usr/lib/Handy/libtranscribe.so.0.2 | grep cblas
                 U cblas_sgemm
                 U cblas_sgemv

Root cause (build side)

The BLAS link is decided in transcribe-cpp-sys 0.2.4, src/CMakeLists.txt (BLAS block around lines 198–232). With TRANSCRIBE_USE_SYSTEM_BLAS=ON (the default), it runs find_package(BLAS) (line 213) and then only checks that cblas.h exists (check_include_file(cblas.h HAVE_CBLAS_H), line 220) before linking ${BLAS_LIBRARIES}. The upstream comment already anticipates this case:

find_package(BLAS) may find a Fortran-only BLAS (e.g. libblas3 on Debian/Ubuntu) that lacks the cblas C wrappers. Verify that cblas.h exists before enabling

However, the check validates the header, not the library. With Netlib blas + cblas installed, cblas.h is present (from cblas), but FindBLAS selects the generic libblas.so, and libcblas.so is never linked. The shared library builds without errors because undefined symbols are allowed in shared objects, so the failure only appears at runtime. The CMakeCache from my build:

BLAS_blas_LIBRARY:FILEPATH=/usr/lib/libblas.so
BLAS_openblas_LIBRARY:FILEPATH=BLAS_openblas_LIBRARY-NOTFOUND
HAVE_CBLAS_H:INTERNAL=1
TRANSCRIBE_USE_SYSTEM_BLAS:BOOL=ON

CI doesn't hit this because the Linux jobs install libopenblas-dev, so FindBLAS picks OpenBLAS (as the official .deb shows).

Documentation gap

BUILD.md doesn't list OpenBLAS in any of the Linux dependency lists (Ubuntu/Debian, Fedora/RHEL, Arch), even though CI installs libopenblas-dev. Someone following BUILD.md exactly on Arch ends up with this crash if their system has Netlib blas instead of OpenBLAS.

Workaround

sudo pacman -S blas-openblas (replaces blas and cblas; libblas.so.3 then exports cblas_sgemm/cblas_sgemv). After that, Nemotron works correctly on Vulkan without rebuilding.

Possible fixes (options, for your judgement)

  • Add OpenBLAS to the BUILD.md dependency lists (libopenblas-dev / openblas-devel / openblas), matching what CI installs. Note: I haven't tested whether installing openblas alongside Netlib blas is enough for FindBLAS to prefer it, or whether -DBLA_VENDOR=OpenBLAS is also needed.
  • Pin the vendor at build time (e.g. BLA_VENDOR=OpenBLAS), so source builds link libopenblas.so.0 like the official package.
  • Upstream in transcribe-cpp: replace or augment the cblas.h header check with a link check (e.g. check_symbol_exists(cblas_sgemm ...) against ${BLAS_LIBRARIES}), so a Fortran-only BLAS falls back to the scalar path (or fails loudly) instead of producing a library that crashes at runtime.
  • The runtime shim proposed in #2102. In v0.9.8 the official package already links libopenblas.so.0 directly, so the problem seems limited to source builds; this may affect whether the shim is still needed.

Scope (code-level, not runtime-verified): in transcribe-cpp-sys 0.2.4, CBLAS is called from the shared mel frontend (transcribe-mel.cpp, included by several architectures) and from the parakeet and gigaam decoders. Other transcribe-cpp models are therefore likely affected in the same build. I only reproduced the crash with Nemotron.

System Information

App Version: v0.9.8, built from source (tag v0.9.8)

RUSTFLAGS="-C target-cpu=native" CARGO_PROFILE_RELEASE_LTO=fat CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1 bun run tauri build --bundles deb

Installed by extracting the .deb per BUILD.md "Linux Install (from source)" (binary in /usr/bin, libraries in /usr/lib/Handy).

Operating System: CachyOS x86_64, kernel 7.2.9-2-cachyos, Hyprland 0.56.2 (Wayland). BLAS packages at build time and at the time of the crash: blas 3.12.1-2.1, cblas 3.12.1-2.1 (Netlib); OpenBLAS not installed.

CPU: Intel Core i9-9900K (libggml-cpu-haswell.so loaded)

GPU: NVIDIA GeForce RTX 2080 Ti (Vulkan0 backend)

Model: handy-computer/nemotron-3.5-asr-streaming-0.6b-gguf (Q8_0), live streaming enabled

Logs

... Live streaming transcription started
handy: symbol lookup error: /usr/bin/../lib/Handy/libtranscribe.so.0.2: undefined symbol: cblas_sgemm

AI Assistance Disclosure

  • AI used: Yes.
  • Tools: Claude Code (Claude Opus 5.5), used in two sessions: one to debug and draft the issue, another to review it for privacy and verify its claims.
  • Extent: AI did the debugging and wrote this entire issue. I'm not a Handy developer and haven't read the code myself; I built from source as a user, only to get a binary optimized for my machine.
  • What I verified myself: the crash, the workaround (blas-openblas fixes it without rebuilding), and the command outputs shown above (readelf, nm, pacman -Qo, CMakeCache, and the extracted official .deb), which I ran on my machine.
  • AI analysis I haven't verified: the root-cause reading of transcribe-cpp-sys CMakeLists.txt, the BUILD.md documentation gap, the possible fixes, and the code-level scope of other affected models.

Happy to help if you need more information 🙌

Activity

0

No activity yet.