Skip to content

cross --deploy --run: staged libihs_shared.so.1 not found — RPATH points at host build dirs, not $ORIGIN/lib #113

Description

@jwinarske

Summary

emb cross … --deploy --run of an ivi-homescreen runnable bundle dies at launch on the target:

./homescreen: error while loading shared libraries: libihs_shared.so.1: cannot open shared object file: No such file or directory

The auto-staging correctly ships the library — lib/libihs_shared.so.1 is present in the runnable bundle and rsynced to the device — but the embedder binary can't find it at exec time because its RPATH points at the host build directories, not $ORIGIN/lib.

This affects every --deploy --run (all backends) since ivi-homescreen's shell started linking the ihs_shared logging library (ivi-homescreen #295). libflutter_engine.so and libapp.so are unaffected because they're dlopen'd by absolute path; libihs_shared.so.1 is a link-time NEEDED entry resolved by the dynamic loader, which never looks in ./lib/.

Reproduce

emb cross . --target rpi4-trixie --backend drm-kms-egl -D BUILD_COMPOSITOR=ON \
  --build --app <flutter-app> --mode release \
  --deploy joel@raspberrypi.local --run --no-verify

Build + deploy succeed; the --run step exits 127 with the error above.

Root cause

The runnable bundle is correct:

~/ivi-homescreen/
  homescreen
  lib/libapp.so
  lib/libflutter_engine.so
  lib/libihs_shared.so.1   # staged, present on device

But the binary's dynamic section:

readelf -d homescreen | grep -E 'NEEDED|RPATH'
 (NEEDED)  Shared library: [libihs_shared.so.1]
 (RPATH)   Library rpath: [/…/cross-build-…/build-drm-kms-egl:/…/cross-build-…/build-drm-kms-egl/shared:]

Those RPATH entries are the host build tree, absent on the device, so the loader falls through to the default search path and misses ./lib/.

Two spots in the deploy path assume the loader will find the staged libs but neither arranges for it:

  • lib/src/cross/runnable_bundle.dart install() — copies the embedder verbatim (copySync + chmod 0755); no RPATH patch.
  • lib/src/cross/deployer.dart runArgv() — runs cd <destDir> && ./homescreen -b .; no LD_LIBRARY_PATH.

Workaround

cd ~/ivi-homescreen && LD_LIBRARY_PATH=$PWD/lib ./homescreen --backend drm-kms-egl -b . -d

Proposed fix (either, prefer the first)

  1. Patch the embedder RPATH to $ORIGIN/lib when staging in RunnableBundle.install() (e.g. patchelf --set-rpath '$ORIGIN/lib', or --add-rpath). Makes the bundle self-contained and correct regardless of how it's launched (rsync, .tar.gz, .deb, flatpak). Guard on patchelf availability.
  2. Export LD_LIBRARY_PATH=<destDir>/lib in Deployer.runArgv() (prefix the command). Cheaper, but only fixes --run — a bundle launched any other way still breaks, so this is a fallback, not the real fix.

Option 1 also fixes the non-deploy runnable bundle used for --target local/--tar if it ever links a private .so.

Environment

  • host x86_64 → RPi4 (raspios trixie arm64), arm-gnu 15.2, drm-kms-egl.
  • Bundle otherwise renders correctly once LD_LIBRARY_PATH is set (validated live: LayerScene direct-scanout, zero errors).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions