Create AppImage With linuxdeploy AND CMAKE

An AppAImage is simply a method to create a single executable file with all of the program dependencies, assets and etc inside the file. This allows for executing the program on any system that supports the AppImage without having to have all the dependencies installed on the system. Such as libraries. Basically, a self-contained executable file. Many open-source projects use, like Godot, OpenRA, and many more.

The way AppImage works, in general, is by simply creating a fake root file system, using squashfs. which is a lightweight filesystem. Inside the directory you will find, in many applications, using a similar structure as your real Unix-based root file system is setup. like directories like /usr/lib and /usr/bin and etc.


Explore Existing AppImage

The best way to get an understanding would be to download an AppImage that you perhaps use and have a good understanding of what it does and etc.

All AppImage has dedicated command line options associated with the AppImage itself. In order to see the whole list, use the following commands.

MyApp.AppImage --appimage-help
AppImage options:
 --appimage-extract []  Extract content from embedded filesystem image
                                   If pattern is passed, only extract matching files
   --appimage-help                 Print this help
   --appimage-mount                Mount embedded filesystem image and print
                                   mount point and wait for kill with Ctrl-C
   --appimage-offset               Print byte offset to start of embedded
                                   filesystem image
   --appimage-portable-home        Create a portable home folder to use as $HOME
   --appimage-portable-config      Create a portable config folder to use as
                                   $XDG_CONFIG_HOME
   --appimage-signature            Print digital signature embedded in AppImage
   --appimage-updateinfo[rmation]  Print update info embedded in AppImage
   --appimage-version              Print version of AppImageKit

The command –appimage-extract will extract the file similar to when you extract files from a zip/archive file. That way, it will become apparent how AppImage is structured internally.

MyApp.AppImage --appimage-extract

An example would be the OpenRA Red Alert AppImage. By executing the AppImage with the extract command option, we get the following outputs and etc.

 ./OpenRA-Red-Alert-x86_64.AppImage --appimage-extract
 squashfs-root/.DirIcon
 squashfs-root/AppRun
 squashfs-root/etc
 squashfs-root/etc/mono
 squashfs-root/etc/mono/4.5
 squashfs-root/etc/mono/4.5/machine.config
 squashfs-root/etc/mono/config
 squashfs-root/openra-ra.desktop
 squashfs-root/openra-ra.png
 squashfs-root/usr
 squashfs-root/usr/bin
 squashfs-root/usr/bin/gtk-dialog.py
 squashfs-root/usr/bin/mono
 squashfs-root/usr/bin/openra-ra
 squashfs-root/usr/bin/openra-ra-server
 squashfs-root/usr/bin/openra-ra-utility
 squashfs-root/usr/bin/restore-environment.sh
 squashfs-root/usr/lib
 .........

Looks very similar to the file structure on many Unix based system, with the /usr/bin and /usr/lib.

Though, it should be mention that it is possibly not necessary required to have the same structure as the Unix file system. Since the first thing to be executed is the AppRun file.


Configure CMAKE

When building an AppImage, The installation properties for both executable and library has to be set. Furthermore, for any additional asset files, the program will use. See the following for library and executable targets.

# Setup library and executable targets.
ADD_LIBRARY(mylib lib.cpp)
ADD_EXECUTABLE(myBin main.cpp)
# Install targets.
INSTALL(TARGETS mylib DESTINATION lib)
INSTALL(TARGETS myBin DESTINATION bin)

Once the CMake file has been configured, the following commands can be invoked. It will create a dedicated directory to build, followed by the install prefix. This will override the default install prefix that CMake assigns. Followed by simply invoking make, or whatever build system you use. Once is compiled successfully, You can install it, by override the root directory for where it will install. In this case, it will be AppDir. It should not be required to call the directory AppDir.

mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
make -j $( nproc )
make install DESTDIR=AppDir

Once all of the previous commands are successful, we can proceed with the next section.


Build Image with LinuxDeploy

Note, the following mention program as of this writing is still in Alpha. Though, still a useful tool. The following is an example of what argument should be added.

  • –appdir is the root installed directory. It is the same directory that DESTDIR was assigned to previously.
  • –icon-filename is the path to the icon image it will use. (note it can be picky with the resolution)
  • –icon-file the name of the icon file inside the AppImage. Note this is the name that the desktop file used in its configuration.
  • –desktop-file the path to a valid desktop file.
  • –output what kind of output format.

Note, that the desktop file is important since the program will use its configuration for which executable it will invoke.

./linuxdeploy-x86_64.AppImage --appdir AppDir/ --output appimage --icon-filename --desktop-file myprogram.desktop --icon-file icon

Following is an example of a desktop file. using the file extension .desktop.

[Desktop Entry]
Type=Application
Version=1.0
Name=MyProgram
Comment=a very cool software
Exec=myprogram
Icon=icon
GenericName=MyProgram
Categories=Utility
Terminal=false

The output filename as of writing does not seem to be able to be set. Rather, it is implicitly set by the name, that is configured in the desktop file. Whereas the version by default set by git commit hash. However can be set setting the environment variable VERSION. For instance, as following.

export VERSION="0.1.0" 

HotFix Finding Library in Other Paths

The program will automate much of the process such as finding libraries dependencies your program uses. However, if you use libraries associated with your executable target in CMake, you will have to add a search path for its explicitly as an argument with linuxdeploy. This can be resolved by using the LD_LIBRARY_PATH environment variable.

export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:path_to_my_program_library_directory"

Quick About Handle File Management

Finally, A quick note about handle the relative file path inside the AppImage, Since the current directory is set to some random directory. It can become a bit of a challenge for the file management to make sure that the program can find its files.

Environment Variables

It is possible to get some useful data from the environment variables that AppImage creates when executing it. These can be used to handle File Management. See the AppImage website documentation. The APPDIR is useful to get the root directory path for the AppImage. From there it is simply a matter of computing the relative path of your asset files.


Conlsusion

AppImage can allow for creating a single deployable executable that is easier to run on any system that supports Linux/Unix. Since it does not require all dependent apt-packages to be available. However, there is an initial setup and potential changes required in the code to handle file paths. Though, it can be provided with a great way to share programs without having to do much setup.