Relocatability problem / where am I?

Hey, I’m trying to package GemRB as an AppImage and the creation itself is pretty standard and seems to work fine:

$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DSTATIC_LINK=on
$ make -j4
$ make install DESTDIR=./AppDir
$ LD_LIBRARY_PATH=./AppDir/usr/lib/gemrb linuxdeploy-x86_64.AppImage --appdir=./AppDir --output=appimage

The image runs, but I can’t get it to find stuff packaged in AppDir. I know AppRun changes dir to usr, but using a relative path doesn’t work:

$ strace ./GemRB-b672fc7b7-x86_64.AppImage |& grep unhardcoded
access("../share/gemrb/unhardcoded", R_OK) = -1 ENOENT (No such file or directory)
access("../share/gemrb/unhardcoded", R_OK) = -1 ENOENT (No such file or directory)
stat("../share/gemrb/unhardcoded/shared", 0x7ffd51de6208) = -1 ENOENT (No such file or directory)
[ResourceManager/WARNING]: Invalid path given: ../share/gemrb/unhardcoded/shared (shared GemRB Unhardcoded data)

The AppDir has two shared dirs (to be fixed later / temporary), but only the first one is key:

$ ls AppDir/*/*
AppDir/etc/gemrb:
GemRB.cfg  GemRB.cfg.noinstall.sample  GemRB.cfg.sample

AppDir/share/gemrb:
GUIScripts  minimal  override  unhardcoded

AppDir/usr/bin:
extend2da.py  gemrb

AppDir/usr/lib:
libs...

AppDir/usr/share:
applications  doc  icons  man  pixmaps

So since it’s supposed to be running from AppDir/usr, ../share/ should be correct. I also tried with share/ and files copied to the second share dir, and deeper backtracking (since the binary is in usr/bin), but nothing works. GemRB itself doesn’t change the CWD.

Any clues?

You can never know where the user “is” when your payload application gets executed. Hence, you should not try to load resources from a path relative to the current working directory of the user (cwd) as this is unreliable.

Instead, you need to figure out at runtime where your main payload application “is”, and construct a path to the resources to be loaded using that information.

Please change the source code of the application so that it loads resources from an absolute path constructed based on the path of the main binary.
For example, in Qt you can use QString QCoreApplication::applicationDirPath()) to construct such a path.

But isn’t the CWD in the appdir as far as we’re concerned? What’s the point of the cd in AppRun then?

It sounds like there’s no way to get AppImage-relative paths. I thought it worked like a chroot, hence the various assumptions. It’s odd AppRun doesn’t export appdir as an environmental variable, since it would eliminate the need for every payload to reimplement the same lookup. :confused:

Any further comment @probono? I’d like to avoid hardcoding too much to get appimage support, so better understanding is key.

AppImages export the environment variable “APPDIR”, which is the location the AppImage gets mounted to at runtime, is this what you’re referring to? It’ll be available in AppRun, and you can export it to the binaries, etc from there.

1 Like

That’s a dirty hack for legacy applications. Don’t rely on it. Use something like QCoreApplication::applicationDirPath() to construct the path.