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)
- 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.
- 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).
Summary
emb cross … --deploy --runof an ivi-homescreen runnable bundle dies at launch on the target:The auto-staging correctly ships the library —
lib/libihs_shared.so.1is 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.soandlibapp.soare unaffected because they'redlopen'd by absolute path;libihs_shared.so.1is a link-timeNEEDEDentry resolved by the dynamic loader, which never looks in./lib/.Reproduce
Build + deploy succeed; the
--runstep exits 127 with the error above.Root cause
The runnable bundle is correct:
But the binary's dynamic section:
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.dartinstall()— copies the embedder verbatim (copySync+chmod 0755); no RPATH patch.lib/src/cross/deployer.dartrunArgv()— runscd <destDir> && ./homescreen -b .; noLD_LIBRARY_PATH.Workaround
Proposed fix (either, prefer the first)
$ORIGIN/libwhen staging inRunnableBundle.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 onpatchelfavailability.LD_LIBRARY_PATH=<destDir>/libinDeployer.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/--tarif it ever links a private.so.Environment
LD_LIBRARY_PATHis set (validated live: LayerScene direct-scanout, zero errors).