Alan Pope
on 24 January 2019
Zero to Snap – Rev up your packaging
Software developers often have enough to worry about. Their focus is creating the best application they can, often without having to consider packaging.
We recently discovered Akira, which illustrates this well. The small team of developers are hard at work on the application, so software packaging isn’t a high priority at the moment.
Akira is a
We’re not specifically endorsing Akira, or recommending you back their campaign. We figured this was a good example to illustrate packaging software for a small team.
If the campaign is successful, they’ll be keen to get fast feedback from intrepid users who are willing to test out bleeding-edge builds.
This sounds like a job for snapcraft!
I created a snap of Akira and thought I’d use this opportunity to explain the process I went through. Developers looking to package their application might learn from the steps I took, and the resulting snapcraft.yaml
.
The snap store has a concept of channels. The edge channel is typically hooked directly up to a git repo, delivering daily or per-commit builds of software to the store. Adventurous users can accept this risk and install software from the edge channel, knowing the latest build may sometimes contain bugs.
Start at the beginning
I started by forking the upstream project on GitHub, and made a branch to work in.
After a few iterations I had a successful build of the application and submitted a pull request to the upstream developers. Note though, that Akira is very early in development, so don’t expect a finished product if you follow along and build this particular snap yourself. It’s still a good learning exercise though!
I’ve put links to documentation through this post so you can find out more about the topics covered. You can also join the community over on the snapcraft forum, where a friendly group of snapcraft developers and users hang out.
What’s in a name
Every snap needs some basic metadata. Here we set the snap name as it will be registered in the store, a short summary and description. The description may contain multiple lines.
It will be the text which appears in the snap store, and in the output of snap info
icon
setting points to the existing icon file in the project source tree.
name: akira
summary: Akira
description: |
Native Linux App for UI and UX Design built in Vala and Gtk
icon: data/assets/icons/com.github.alecaddd.akira.png
Version therapy
Snapcraft has multiple ways to set the version number of a project at build time. It can be hard coded version: x
version: git
version-script:
is more flexible, in that you can run any arbitrary command to determine the version string. For example, you could cat or grep the version string from a file in the source tree.
I adopt-info
snapcraftctl
set-version
command. I just had to nominate the part that was going to be driving the version string for this snap.
adopt-info: akira
Heavy on the base
base
core
core18
base can be considered to map to Ubuntu 18.04. Previously the core
base: core18
Living in a box
Strict confinement provides the snap with a restricted runtime environment. No need to change this default.
confinement: strict
Spare parts
Parts are typically where the bulk of work is done constructing a snap. A simple command-line snap may contain just one part, the application itself. Graphical applications require more interdependent components to be built will often need a bit more work.
In the case of Akira – a GNOME application – I needed separate parts for Akira itself, an up to date build of the granite library, a bundle of GNOME desktop libraries, and a set of scripts to successfully launch Akira on any desktop environment, GPU and Linux distribution.
parts:
akira:
after: [granite, desktop-gnome-platform]
after
after
stanza to
plugin: meson
meson-parameters:
- --prefix=/usr
source: .
Akira is written in Vala, uses meson to build, and requires a few additional libraries. All of these are listed as build-packages
(below). We use meson
snapcraft.yaml
is intended to live in the upstream tree, the source
line merely points to the current directory, but the source code could be elsewhere, in a git,
override-build: |
snapcraftctl build
sed -i 's|Icon=com.github.alecaddd.akira|Icon=${SNAP}/data/assets/icons/com.github.alecaddd.akira.png|' ${SNAPCRAFT_PART_INSTALL}/usr/share/applications/com.github.alecaddd.akira.desktop
override-build
.desktop
file to adjust the path to the desktop icon.
The build-packages stanza details the packages required at build time to compile this part. This list was taken from the upstream build documentation.
build-packages:
- libgtk-3-dev
- valac
- libgranite-dev
- libjson-glib-dev
- libgudev-1.0-dev
- libevdev-dev
- libgtksourceview-3.0-dev
- libxml2-dev
- libglib2.0-dev
Voyage of discovery
Often when making snaps, time can be spent iterating over a build, adding missing libraries. This can be time consuming, so I made a little script to reduce those iterations. I wrote a script called lddtostage that automates the discovery of required libraries and prints them out in a simple format that can be pasted into the snapcraft.yaml
at the stage-packages
stanza.
The lddtostage
ldd
stage-packages
on. However, I only had the source tree of Akira, so stage-packages
specified to get a binary I could interrogate.
Once built and installed, I lddtostage /snap/akira/current/usr/bin/com.github.alecaddd.akira
stage-packages
libc6
core
mentioned above.
stage-packages:
- libdatrie1
- libdbus-1-3
- libepoxy0
- libexpat1
- libffi6
- libgcrypt20
- libgee-0.8-2
- libgpg-error0
- libgraphite2-3
- libharfbuzz0b
- liblz4-1
- liblzma5
- libmount1
- libpcre3
- libpixman-1-0
- libpng16-16
- libthai0
- libwayland-client0
- libwayland-cursor0
- libwayland-egl1-mesa
- libx11-6
- libxau6
- libxcb1
- libxcb-render0
- libxcb-shm0
- libxcomposite1
- libxcursor1
- libxdamage1
- libxdmcp6
- libxext6
- libxfixes3
- libxi6
- libxinerama1
- libxkbcommon0
- libxrender1
- zlib1g
I also removed the following stage packages because they’re also staged as part of the gnome-3-28-1804
snap covered in the “Slots and Plugs” section below. Staging these libraries is unnecessary and will cause the snap to be approximately 30MB larger if we do.
- libatk1.0-0
- libatk-bridge2.0-0
- libatspi2.0-0
- libblkid1
- libbsd0
- libcairo2
- libcairo-gobject2
- libfontconfig1
- libfreetype6
- libgdk-pixbuf2.0-0
- libglib2.0-0
- libgtk-3-0
- libpango-1.0-0
- libpangocairo-1.0-0
- libpangoft2-1.0-0
- libselinux1
- libsystemd0
- libuuid1
- libxrandr2
The second required part is granite, a library used by Akira. This will be built first, and akira
after
akira
build-packages
needed to compile the library.
The configflags
parameter for the CMake plugin enabled me to pass some compilation flags into the build process. I discovered which parameters to pass from another GTK application whose snapcraft.yaml
was available on github. Typically the developer of the library will have documentation on supported flags though.
granite:
plugin: cmake
source: https://github.com/elementary/granite/archive/5.2.2.tar.gz
source-type: tar
configflags: [-DCMAKE_BUILD_TYPE=Release, -DCMAKE_INSTALL_PREFIX=/usr, -DCMAKE_INSTALL_LIBDIR=/usr/lib]
build-packages:
- build-essential
- libgee-0.8-dev
- libgirepository1.0-dev
- libgtk-3-dev
- cmake
- gobject-introspection
A donsey of GNOMEs
The next part to define is desktop-gnome-platform
to pull in helper scripts and common libraries needed by most GTK applications. The snap needs to setup environment variables and directories on desktop-launch
script you’ll see mentioned in the next section, below.
desktop-gnome-platform:
source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
source-subdir: gtk
plugin: make
make-parameters: ["FLAVOR=gtk3"]
build-packages:
- build-essential
- libgtk-3-dev
override-build: |
snapcraftctl build
mkdir -pv $SNAPCRAFT_PART_INSTALL/gnome-platform
These are all snapcraft.yaml
is complete enough that it should successfully build the application and incorporate the other parts into a snap. However, the application won’t actually run yet. There are still a few more stanzas to add.
Getting exposure
Snaps typically contain libraries and binaries. Many of the binaries will only be used internally by the application, and are not run directly by the user. Snaps only expose the binaries listed in an apps
stanza to the host computer. These can be long-running services, simple one-shot command-line utilities, or full graphical applications. For each binary that needs to be exposed to the user, we have to specify an entry.
apps:
akira:
command: desktop-launch $SNAP/usr/bin/com.github.alecaddd.akira
plugs:
- desktop
- desktop-legacy
- opengl
- x11
desktop: usr/share/applications/com.github.alecaddd.akira.desktop
environment:
GSETTINGS_SCHEMA_DIR: $SNAP/share/glib-2.0/schemas
slots: [ dbus-akira ]
command
akira
akira
desktop-launch
desktop-gnome-platform
$SNAP
/snap/akira/current
.
Akira is built as a strictly confined snap, which by default will not have access to the display. Snaps use a concept of Interfaces to connect applications inside snaps to resources provided by other snaps. Interfaces plugs
slots
plugs
slots
core18
snap.
In the section above are listed the minimum necessary plugs to enable the snap to paint a GTK window. If Akira grew the capability to access network resources, we might add the network
plug here.
.desktop
akira
The environment
section enables us to add or override environment variables set at runtime. In this case, we need to point to where the GSettings schemas are located inside the snap.
The dbus-akira
slot
is mentioned here, but defined in the next section.
Slots and Plugs
D-Bus is a messaging system for applications. Modern applications commonly need to register themselves on the D-Bus “session bus”. Strictly confined applications are unable to do this by default. The following section (combined with the line in the apps
stanza above) will allow the application to register on the session bus if needed. I set the slot name to an appropriate setting of dbus-akira
and the name to whatever the application tries to register on the session bus as.
slots:
dbus-akira:
interface: dbus
bus: session
name: com.github.alecaddd.akira
The next section adds some plugs that will connect to slots available in the gnome-3-28-1804
snap. This enables us to save space in the snap, having theme, icons and sound components stored elsewhere. When the Akira snap is installed from the store, the gnome-3-28-1804
snap will also be installed, and the plugs here will be automatically connected to the slots in that snap.
plugs:
gnome-3-28-1804:
interface: content
target: $SNAP/gnome-platform
default-provider: gnome-3-28-1804
gtk-3-themes:
interface: content
target: $SNAP/data-dir/themes
default-provider: gtk-common-themes
icon-themes:
interface: content
target: $SNAP/data-dir/icons
default-provider: gtk-common-themes
sound-themes:
interface: content
target: $SNAP/data-dir/sounds
default-provider: gtk-common-themes
Building mighty oaks
With all these in one snapcraft
. I built the Akira snap on my KDE Neon 18.04 laptop, but you could use an Ubuntu VM or build in a cloud service such as Travis or CircleCI.
On a Linux system with snap support enabled, install snapcraft and multipass, and you have what you need to build Akira, or indeed any other snap.
Next steps
This post has focused on snapping Akira and used specific build tools such as meson and
If you have any questions or comments about this
Photo by Francisco Requena on Unsplash