Gotchas When Creating a Snap Package for Haskell (Stack) Program

Posted on August 16, 2019

Introduction

Building snap packages and publishing them on the Snapcraft Store is well documented by Canonical. For the most part, creating a snap package for a Haskell program (built with Stack) is the same as building any other Snap package. However, I did need to know a few things to successfully build my Snap package.

GHC Memory Requirements

GHC is a memory hog. Many libraries can take over 4 GB of memory to compile. By default, snapcraft will only allocate 2 GB of memory when building an application with multipass. Multipass gets used by snapcraft when core18 is specified in the snapcraft.yaml as a base.

To change the memory allocated by multipass, use an snapcraft environment variable, when running snapcraft. The snapcraft command will look like, SNAPCRAFT_BUILD_ENVIRONMENT_MEMORY=4G snapcraft, to allocate 4 GB. If snapcraft already ran with lower memory then you’ll need to rebuild the multipass VM by running snapcraft clean first.

Using Stack tool in Snapcraft

Many Haskell applications build using the stack tool. There is not a snapcraft plugin available for the stack tool so a build override is needed. The following snippet will download and install stack. Next the snippet will build the program with stack.

override-build: |
  if [ ! -x "$(command -v stack)" ]; then
    curl -sSL https://get.haskellstack.org/ | sh
  fi
  stack build --copy-bins

Use plugin: nil for the part building the Haskell program.

Also, make sure curl and any other build dependencies you need are in the build-packages section.

Finding the binary

By default the binary will be stored in /root/.local/bin from running stack buidl --copy-bins. It is probably more convenient for the application to be in /bin. Use organize to move the binary were it is needed for the snap. For example:

organize:
  /root/.local/bin/myapp: bin/myapp

Automatic Versioning

Snapcraft can use the same version specified in the package.yaml like so:

override-pull: |
  snapcraftctl pull
  snapcraftctl set-version "$(grep version package.yaml | awk '{ print $NF }')"

Use adopt-info in the snapcraft.yaml to select the part to use the version info from.

Example

For a working example, see my s17-turbo-switch snap configuration.

Modified: August 16, 2019 - 06:24:50 PM