Native Linux apps¶
This guide covers packaging pre-built Linux binaries distributed as tarballs, AppImages, RPMs or DEBs.
Generic tarballs¶
If upstream ships a "generic" .tar.gz or .tar.xz that works on most distributions, this is the easiest case:
<?xml version="1.0"?>
<interface xmlns="http://zero-install.sourceforge.net/2004/injector/interface">
<name>MyApp</name>
<summary>does something useful</summary>
<homepage>https://example.com/myapp</homepage>
<icon href="https://example.com/myapp.png" type="image/png"/>
<feed-for interface="https://example.com/myapp.xml"/>
<group license="MIT">
<command name="run" path="bin/myapp"/>
<implementation arch="Linux-x86_64" version="{version}" released="{released}" stability="stable">
<manifest-digest/>
<archive href="https://example.com/downloads/myapp-{version}-linux-x64.tar.gz"/>
</implementation>
<implementation arch="Linux-aarch64" version="{version}" released="{released}" stability="stable">
<manifest-digest/>
<archive href="https://example.com/downloads/myapp-{version}-linux-arm64.tar.gz"/>
</implementation>
</group>
</interface>
arch="Linux-x86_64" covers AMD64 CPUs. Other common values are Linux-i486 (32-bit), Linux-aarch64 (ARM64) and Linux-armv7l (ARMv7).
Single-binary downloads¶
For tools shipped as a single executable (common for Go and Rust binaries), use <file> instead of <archive> and mark it executable:
<implementation arch="Linux-x86_64" version="{version}" released="{released}" stability="stable">
<manifest-digest/>
<file dest="myapp"
executable="true"
href="https://github.com/example/myapp/releases/download/v{version}/myapp-linux-amd64"/>
<command name="run" path="myapp"/>
</implementation>
RPMs and DEBs¶
Zero Install can extract .rpm and .deb packages without installing them. The contents are unpacked into a per-user cache, so users without root can run them and the app must work outside /usr.
Tip
When upstream doesn't publish a generic tarball, an RPM often works on Debian (and vice versa). If several distro-specific packages are available, pick the one for the oldest distribution: packages built against an older glibc keep working on newer systems, but not the other way around.
<implementation arch="Linux-x86_64" version="{version}" released="{released}" stability="stable">
<manifest-digest/>
<archive href="https://example.com/downloads/myapp-{version}.x86_64.rpm"
type="application/x-rpm"/>
<command name="run" path="usr/bin/myapp"/>
</implementation>
The path is relative to the unpacked tree, so a binary that the package installs at /usr/bin/myapp is at usr/bin/myapp after extraction.
Attention
This only works if the binary is relocatable. Apps that hard-code paths like /usr/share/myapp will need either a binreloc-aware build or a <recipe> to patch the install. The original Inkscape RPM was recompiled with binreloc support specifically for this reason.
Shell-script launchers that cd to a hard-coded directory are the same problem in miniature. The cleanest fix is upstream (cd "$(dirname "$0")" is portable); if that's not an option, use a <recipe> to patch the script, and compute the post-patch implementation ID with 0install digest on the patched tree.
AppImages¶
AppImages are self-mounting ELF files; they cannot be unpacked with the built-in archive types. Either:
- Re-archive them as a tarball (
./myapp.AppImage --appimage-extract && tar czf myapp.tar.gz squashfs-root/) and host the result yourself, or - Ask upstream to publish a regular tarball alongside the AppImage.
Once re-archived, package as a regular tarball with command="run" path="AppRun" (the standard AppDir entry point).
Shared library dependencies¶
If your app links against shared libraries published as their own feeds, add a <requires> and bind the library directory into LD_LIBRARY_PATH:
<requires interface="https://example.com/somelibrary.xml">
<environment name="LD_LIBRARY_PATH" insert="lib"/>
</requires>
For libraries provided by the host distribution (glibc, libc++, etc.), use <package-implementation> to declare the dependency without trying to repackage system libraries:
<package-implementation distributions="Debian Ubuntu" package="libcurl4"/>
<package-implementation distributions="RPM" package="libcurl"/>
See Distribution integration for the list of recognized distribution names.
Tip
Set <needs-terminal/> on console apps so GUI launchers open a terminal.