Ubuntu 16.04: Install and build snap package

This article will describe installing and building snap package.

 

1 snap package

A snap package includes private root filesystem which has libraries required by package. This will protect dependency of libraries for each package but duplicated libraryes will make size of system be large.

For example, the private root filesystem of bluez is as below.

$ tree /snap/bluez/6/
/snap/bluez/6/
├── command-bluetoothctl.wrapper
├── command-bluez.wrapper
├── command-obexctl.wrapper
├── command-obex.wrapper
├── meta
│   ├── gui
│   │   └── icon.png
│   └── snap.yaml
└── usr
    ├── bin
    │   ├── bluetoothctl
    │   └── obexctl
    ├── lib
    │   ├── bluetooth
    │   │   ├── bluetoothd
    │   │   └── obexd
    │   └── x86_64-linux-gnu
    │       ├── libical.so.1 -> libical.so.1.0.1
    │       ├── libical.so.1.0.1
    │       ├── libicalss.so.1 -> libicalss.so.1.0.1
    │       ├── libicalss.so.1.0.1
    │       ├── libicalvcal.so.1 -> libicalvcal.so.1.0.1
    │       └── libicalvcal.so.1.0.1
    └── share
        └── doc
            ├── bluez
            │   ├── copyright
            │   └── overview.md
            └── libical1a
                └── copyright

2 Install snapd

The snapd is a tool for installing snap package. This name may be changed from snappy to snapd.

$ sudo apt install -y snapd

2.1 snap command

The snap command for package operations is as below.

 

snap find List avaiable packages
snap find <pattern> List avaiable packages with pattern
snap list List installed packages
snap install <package> Install package
snap remove <package> Uninstall package

 

2.2 Available packages

Available packages on 2016/6/28 are as below.

ab alsa-utils apktool atom-cwayne audovia base beagleblack bluez
canonical-dragon canonical-i386 canonical-pc canonical-pc-linux
canonical-pi2 cassandra cla-check compass-straightedge drmips eeevil
ejabberd filebot foobar21 freecad freechartgeany gdoc-html-cleaner
ghex-udt gmailfilter gnuchess go-example-webserver hangups hello
hello-huge hello-snap hello-world htop http jenkins john-the-ripper
kale keepassx-elopio kpcli-elopio krita languagetool links
littlewatcher minecraft-server-jdstrand miniterm-joc moon-buggy
morse-converter-py nextcloud nikola nmap notes open-solitaire-classic
openscad-plars owncloud pciutils pen roseapple-pi scummvm serial-vault
shadowsocks shout simplenote-jamiebennett snapd-hacker-toolbelt
snappy-debug snapstore-example speed-test spread sshtron
stellarium-plars sudo systesterpro64 taskwarrior-plars teatime-unity
telegram-sergiusens tic-tac-toe tio tor-middle-relay tpad tproxy
ubuntu-calculator-app ubuntu-clock-app ubuntu-core ufw vaca
vault-elopio vlc vtop webcam-webui-stylerrr webdm x11-apps
xkcd-webserver xkcdpass-codersquid yacas yagy

For example, jenkins has a openjdk in private root filesystem.

3 snap package structure

snap package structure is following.

3.1 /var/lib/snapd/snaps/<package>.snap

This is a squashfs image for private root filesystem. This image will be mount to /snap/<package/<rev> but read only mount because of squashfs.

$ mount | grep snap
/var/lib/snapd/snaps/ubuntu-core_122.snap on /snap/ubuntu-core/122 type squashfs (ro,relatime)
/var/lib/snapd/snaps/jenkins_6.snap on /snap/jenkins/6 type squashfs (ro,relatime)

3.2 /etc/systemd/system/snap-<package>-<rev>.mount

This is a systemd script for mounting <package>.snap. This will be started before snap.<package>.<component>.service.

3.3 /etc/systemd/system/snap.<package>.<component>.service

This is a systemd script for running command-<component>.wrapper as service. SNAP_XXX variable like SNAP_DATA and SNAP_USER_DATA will be set in this scripts. This is started by snapd.frameworks.target.

