Skip to content

fix(linux): bundle libgomp in the AppImage, the one format that cannot declare it - #326

Merged
EtienneLescot merged 2 commits into
mainfrom
fix/appimage-bundle-libgomp
Aug 10, 2026
Merged

fix(linux): bundle libgomp in the AppImage, the one format that cannot declare it#326
EtienneLescot merged 2 commits into
mainfrom
fix/appimage-bundle-libgomp

Conversation

@EtienneLescot

@EtienneLescot EtienneLescot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

1.9.2 declared the three sonames its Linux packages needed and never asked for.
That fixed three formats out of four. The AppImage has no dependency mechanism,
so declaring anything does nothing for it — on a machine without libgomp.so.1
its STT stack still dies in ld.so before main(), and transcription still
shows an end user a developer error.

Why this one and not the other two

soname bundleable why
libgomp.so.1 yes self-contained runtime, absent from the AppImage excludelist
libgbm.so.1 no excludelist: "part of mesa" — speaks to the host's DRM stack
libasound.so.2 no excludelist: loads the host's ALSA plugins and configuration

It needed less than expected

Every STT binary already carries RUNPATH=$ORIGIN:$ORIGIN/bin, so a copy in
that directory is found ahead of the system one. No patchelf pass, no custom
AppRun — both of which the first sketch of this change assumed were
unavoidable.

Where the copy is made matters more than that it is made

It happens in build-whisper-stt.sh, on the machine that compiles these
binaries, whose Linux leg build-whisper-stt.yml pins to ubuntu-22.04 — the
same floor before-pack.cjs enforces. The library that ships therefore comes
from the same machine and the same glibc as the binaries that load it, and it
travels inside the whisper artifact to every consumer whatever their own distro.

The first version of this PR copied it during packaging instead, and that was
wrong in a way worth naming: it took the library from whoever ran the build, so
a developer on 24.04 staged a libgomp needing GLIBC_2.38, before-pack.cjs
correctly refused it, and npm run build:linux stopped working locally for a
change meant to be invisible there. Provenance was the fix, not a version check.

stage-whisper-stt.sh now only asserts the library arrived, and names the
workflow to re-run when an older artifact does not carry it — including on the
early-exit path a developer with a locally built binary takes.

The libgomp1/libgomp entries added in 1.9.2 stay: redundant now, and free
insurance if this staging ever regresses silently.

Verification

  • With the copy in place, ldd resolves libgomp.so.1 through $ORIGIN to the bundled file rather than the system one.
  • The STT binary loads on an ubuntu:24.04 container with no libgomp1 installed.
  • Remove the staged copy in that same container and it dies on libgomp.so.1: cannot open shared object file.

Note for whoever merges

The whisper artifact currently published predates this change, so it does not
carry the library yet. stage-whisper-stt.sh will fail loudly and say so —
re-run build-whisper-stt.yml before the next release build. That is the
intended behaviour, not a regression.

Not in scope

The rest of what the AppImage takes from the host is the GTK/GLib/NSS stack,
which no AppImage bundles — theme engines, GIO modules and pixbuf loaders all
resolve against the host. libvulkan.so.1 is already bundled at the AppImage
root by electron-builder itself.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Improved Linux Whisper packaging by bundling the required libgomp.so.1 runtime with the artifact.
    • Builds and staging now provide clear, actionable errors when the runtime is missing or cannot be resolved.
    • Non-Linux packaging remains unaffected.
  • Documentation

    • Clarified bundled and host-provided Linux dependencies, including graphics, audio, GTK/GLib/NSS, and Vulkan driver requirements.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d85a797c-4d19-4261-83ee-36b00ed58ddb

📥 Commits

Reviewing files that changed from the base of the PR and between d3f1437 and b4dc916.

📒 Files selected for processing (1)
  • technical-documentation/engineering/build-and-packaging.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • technical-documentation/engineering/build-and-packaging.md

📝 Walkthrough

Walkthrough

Linux Whisper packaging now stages and validates libgomp.so.1. The AppImage documentation distinguishes bundled runtimes from host-provided graphics, audio, toolkit, and Vulkan-driver dependencies.

Changes

Whisper OpenMP packaging

Layer / File(s) Summary
OpenMP runtime staging and validation
scripts/build-whisper-stt.sh, scripts/stage-whisper-stt.sh
Linux builds resolve and stage libgomp.so.1. Local and downloaded artifacts fail validation when the runtime is missing.
Packaging dependency documentation
technical-documentation/engineering/build-and-packaging.md
The documentation identifies bundled libgomp.so.1 and libvulkan.so.1, plus host-provided graphics, audio, toolkit, and Vulkan-driver dependencies.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: bundling libgomp in the Linux AppImage.
Description check ✅ Passed The description clearly covers the change, scope, testing, and release follow-up, but it omits the repository template headings and checkbox metadata.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/appimage-bundle-libgomp

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…t declare it

