Linux packaging

Published October 20, 2021

Linux packaging is weird. That’s not really a strange topic if you’re familiar with Linux, but it bears mentioning nonetheless. Linux supports software as packages, which are downloaded with package managers which can vary between distros. There are two major packaging formats, being RPMs and DEBs, from Red Hat and related distros and Debian based distros respectively. Some smaller distros, like Arch, have their own packaging formats, to add to the confusion. Running Arch and using Linux for packaging, I am a big fan of using packages to install and manage software. As a result, I have written some packages for software which is not provided normally. That’s where the problem comes, each of the above systems have their own methods of packaging which is generally incompatible with each other.

Running Arch on my desktop systems, I have the most experience with writing Arch packages. I currently maintain a number of packages on the AUR and have even written a script to automatically build my own packages. Arch packages are defined with a PKGBUILD file. The PKGBUILD describes the package information and steps to build and package the software. Fundamentally the file is a bash script, with the information as bash variables and the build information as specific named functions. This makes it fairly easy to build software, as the exact build commands can be written into a function to mimic exactly what would be typed to build manually. This makes it very easy to alter the build and package behaviour, as any changes can be directly entered as bash commands. There even is the ability to build straight from a version control tree, providing the most up to date version of the software possible. All of this is fairly well documented on the arch wiki, lending some credence that such modification is the expected behaviour of writing PKGBUILDs. This makes it fairly easy to package arch software, with it able to be done with little previous setup on the computer. This ease helps form the AUR, one of the best things about Arch.

RPMs are a little weird. RPMs are built from SPEC files, and have to have a certain directory structure to use the provided tools. The documentation from Red Hat is fairly good, if a little lengthy and lacking in some parts. It generally covers most parts of writitng RPM SPEC files, but leaves out troubleshooting steps and doesn’t explain some functions. SPEC files start with documentation about the package and proceed to go into steps for building the package. The file is split into sections with headers denoted with a “%”. A number of macros are provided to make it easier to build packages. These macros are denoted with the same “%” as the headers, making it difficult to differentiate between the two. SPEC files also require all built and installed files to be included, ensuring what is installed is intended. This can make it hard to update packages though, but is an interesting feature. In general, the macros can be ignored and standard commands can be used to build the software. While I prefer the function approach of Arch’s PKGBUILDs, this is still a fairly straightforward approach.

DEBs are my least liked packaging method. DEBs require a source tarball to be in the source’s parent directory and there to be a debian folder containing package information to be added to the source directory. The DEB directory needs to exactly match the tarball, with the exception of the debian directory, making it hard to modify the package before building. This nearly excludes the prossibility of building from a git tree. The debian directory contains a number of files relating to various parts of the build process, which is poorly describes on the debian wiki. The build “rules” file is structured like a makefile, with a number of standard rules which can be explicitly overridden, although these steps are hard to find. As a result, it is easier to modify a project’s Makefile, and let the “dh” build tool do the rest. This results in many iterations altering the source tree until the package builds as intended. In general, I found this method to nearly be more of a pain than its worth.

At the moment, there is a rise of cross platform packing formats, such as flatpak, snap and appimage. These are isolated environments which come with their own dependencies, allowing them to be run on any distro. The idea generally is to prevent developers from having to write multiple packages for each distro. Unfortunately, these packages tend to be larger in size (having to ship a full or partial system along with the package), can have performance penalties and can interact poorly with the rest of the system. While they can provide sandboxing for applications, I don’t think that they justify their comprimises to replace most, if not all standard distro binary packages.

In summary, I am not a fan of the dissarray of Linux packaging solutions. It is too hard to write a package to suit every system, with some systems allowing easy granular control and others providing many features automatically. My favourite solution is Arch’s PKGBUILDs, as I find them to be the best documented and provide the most flexibility in packaging. RPMs come in as a second, with some interesting features which Arch is lacking, but with some syntax ambiguity and annoyances. Debian comes in last, having the worst, easily accessable documentation by far and generally being a chore to use. I have yet to experiment with the “next gen”, cross platform solutions, but as stated, am generally not a fan of the approach they take. I think that as these formats will not merge, as each distro is comitted to their tools, a tool to easily convert from one form to another is needed. Or, failing that a tool to move from a generic system to one specific to each distro. I think that this could remove the need for the “next gen” packaging solutions. Ideally this would allow for maximum flexibility and reduce developed load in packaging for different systems.