3.4 /snap/bin/<component>

This is a command for running command-<componetn>.wrapper. SNAP_XXX variable like SNAP_DATA and SNAP_USER_DATA will be set in this scripts. /etc/profile.d/apps-bin-path.sh will add /snap/bin to PATH variable.

3.5 /snap/<package>/<rev>/command-<component>.wrapper

This is a wrapper script running by /snap/bin/<component> and snap.<package>.<component>.service. This will exchange SNAP_XXX variable to variable of real command and run real command. The real command is like /snap/bluez/6/usr/bin/bluetoothctl.

3.6 SNAP_DATA

SNAP_DATA in almost packages is set to /var/snap/<package>/<rev>. This is used to output data like logging and database.

I think that package configuration file like /etc/<package>.conf is in this directory but this is up to command-<component>.wrapper.

For example, /snap/jenkins/6/command-jenkins.wrapper only uses SNAP_DATA as JENKINS_HOME but not uses for setting JENKINS_PORT, jenkins snap package could not change TCP port.

3.7 SNAP_USER_DATA

SNAP_USER_DATA in almost packages is set to /<user>/snap/<package>/<rev>. Data for each user will be saved.

4 Install snapcraft

The snapcraft is a tool for building snap package.

$ sudo apt install -y snapcraft

4.1 snapcraft command

The snapcraft command for package operations is as below.

 

snapcraft Build package
snapcraft clean Clean work directory

 

4.2 snapcraft-examples

The snapcraft-examples are examples for snapcraft.

$ sudo apt install -y snapcraft-examples
$ ls /usr/share/doc/snapcraft-examples/examples/git
96boards-kernel             godd              mosquitto    ros                  webchat
busybox                     gopaste           opencv       shout
downloader-with-wiki-parts  java-hello-world  py2-project  tomcat-maven-webapp
git                         libpipeline       py3-project  webcam-webui

Check git example.

$ cp -a /usr/share/doc/snapcraft-examples/examples/git .
$ cd git
$ tree
.
├── setup
│   └── gui
│       └── icon.png
└── snapcraft.yaml

The snapcraft.yaml is configuration file for snapcraft. This snapcraft.yaml is very simple because of make plugin.

$ cat snapcraft.yaml
name: git
version: 2.8.0
summary: Git is a free and open source distributed version control system.
description: This example is not really production quality
confinement: strict

apps:
  server:
    command: bin/git

parts:
  git:
    plugin: make
    source: https://github.com/git/git
    source-type: git
    make-parameters:
      - prefix=
    build-packages: [gettext, libssl-dev, libcurl4-openssl-dev, libexpat1-dev]

The make plugin will run "make all" and "make install DESTDIR=xxx". When Makefile defines DESTDIR properly, snapcraft.yml only needs source code URL, type, and build-packages.

Plugins of snapcraft are as below.

$ snapcraft list-plugins
ant        catkin  copy  jdk     kernel  maven  nodejs   python3 tar-content
autotools  cmake   go    kbuild  make    nil    python2  scons

Build git snap package.

$ snapcraft
$ sudo snap install git_2.8.0_amd64.snap
$ ls /snap/git
current  x1

5 Create original snap package

This article will use tetris source code which uses simple Makefile.

Building tetris source code without snapcraft is as below. This will create jni/src/ncurses command and jni/src/sdl command.

$ sudo apt install -y libsdl2-dev libsdl2-image-dev \
libsdl2-ttf-dev libncurses5-dev
$ git clone https://github.com/hiroom2/tetris-sdl-and-ncurses
$ cd tetris-sdl-and-ncurses $ make $ ./jni/src/ncurses # or ./jni/src/sdl

Create work directory and generate snapcraft.yml template with "snapcraft init".

$ mkdir tetris
$ snapcraft init # Generate template snapcraft.yml

Change snapcraft.yml as below. /snap/bin/<package>.<component> and wrapper script will be created by apps directive.