1.9.2 declared the three sonames its packages needed and never asked for, which
fixed three formats out of four. The AppImage has no dependency mechanism at all,
so declaring anything does nothing for it: on a machine without libgomp.so.1 its
STT stack still dies in ld.so before main(), and transcription still shows an end
user a developer error.

Of those three, exactly one may be bundled, and it happens to be that one. The
AppImage project's excludelist names the other two and gives the reason:
libgbm.so.1 is "part of mesa" and talks to the host's DRM stack, libasound.so.2
loads the host's ALSA plugins and configuration. A bundled copy of either is
worse than none. libgomp is a self-contained runtime and is absent from that
list.

Nothing else was needed to make it resolve, which is worth recording:
whisper-stt-server and every libggml/libwhisper/libparakeet beside it already
carry `RUNPATH=$ORIGIN:$ORIGIN/bin`. A copy in that directory is found ahead of
the system one, so this needs no patchelf pass and no custom AppRun — both of
which the first sketch of this change assumed were unavoidable.

WHERE the copy is made matters more than that it is made. It happens in
build-whisper-stt.sh, on the machine that compiles these binaries, whose Linux
leg build-whisper-stt.yml pins to ubuntu-22.04 — the same floor before-pack.cjs
enforces. So the library that ships comes from the same machine and the same
glibc as the binaries that load it, and it travels inside the whisper artifact to
every consumer whatever their own distro.

The first version of this change copied it during packaging instead, and that was
wrong in a way worth naming: it took the library from whoever ran the build, so a
developer on 24.04 staged a libgomp needing GLIBC_2.38, before-pack.cjs correctly
refused it, and `npm run build:linux` stopped working locally for a change that
was supposed to be invisible there. Provenance was the fix, not a version check.

stage-whisper-stt.sh now only asserts the library arrived, and names the workflow
to re-run when an older artifact does not carry it. It checks on the early-exit
path too: that is the branch a developer with a locally built binary takes, and
skipping it there is how the AppImage would keep shipping without libgomp on
exactly the builds nobody re-checks.

Resolved through the binary rather than a hardcoded /usr/lib path so arm64 needs
no second case, and copied under its soname because that is the DT_NEEDED the
loader looks for; the file on disk is libgomp.so.1.0.0.

The libgomp1/libgomp entries added to deb, rpm and pacman in 1.9.2 stay. They are
redundant now that the copy travels with the binaries, and they cost nothing: if
this staging ever regresses silently, three formats out of four still resolve.

Verified: with the copy in place, ldd resolves libgomp through $ORIGIN to the
bundled file rather than the system one, and the STT binary loads on an
ubuntu:24.04 container that has no libgomp1 installed. Remove the staged copy in
that same container and it dies on "libgomp.so.1: cannot open shared object file".
@EtienneLescot
EtienneLescot force-pushed the fix/appimage-bundle-libgomp branch from fc8ef1c to d3f1437 Compare August 10, 2026 11:14

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@technical-documentation/engineering/build-and-packaging.md`:
- Line 132: Update the documentation reference to use the repository-relative
path scripts/stage-whisper-stt.sh, and verify any related source-code file paths
or line ranges still point to the intended staging implementation.
- Around line 130-134: Correct the AppImage dependency explanation in the
surrounding documentation: replace the claim that every system soname is missing
by construction with the statement that the AppImage has no host-dependency
manifest for this check. Preserve the existing descriptions of bundled
libgomp.so.1 and libvulkan.so.1 and the host-supplied libraries.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ee33f046-0974-4975-b84e-b64ac54e4101

📥 Commits

Reviewing files that changed from the base of the PR and between 5e8b9d2 and fc8ef1c.

📒 Files selected for processing (2)
  • scripts/stage-whisper-stt.sh
  • technical-documentation/engineering/build-and-packaging.md

Comment thread technical-documentation/engineering/build-and-packaging.md Outdated
Comment thread technical-documentation/engineering/build-and-packaging.md Outdated
Review catch, and a fair one. The paragraph said every system soname is missing
by construction for the AppImage, then described two that ship inside it —
libgomp.so.1 from this change, libvulkan.so.1 from electron-builder. Both cannot
be true.

What is actually true is narrower: the check verifies that everything a package
needs is either declared or shipped, and the AppImage declares nothing, so it
would report every library the format legitimately expects from the host. That is
the model working as intended rather than a defect, which is the reason the check
skips the format — not that its sonames are absent.

Both scripts also take the repository-relative path on first mention, which is
what the rest of this file does (`scripts/before-pack.cjs` then `before-pack.cjs`).
@EtienneLescot
EtienneLescot merged commit 53ae222 into main Aug 10, 2026
16 checks passed
@EtienneLescot
EtienneLescot deleted the fix/appimage-bundle-libgomp branch August 10, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant