Build Fix Report: WSL 2 libgbm Linker Failure
System
- Project: Emerge — an Elixir GUI framework backed by a Rust NIF (
emerge_skia) using Skia for rendering
- Environment: WSL 2, Ubuntu 22.04 (Jammy) on x86_64
- Build toolchain: Elixir/Mix + Rustler (NIF bridge) + Cargo
Problem
mix compile failed at the Rust link step:
rust-lld: error: unable to find library -lgbm
The crate unconditionally declared gbm = "0.18" and drm = "0.14" as Cargo dependencies. These crates link against the system libgbm (Mesa's Generic Buffer Manager), which is only needed for the DRM backend — bare-metal framebuffer rendering with no window manager. That backend is irrelevant on WSL 2, which uses WSLg (a Weston compositor over RDP to Windows DirectX).
Root Cause of System State
libgbm1 v25.0.5 was installed from the kisak-mesa PPA. The only available libgbm-dev package requires libgbm1 = 23.2.1 exactly (strict pin). The kisak-mesa PPA for Ubuntu 22.04 was subsequently discontinued, leaving the system with a newer runtime than any matching dev package — an unresolvable apt conflict.
What Was Attempted (and Why It Failed)
| Attempt |
Failure reason |
apt install libgbm-dev |
Version conflict: installed libgbm1 is v25, dev package requires v23 |
apt install --allow-downgrades libgbm1=23.2.1 |
Cascading conflicts: entire Mesa 25 stack (libegl-mesa0, etc.) is entangled |
add-apt-repository --remove ppa:kisak/kisak-mesa |
Removes source list only; installed packages remain at v25 |
apt install ppa-purge && ppa-purge ppa:kisak/kisak-mesa |
PPA discontinued for Jammy — no package list to diff against; ppa-purge reports "could not find package list" even after re-adding the PPA source |
Re-add PPA, then ppa-purge |
Same failure — PPA metadata for Jammy is gone |
Conclusion: No apt-level fix was viable. The Mesa install is permanently broken for this purpose.
Why a Code Fix Was the Right Path
libgbm is not needed for:
- The Wayland backend (winit + glutin + EGL, used on WSL 2 via WSLg)
- The raster backend (offscreen CPU rendering)
- Any tests
It is needed exclusively for the DRM backend (src/backend/drm.rs, src/drm_input.rs), which requires direct GPU framebuffer access — impossible in WSL 2.
Rustler supports a features: option that passes Cargo feature flags at compile time, configurable from Elixir application config.
What Was Changed
native/emerge_skia/Cargo.toml
- Added
[features] section with drm = ["dep:drm", "dep:gbm", "dep:evdev"]
- Made
drm, gbm, evdev optional dependencies
- Kept
libc as a required dep (also used in src/video.rs)
native/emerge_skia/src/backend/mod.rs
- Gated
pub mod drm behind #[cfg(feature = "drm")]
native/emerge_skia/src/lib.rs
- Gated
mod drm_input and its use imports
- Gated
BackendKind::Drm enum variant
- Gated the
BackendKind::Drm match arm in stop() (the Drop impl)
- Gated the
BackendKind::Drm match arm in start_with_config()
- Gated
"drm" string → BackendKind::Drm parsing; returns a clear error if DRM feature is not compiled
- Added
#[cfg_attr(not(feature = "drm"), allow(dead_code))] on drm_card, drm_hw_cursor, drm_input_log fields
- Annotated
bounded::<RenderMsg> for type inference (previously inferred from the DRM branch)
- Used
_cursor_rx + conditional rebind to suppress unused variable warning
lib/emerge_skia/native.ex
- Added
features: Application.compile_env(:emerge, :emerge_skia_features, []) — reads Cargo features from Elixir app config, defaulting to none
Result
mix compile succeeds with no linker errors
mix test: 179 tests, 0 failures
- DRM backend code remains in the repo, intact
- To enable DRM on a system with
libgbm-dev: config :emerge, emerge_skia_features: ["drm"]
Build Fix Report: WSL 2
libgbmLinker FailureSystem
emerge_skia) using Skia for renderingProblem
mix compilefailed at the Rust link step:The crate unconditionally declared
gbm = "0.18"anddrm = "0.14"as Cargo dependencies. These crates link against the systemlibgbm(Mesa's Generic Buffer Manager), which is only needed for the DRM backend — bare-metal framebuffer rendering with no window manager. That backend is irrelevant on WSL 2, which uses WSLg (a Weston compositor over RDP to Windows DirectX).Root Cause of System State
libgbm1v25.0.5 was installed from the kisak-mesa PPA. The only availablelibgbm-devpackage requireslibgbm1 = 23.2.1exactly (strict pin). The kisak-mesa PPA for Ubuntu 22.04 was subsequently discontinued, leaving the system with a newer runtime than any matching dev package — an unresolvable apt conflict.What Was Attempted (and Why It Failed)
apt install libgbm-devlibgbm1is v25, dev package requires v23apt install --allow-downgrades libgbm1=23.2.1libegl-mesa0, etc.) is entangledadd-apt-repository --remove ppa:kisak/kisak-mesaapt install ppa-purge && ppa-purge ppa:kisak/kisak-mesappa-purgereports "could not find package list" even after re-adding the PPA sourceppa-purgeConclusion: No apt-level fix was viable. The Mesa install is permanently broken for this purpose.
Why a Code Fix Was the Right Path
libgbmis not needed for:It is needed exclusively for the DRM backend (
src/backend/drm.rs,src/drm_input.rs), which requires direct GPU framebuffer access — impossible in WSL 2.Rustler supports a
features:option that passes Cargo feature flags at compile time, configurable from Elixir application config.What Was Changed
native/emerge_skia/Cargo.toml[features]section withdrm = ["dep:drm", "dep:gbm", "dep:evdev"]drm,gbm,evdevoptional dependencieslibcas a required dep (also used insrc/video.rs)native/emerge_skia/src/backend/mod.rspub mod drmbehind#[cfg(feature = "drm")]native/emerge_skia/src/lib.rsmod drm_inputand itsuseimportsBackendKind::Drmenum variantBackendKind::Drmmatch arm instop()(theDropimpl)BackendKind::Drmmatch arm instart_with_config()"drm"string →BackendKind::Drmparsing; returns a clear error if DRM feature is not compiled#[cfg_attr(not(feature = "drm"), allow(dead_code))]ondrm_card,drm_hw_cursor,drm_input_logfieldsbounded::<RenderMsg>for type inference (previously inferred from the DRM branch)_cursor_rx+ conditional rebind to suppress unused variable warninglib/emerge_skia/native.exfeatures: Application.compile_env(:emerge, :emerge_skia_features, [])— reads Cargo features from Elixir app config, defaulting to noneResult
mix compilesucceeds with no linker errorsmix test: 179 tests, 0 failureslibgbm-dev:config :emerge, emerge_skia_features: ["drm"]