$ cat snapcraft.yaml
name: tetris
version: 1.0
summary: tetris with ncurses or sdl2
description: https://github.com/hiroom2/tetris-sdl-and-ncurses
confinement: strict

# /snap/bin/<package>.<component>
apps:
  sdl:
    command: bin/sdl
  ncurses:
    command: bin/ncurses

# Build package
parts:
  tetris:
    plugin: make
    source: https://github.com/hiroom2/tetris-sdl-and-ncurses
    source-type: git
    build-packages: [libsdl2-dev, libsdl2-image-dev, libsdl2-ttf-dev, libncurses5-dev]

Build snap package.

$ snapcraft
Preparing to pull tetris
Pulling tetris
Cloning into '/home/hiroom2/tetris/parts/tetris/src'...
remote: Counting objects: 26, done.
remote: Compressing objects: 100% (24/24), done.
remote: Total 26 (delta 1), reused 25 (delta 1), pack-reused 0
Unpacking objects: 100% (26/26), done.
Checking connectivity... done.
Preparing to build tetris
Building tetris
make -j1
make -C jni/src
make[1]: Entering directory '/home/hiroom2/tetris/parts/tetris/build/jni/src'
rm -rf sdl ncurses *.dSYM
g++ -Wall -I.  `sdl2-config --cflags` -o sdl Tetris.cpp TetrisSDL.cpp SDL.cpp -lpthread -lSDL2 -lSDL2_ttf
g++ -Wall -I. -o ncurses Tetris.cpp TetrisNcurses.cpp ncurses.cpp -lpthread -lncurses
make[1]: Leaving directory '/home/hiroom2/tetris/parts/tetris/build/jni/src'
make install DESTDIR=/home/hiroom2/tetris/parts/tetris/install
install -d -m755  /home/hiroom2/tetris/parts/tetris/install/bin/
install -m755 jni/src/sdl /home/hiroom2/tetris/parts/tetris/install/bin/
install -m755 jni/src/ncurses /home/hiroom2/tetris/parts/tetris/install/bin/ncurses
Staging tetris
Priming tetris
Snapping 'tetris' -
Snapped tetris_1.0_amd64.snap

Install snap package.

$ sudo snap install tetris_1.0_amd64.snap

Name    Version  Rev  Developer  Notes
tetris  1.0      x1              -

/snap/tetrisにsquashfs is mounted.

$ tree /snap/tetris/
/snap/tetris/
├── current -> x1
└── x1
    ├── bin
    │   ├── ncurses
    │   └── sdl
    ├── command-ncurses.wrapper
    ├── command-sdl.wrapper
    ├── meta
    │   └── snap.yaml
    └── usr
        └── lib
            └── x86_64-linux-gnu
                ├── libasound.so.2
                ├── libasyncns.so.0
                ├── libFLAC.so.8
                ├── libogg.so.0
                ├── libpulse.so.0
                ├── libSDL2-2.0.so.0
                ├── libSDL2_ttf-2.0.so.0
                ├── libsndfile.so.1
                ├── libsndio.so.6.1
                ├── libvorbisenc.so.2
                ├── libvorbis.so.0
                ├── libwayland-client.so.0
                ├── libwayland-cursor.so.0
                ├── libwayland-egl.so.1
                ├── libX11.so.6
                ├── libXau.so.6
                ├── libxcb.so.1
                ├── libXcursor.so.1
                ├── libXdmcp.so.6
                ├── libXext.so.6
                ├── libXfixes.so.3
                ├── libXinerama.so.1
                ├── libXi.so.6
                ├── libxkbcommon.so.0
                ├── libXrandr.so.2
                ├── libXrender.so.1
                ├── libXss.so.1
                ├── libXxf86vm.so.1
                └── pulseaudio
                    └── libpulsecommon-8.0.so

/snap/bin/<package>.<component> is added.

$ ls /snap/bin/tetris.*
/snap/bin/tetris.ncurses  /snap/bin/tetris.sdl