Igor Ljubuncic
on 7 May 2021
A couple of weeks ago, we published an article about Ubuntu 16.04 entering Extended Security Maintenance (ESM), and the implications of this change for snap publishers. We talked about the different options available to developers and publishers who still may rely on the older bases in their build process – free Ubuntu Advantage (UA) tokens, Launchpad and Snapcraft Build Service, snapcraft support for ESM base, and others.
However, for the majority of publishers, migrating away from the ESM base (core) to core18 and core20 offers the highest degree of flexibility. This will allow them to build snaps with the latest builds of snapcraft, enjoy current and future improvements in the ecosystem, and provide their users with the best possible experience. Today, in this guide, we outline several common, practical tips for the migration to newer bases.
Package names may have changed
When you create a snap, you specify a list of optional packages required at build time and runtime. These are defined under the build-packages and stage-packages sections of the snapcraft.yaml file.
With no base or core specified, snapcraft use packages available from the Ubuntu 16.04 LTS archive at build and stage steps of the snap lifecycle. Similarly, if you use the core18 base, snapcraft uses packages from the Ubuntu 18.04 LTS archive, and with the core20 base, it consumes packages from the Ubuntu 20.04 LTS archive. This means that if you rely on a specific package name and version, it could change between these different releases.
For example, with the Irssi snap, a change to stage-packages would look as follows:
- - libperl5.22
+ - libperl5.26
In this example, the name of the Perl library package changed due to a version bump. The easiest way to discover the “delta” in the packages and their versions is to build a new snap on the destination base system (18.04 or 20.04), examine any runtime failures, and update each unresolved package.
The architecture keyword change
An important difference moving to newer bases is that the architecture keyword now defines a set of both build and run architectures.
architectures:
- build-on: amd64
run-on: amd64
It is also important to pay attention to 32-bit software. Snaps that produce i386 builds are supportable for the lifetime of Ubuntu 16.04 LTS or Ubuntu 18.04 LTS when using the core or core18 snaps as the base. However, base: core20 does not support the i386 architecture. With core20, the supported architectures are amd64, arm64, armhf, ppc64el, and s390x.
Environment variables & hard-code paths
Environment variables are often used in snaps to ensure binaries are able to find loadable modules or libraries included in the snap at runtime. In some cases, environment variables may include hard-coded paths that contain specific version numbers, and will need to be changed. Once again, if we look at the Irssi snap:
environment:
- PERL5LIB: "$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/perl-base/:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/perl5/5.22/:$SNAP/usr/share/perl5/:$SNAP/usr/share/perl/5.22.1/:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/perl/5.22/:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/perl/5.22.1/"
+ PERL5LIB: "$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/perl-base/:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/perl5/5.26/:$SNAP/usr/share/perl5/:$SNAP/usr/share/perl/5.26.1/:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/perl/5.26/:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/perl/5.26.1/"
Remote parts
The remote parts functionality has been deprecated. In the past, snaps were able to use remote parts to share configuration across multiple sans, to reduce the local snapcraft.yaml complexity. Remote parts would be defined in locations other than the local directory, and incorporated at build time.
Going forward, the remote parts should be pasted directly into the snapcraft.yaml or referenced from their source repository. For example, a pasted remote part in the Mr Rescue snap.
parts:
mrrescue:
- after:
- - desktop-glib-only
+ desktop-glib-only:
+ build-packages:
+ - libglib2.0-dev
+ plugin: make
+ source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
+ source-subdir: glib-only
+ stage-packages:
+ - libglib2.0-bin
Snapcraft extensions
The migration from remote parts ties nicely into Snapcraft extensions, a new concept introduced into the snap build lifecycle. Snapcraft extensions allow developers to simplify their snaps by using common code bundles, which hide and abstract away a lot of the cruft that would normally be used in snapcraft.yaml files. This way, developers can avoid repetitive tasks, use a common, consistent template for their application builds, and make best use of known practices, which ultimately save time and effort, and can result in snaps of smaller size and with improved startup times.
When migrating to newer cores (and extensions), the developers should pay attention to the syntax, as well as make sure they use the right version of the extension for their build. First, let’s look at a snap that did not use an extension.
parts:
xonotic:
- after:
- - desktop-glib-only
apps:
xonotic:
- command: desktop-launch $SNAP/Xonotic/xonotic-linux-sdl.sh
+ extensions: [gnome-3-34]
+ command: Xonotic/xonotic-linux-sdl.sh
In the above example, we remove the reference to a remote part desktop-glib-only and instead declare the use of the gnome-3-34 extension, which replaces the functionality of the remote part (as well as provides additional benefits).
Snapcraft extensions naming
It is also important to pay attention to the naming convention, as not all extensions (and their specific versions) work on all bases. For example, on core18, if you want to use the GNOME extension, you need to use the gnome-3-34 extension, while on core20, you need to use gnome-3-38. You can read the Supported extensions page for further details.
As an example, Dwarf Fortress uses the core-20-only GNOME extension:
parts:
tarball:
- after: [desktop-gtk3]
apps:
dwarffortress:
- command: desktop-launch $SNAP/wrapper.sh
+ extensions: [gnome-3-38]
+ command: wrapper.sh
Audio interfaces change
For applications which play or record audio, the interface names have changed. Previously, the pulseaudio interface was used for both playback and recording of audio. This has been replaced by audio-playback and audio-record, respectively:
apps:
xonotic:
Plugs:
- pulseaudio
+ audio-playback
Snap publishers should note that, for privacy and security reasons, the audio-record interface is not automatically connected. For seamless (necessary) functionality of a snap that relies on audio-record, publishers should create a request on the Snapcraft forum.
Plugin name changes
Several different Snapcraft plugins have changed, and snaps that rely on them will require some modifications. In general, plugin changes can be queried with the snapcraft help <plugin name> –base <base name> command:
$ snapcraft help npm --base core20
Displaying help for the 'npm' plugin for 'core20'.
[...]
You can also list plugins for a specific base with snapcraft list-plugins –base <base name>, e.g.:
$ snapcraft list-plugins --base core20
Displaying plugins available for 'core20'
autotools catkin catkin-tools cmake colcon dump go make
meson nil npm python qmake rust
If you are unsure what to do, try to build your snap with just core18/20 declared. Snapcraft will provide you with meaningful errors that should help you make necessary modifications to your snapcraft.yaml file.
Plugin | Core | Core20 | Comments |
---|---|---|---|
node/npm | nodejs | npm | |
node/npm | node-engine | npm-node-version | Specify the version of upstream npm to be used at build time |
autotools | configflags | autotools-configure-parameters | |
go | go-importpath | go-channel |
Npm plugin syntax changes example:
parts:
wethr:
- plugin: nodejs
+ plugin: npm
parts:
wethr:
- node-engine: "10.14.1"
+ npm-node-version: "10.14.1"
Autotools plugin syntax changes example:
parts:
libconfuse:
plugin: autotools
- configflags: ['--prefix=/usr', '--disable-examples', '--disable-static']
+ autotools-configure-parameters: ['--prefix=/usr', '--disable-examples', '--disable-static']
Go plugin syntax changes example:
parts:
slack-term:
plugin: go
- go-importpath: github.com/erroneousboat/slack-term
+ go-channel: latest/stable
Application definitions
There are also several changes in the application definition. Snapcraft now requires explicit paths to be specified for binaries listed in the apps stanza:
apps:
wethr:
- command: wethr
+ command: bin/wethr
Furthemore, rather than specify a command followed by a long list of space-separated executables, they can now be listed with the command-chain option. For instance, in the Atom snap example:
apps:
atom:
- command: bin/launcher ${SNAP}/usr/share/atom/atom
+ command-chain:
+ - bin/launcher
+ command: usr/share/atom/atom
Version scripts
The top level version-script option has been deprecated in favour of adopt-info. This requires that you specify adopt-info with a reference to the part in which the version data (and some other metadata) may be set. Within the parts section, you can use snapcraftctl set-version to define the snapcraft project version number used at build time.
-version-script: git -C parts/cointop/build rev-parse --short HEAD
+adopt-info: cointop
parts:
cointop:
+ override-pull: |
+ snapcraftctl pull
+ snapcraftctl set-version $(git rev-parse --short HEAD)
Summary
The migration to newer bases entails some syntax changes, inclusion of different stage package versions, and some focus on environment variables and interface declarations. This article covers only a subset of possible scenarios and use cases that you may encounter, but we hope it will provide you with a nudge in the right direction.
We understand the major changes in snapcraft.yaml aren’t easy, and we want to make this journey as smooth and practical as possible. If you have any questions, or perhaps suggestions for other users, you can participate in an existing thread on this topic, and provide your input.
Photo by Tanguy Sauvin on Unsplash.