Want to run your application binaries on any Linux distribution? Snap makes that possible.
For general purpose information about snap, snapcraft and how to use them please have a look at their documentation as it excellently teaches you most generic information about snaps https://docs.snapcraft.io
Even so this page will teach you a lot of the basics of snaps.
TBD separate page specifically about how to use the content snap
Building a snap we'll lovingly call "snapping". At the time of writing you can snapcraft on two core systems: one is Ubuntu 16.04, the other is Ubuntu 18.04. Both of them are the LTS version of Ubuntu and therefore supported for what seems like forever. Snapcraft has native support to pull binary packages (i.e. debs) into the snap so that you might build against them without having to build the binaries yourselves. For example you could use Qt from Ubuntu directly without the need to build it in your snap. However, since the base systems are LTS the software is usually very dated. Seeing as you may need newer dependencies there's a bunch of ways you can get them besides pre-built Ubuntu debs:
You can add any number of additional parts that build dependencies. For example you might build your own qtbase as part of snap. How much work this is can be vastly different between software. Building all of Qt can get quick old, at the same time relying on an ancient Qt may not be practical either.
We are in luck and KDE neon already builds packages for Ubuntu LTS, so you may choose to simply use neon debs on top of Ubuntu debs. This gives access to the latest Qt, KDE frameworks and other related libraries. This can be a huge time saver. Unfortunately Snapcraft's support for adding additional repositories is non-existent and so if you choose to go this route you may need to somewhat manually manage the build environment yourself e.g. using an especially prepared LXD container.
Much like KDE neon, this too will require you to manage the build environment manually. Also, when using PPAs beware that they may not be compatible with neon (so, ideally you should use either-or) and that many of them are not particularly trustworthy or well maintained (important vis-a-vis security).
The tool to build snaps is called snapcraft. The definition for how to craft a snap is written down in snapcraft.yaml. Generally speaking a snapcraft.yaml will contain global metadata of the snap, a list of applications provided by the snap, and lastly a list of parts that when put together result in the snap.
With a broad overview of abilities and shortcomings let's dive right in and look at types of snaps we might build.
A standalone snap is a snap which solely relies on a "core" but no other snaps. This is generally speaking the most reliable type of snap as everything the snap needs is inside the snap (except libc and friends which are in the core).
It is also the best supported way of building a snap since it's been around since the very beginning.
1 name: qtnetsample 2 version: '0' # the version of the snap. has no semantic meaning 3 summary: This is my-snap's summary # 79 char long summary 4 description: This is my-snap's description # a longer description for the snap 5 confinement: strict # use "strict" to enforce system access only via declared interfaces 6 grade: devel # use "stable" to assert the snap quality 7 base: core18 # the core this snap depends on 8 9 apps: 10 qtnetsample: 11 command: launcher qtnetsample # the launcher will setup the environment for qtnetsample to find libraries/plugins/data etc 12 plugs: [x11, network, network-bind] # this snap will be able to act as xclient and talk over the network 13 14 parts: 15 qtnetsample: 16 build-packages: [qt5-default] 17 plugin: cmake 18 stage-packages: [libqt5network5, libqt5core5a] 19 source: .
A snap may also choose to use one or more Content Snaps (see glossary) to share part of the binaries or UI assets with other snaps. As shared content will generally be in the content snap, the ultimate size of the snap can be fairly small. Think of this as an approach more akin to how traditional binary package dependencies work. Albeit with many of the same complexities surrounding it.
For example KDE neon builds the kde-frameworks-5 content snap. It contains all of Qt and all (not-deprecated) KDE frameworks along with Plasma integration rigging.
1 --- 2 name: kbruch 3 version: 18.12.1 4 confinement: strict 5 grade: stable 6 base: core18 7 adopt-info: kbruch # part to adopt appstream data from (first in parse list) 8 apps: 9 kbruch: 10 command: kf5-launch kbruch 11 plugs: 12 - kde-frameworks-5-plug 13 - home 14 - x11 15 - opengl 16 - network 17 - network-bind 18 - unity7 19 - pulseaudio 20 - desktop 21 - desktop-legacy 22 common-id: org.kde.kbruch.desktop 23 desktop: "usr/share/applications/org.kde.kbruch.desktop" 24 slots: 25 session-dbus-interface: 26 interface: dbus 27 name: org.kde.kbruch 28 bus: session 29 plugs: 30 kde-frameworks-5-plug: 31 content: kde-frameworks-5-core18-all 32 interface: content 33 default-provider: kde-frameworks-5-core18 34 target: kf5 # target directory where the content is mounted i.e. $SNAP/kf5/ 35 parts: 36 kbruch: 37 build-snaps: 38 - kde-frameworks-5-core18-sdk 39 after: 40 - kde-frameworks-5-env 41 plugin: cmake 42 source: src 43 configflags: 44 - "-DKDE_INSTALL_USE_QT_SYS_PATHS=ON" 45 - "-DCMAKE_INSTALL_PREFIX=/usr" 46 - "-DCMAKE_BUILD_TYPE=Release" 47 - "-DENABLE_TESTING=OFF" 48 - "-DBUILD_TESTING=OFF" 49 - "-DKDE_SKIP_TEST_SETTINGS=ON" 50 parse-info: [usr/share/metainfo/org.kde.kbruch.appdata.xml] 51 kde-frameworks-5-env: 52 plugin: dump 53 source: https://github.com/apachelogger/kf5-snap-env.git
When binaries inside snaps get executed they only get a super minimal environment set up by snapd. The snap itself needs to take care of most of the higher level spin up of the environment.
Inside a confined snap the
/ will be the core snap, while the actual snap will be in
SNAP=/snap/name/rev/.... As a result for example icons, which usually would be expected in
/usr/share/icons, will need to be actually be looked for in
$SNAP/usr/share/icons. The same applies to pretty much all XDG_* variables, LD_LIBRARY_PATH, various QT_* variables and so on and so forth.
Simply put: a snap's tree is not "merged" with the core's tree, rather it is "mounted" inside the core tree under $SNAP and so each snap needs to set up an environment which redirects or adds $SNAP to all lookup locations you can possibly imagine. As general assumptions about where things are on a Linux system no longer hold true. One the one hand that technically allows you to create a snap which entirely does away with the FHS, on the other it means someone needs to actually mangle the environment so files may be located properly.
That's why most, if not all, desktop application snaps will need a launch helper. The launcher will set up all the general purpose path variables so they point to $SNAP. A standard desktop launcher implementation is available here https://github.com/ubuntu/snapcraft-desktop-helpers. Obviously you can also write your own, but since there are lots of things to consider, even for simple applications, it's probably not a good idea to do so.
You can have a look at the standard environment by running
snap install hello-world snap run --shell hello-world env
This will drop you on a minimal shell inside the confined snap, where you can have a look around to see what the snap sees.
Words you'll hear and not know what they mean: