Call alternative binary from appimage?

THere are some appliactions that include more than one binary. I.e. Synfig have “bin/synfigstudio” (GUI) and “bin/synfig” (CLI for rendering). Opentoonz also besides main GUI binary have “tcomposer”, “tcleanup”, “tconverter”, “tfarmserver”, and more.

How it is possible to run those “alternative” binaries from appimage, instead of the main one?

In snapcraft this is implemented via dot, i.e. snapname.subcommand.

For appimage I probably can write a script wrapper for default binary, that accepts some argument, like this:
some.appimage --appbin tconverter ...

Just want to know - maybe there are some common practice already exists?

2 Likes

AppImage is centered around GUI applications, just like .app bundles on macOS.

The usual way is that the AppRun file inside the AppImage puts usr/bin onto the $PATH that is seen by the main executable in the AppImage. This means that the main GUI executable can call additional (usually: command-line helper) binaries just like if they were on the system’s $PATH.

If you want to bundle multiple command-line binaries inside an AppImage, then you could define bash as your main executable…

I see - there is no common practice yet.

In this case I would like to provide the opportunity to run alternative binary in the appimages managed by me (OpenToonz, Synfig, and future ones).

This is what I am planning to do:

  • Add a wrapper script, which will look if first cli argument is --appimage-exec and if second argument also have some value
  • If no --appimage-exec argument or no second argument defined, then run default binary
  • If --appimage-exec argument exists, then run application, specified by second cli argument.

Since I am going to enforce this approach on my appimages, I REALLY would like to have an agreement on some standard way on achieving this. In particular, I would like to agree on the option name - will it be called --appimage-exec or something else? In this case user will know - “aha, I can try to run alternative binary with exactly this option”.

In the best possible way it would be awesome if this option will be handled by AppRun script by default. In this case the use of AppImages could be expanded beyond of GUI applications, which is a big benefit.

When the project was still called klik, we checked if $1 was on the $PATH and if yes, executed $@.

With this approach it will not be possible for user to manually associate his files with AppImage executable. Because calling “file.appimage some_file” will try to call “some_file” command instead of opening file.

The advantage of approach with --appimage-exec option is that it also leaves the room to expand future set of options handled by AppRun. I.e. in the future it is possible to add some other --appimage-* options, which extend functionality bundled with AppImage container.

For example, it could be nice to have --appimage-integrate, which will create all necesary desktop files (I know, there is already desktopintegration script available, but it really would be nice to have such feature bundled directly into AppRun).

Well, the architectural question is what should be handled by AppRun (YOUR launcher that is supposed to also work outside of an AppImage, e.g., in a standalone AppDir) vs. AppImage’s runtime.c (common to all AppImages)… which already has some --appimage-... options.

Ah, I didn’t know that. Well, so my “blind shot” about option name hit to the point.

OK, I have added “–appimage-exec” option to OpenToonz appimage now:

…and provided usage instructions:

I would really prefer this option to be supported natively by AppImage runner. :slight_smile:

Looks like this is a really old topic that had already been discussed a very long time ago :slight_smile:

So, what do others think? Conceptually I think this should go into AppRun.

1 Like

Also see https://github.com/AppImage/AppImageSpec/issues/7

Check out the new $ARGV0 environment variable that gets exported by the AppImage runtime since https://github.com/AppImage/AppImageKit/commit/63485edeb854e8e830f201280a61bb803a4ddaa3

Example of how this can be used:

me@host:~$ ln -s Downloads/ippsample-git.4fbfa3f-x86_64.AppImage ipptool

me@host:~$ ./ipptool 
Usage: ipptool [options] URI filename [ ... filenameN ]
(...)

me@host:~$ ln -s Downloads/ippsample-git.4fbfa3f-x86_64.AppImage ippserver

me@host:~$ ./ippserver 
Usage: ippserver [options] "name"
(...)

This is achieved by using this custom AppRun script: https://github.com/probonopd/ippsample/blob/patch-1/appimage/AppRun

#!/bin/bash

# The purpose of this custom AppRun script is
# to allow symlinking the AppImage and invoking
# the corresponding binary depending on which
# symlink was used to invoke the AppImage

HERE="$(dirname "$(readlink -f "${0}")")"

if [ ! -z $APPIMAGE ] ; then
  BINARY_NAME=$(basename "$ARGV0")
  if [ -e "$HERE/usr/bin/$BINARY_NAME" ] ; then
    exec "$HERE/usr/bin/$BINARY_NAME" "$@"
  else
    exec "$HERE/usr/bin/ippserver" "$@"
  fi
else
  exec "$HERE/usr/bin/ippserver" "$@"
fi
1 Like

Thank you for implementing this!! $ARGV0 is exactly what I needed.

Umm… @probono I have read in some of your posts (do not remember exact link) that the concept of AppImage is “to have nothing installed”. In case of using $ARGV0 approach (and thus symlinking to some file) is actually means some kind of installation, From this point of view I find “–appimage-exec” approach more flexible. Sorry for critique, just found this is kind of pops-out from appimage concept.

I would say this is in the domain of what is inside the AppImage, and hence each author of an AppImage can decide. It is not something the AppImage format needs to (or should) mandate.

As an author of an AppImage, you can implement this kind of functionality either in the payload application or in a custom AppRun script.

What about an environment variable that you set before running the AppImage such as ${APPIMAGE_EXEC} this would have the advantage of your custom flag along with not breaking compatibility with other AppImages? It would also have the advantage of not requiring the AppImage to be called via another filename

1 Like

Another argument I can see to such a feature in the AppImage by default is so integration tools can integrate the same commands the appimage can use

Else, we would be in a situation where these tools can manage to run multiple binaries (by listing the usr/bin folder for example), but the AppImage alone can’t if the application author didn’t configure it to do so

(I’ve made a feature request at [Feature] Integrate commands of AppImages in the system · Issue #532 · TheAssassin/AppImageLauncher · GitHub but it has not been accepted yet)

The main way to use AppImages is double-clicking them in the file manager. Just like with .app bundles on the Mac, this implies that each AppImage holds one (main) application.

For command line tool collections like ImageMagick there is the workaround of invoking different commands based on the name of the symlink an AppImage is accessed under. But that is rather a special case.

Usually, “one app = one file”.

@probono Has there been any revisions to this script since you posted it?

Not that I am aware of. You could check what AppRun ImageMagick is using these days; iirc they also wanted this kind of functionality.

@probono I was just looking for a template to use for the 0ad-appimage. Apparently the appimage docs are outdated? source/packaging-guide/manual.rst:add anchor to "this repository" by andy5995 · Pull Request #85 · AppImage/docs.appimage.org · GitHub

I just did this:

#!/bin/sh

# The purpose of this custom AppRun script is
# to allow symlinking the AppImage and invoking
# the corresponding binary depending on which
# symlink was used to invoke the AppImage
# make sure errors in sourced scripts will cause this script to stop
set -e

HERE="$(readlink -f "$(dirname "$0")")"
source "$HERE"/apprun-hooks/"linuxdeploy-plugin-gtk.sh"
BINARY_NAME=$(basename "$ARGV0")

if [ "$BINARY_NAME" = "pyrogenesis" -o "$BINARY_NAME" = "0ad" ] ; then
  exec "$HERE/usr/bin/pyrogenesis" "$@"
elif [ "$BINARY_NAME" = "ActorEditor" ]; then
  exec "$HERE/usr/bin/ActorEditor" "$@"
else
  exec "$HERE/usr/bin/pyrogenesis" "$@"
fi