The first users of Steps were people around me, most of them Linux users. All of them used either Debian or Ubuntu. So, those were the first platforms I targeted.

At first, and for a long time, the only way to get Steps was to copy the source code from me and build it. That required installing several -dev packages and messing in the command line. I had… maybe five friend that did this every now and then. But this was a major hassle, obviously.

Packaging for Debian & Ubuntu is not hard, and is widely documented. The web is full of tutorials on the subject. You can find guides that explain the nuances of packaging Python, Ruby or Qt apps.

The canonical way of packaging

The “canonical” way of creating .deb files is tailored for inclusion in the package archives of specific distros. Or, if you choose to have your own repository (say, a PPA), at least it’s expected to play nicely with the official ones.

More specifically, this means that when you package any app, say a Python or Qt one, you don’t bundle your dependencies with the package. You simply declare them in the package metadata.

By simply declaring your dependencies you reduce the size of your package drastically (you just ship your own code & content). And you gain all the advantages of sharing libraries: better disk usage, better memory usage, free bugfixes & updates, etc.

That is the way distros are designed and it’s a good thing in almost every way.

But I didn’t want to do that.

Installing was still a hassle

I tried it. I packaged Steps for some version of Ubuntu, I don’t remember exacty, it wasn’t even called Steps back then. You could download my .deb and install it with:

dpkg -i steps-for-ubuntu-x.y.deb

and it would fail on dependency problems. And then you could fix those with:

apt-get -f install          # Not elegant at all

Or you could add my own repo, that I never published on Launchpad or anything like it, by modifying your sources.list and running apt-get update and apt-get install steps.

One version per distro

Besides the hassle of installing, I still had to build and maintain one .deb file for each distro / suite I wanted to support. That meant Debian Stable, Debian Testing, Ubuntu 14.04, Ubuntu 14.10, etc.

If my friend decided to try Mint, or any other Debian derivative, I had to, potentially, create a new package and the dependencies could differ from version to version.

This was automatable, but still too much work for my taste, and the end result (the installation part) still didn’t please me.

AppImage

This packaging and distribution problems were not just mine. The Linux community at large is still looking for a reliable way for third parties to distribute apps that’s convenient, secure and easy for the users. That’s the driving force of Snaps and Flatpaks and probably more I haven’t heard of. On that quest I learned of AppImage, previously known as Klick.

AppImage is a system designed to bundle an app and all its dependencies and resources as a single file that can be given exec permission and will just run.

It uses a couple of clever tricks:

  • First, the entire file is an ISO-9660 filesystem with an small ELF executable in the boot sector. When given executable permission, the ELF program mounts the ISO filesystem and runs the app inside.
  • Second, all libraries are loaded from the ISO filesytem by patching all occurrences of /usr inside the app’s binary to ././, which makes it look for libraries under the current directory.

AppImages in theory work in any distro, be it Debian based, RedHat based or any other. You simply need to ensure that you include the required libraries.

However, I felt skeptic about AppImage. It seemed too specifically designed for binary apps that load libraries from /usr. And patching all occurrences of /usr felt fragile. What if I had a string in my app that happened to contain those four characters?

Still, my app fit the bill, so I tried it. Making it work was not particularly straightforward. I expected to have to copy library by library to the app’s AppDir (the source of the ISO-9660 filesystem), but it was way harder to test than I expected. Also the AppImage SDK tools failed repeatedly.

On top of that I realized that just running the app wasn’t everything. I lost a couple of benefits of packaging as a .deb file. The app didn’t register in the system menus (I would have to develop my own UI for that) nor it would register MIME types nor file associations.

A standalone .deb file

My final and current approach is to build a .deb file that declares no dependencies and bundles all libraries, but installs them under a non-standard directory like /usr/local/steps. Then, to run the app, it’s wrapped in a script like this:

#!/bin/sh

export QT_PLUGIN_PATH=/usr/local/steps...
export LD_LIBRARY_PATH=/usr/local/steps/...
exec /usr/local/steps/.../bin/steps

Of course, this works for my app, which uses Qt. For other types of apps the process would be different. This is just like building an AppImage.

But now I regain the possibility of properly setting up the desktop app, with menu items, file associations, etc.

And since the package has no dependencies, users can simply installing by using dpkg or, if a GUI app is available, just click a button:

Gdebi showing Steps about to be installed

If you feel like giving this standalone package a try, it’s available on Bintray. If you want to check the details of how the package is built, check the standalone-deb directory in Steps’s source code.