Snapcraft succeeds, but libblas.so.3 link can't be found at runtime

Hi folks,

I’m a first-time snapcrafter. My application, called ‘stalefish’, is written in C++, uses the cmake build system and is hosted as a github repository (it’s private right now, we’ll publish it open source to coincide with an academic paper on the algorithms which it implements).

The application contains two main binaries, one of which (stalefish) has the dependencies OpenCV, HDF5, libarmadillo, libjsoncpp and their sub-dependencies. The second binary (sfview) has the same dependencies plus libglfw3, libfreetype6 and OpenGL.

After some trial and error, I got the snapcraft build process to create for me a stalefish*.snap which I can snap install.

When I then try to run /snap/usr/bin/stalefish, I get this error:

[seb@minimonster 10:34:27 Stalefish]$ /snap/bin/stalefish
/snap/stalefish/x1/usr/bin/stalefish: error while loading shared libraries: libblas.so.3: cannot open shared object file: No such file or directory

even though libblas.so.3 can be found in the mounted snap:

[seb@minimonster 10:35:59 Stalefish]$ find /snap/stalefish/x1|grep libblas
/snap/stalefish/x1/usr/lib/x86_64-linux-gnu/blas/libblas.so.3
/snap/stalefish/x1/usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
/snap/stalefish/x1/usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
/snap/stalefish/x1/usr/share/doc/libblas3
/snap/stalefish/x1/usr/share/doc/libblas3/changelog.Debian.gz
/snap/stalefish/x1/usr/share/doc/libblas3/copyright
/snap/stalefish/x1/usr/share/lintian/overrides/libblas3

At this point, I feel stuck. Can anyone suggest how I can debug/fix this problem? I note that libblas is part of Debian/Ubuntu’s ‘alternatives’ scheme - perhaps this is something I have to pay attention to in my snapcraft.yaml file?

Thanks in advance for any help!

Seb James

Here’s my snapcraft.yaml file for reference:

name: stalefish
title: Stalefish
version: git
summary: Neuroscience tool
description: |
  Stalefish is a tool to analyse gene expression.
  From your brain slice images you can build 3D
  expression surfaces and then convert these into
  2D expression maps. For more details see...

grade: stable
confinement: devmode
base: core20

parts:
  stalefish:
    plugin: cmake
    cmake-parameters:
    - -DCMAKE_INSTALL_PREFIX=/usr
    source-type: git
    source: https://github.com/ABRG-Models/Stalefish
    build-packages:
      - build-essential
      - cmake
      - wget
      - freeglut3-dev
      - libglu1-mesa-dev
      - libxmu-dev
      - libxi-dev
      - liblapack-dev
      - libopencv-dev
      - libarmadillo-dev
      - libjsoncpp-dev
      - libglfw3-dev
      - libhdf5-dev
      - libfreetype-dev
      - libpopt-dev
      - libopengl-dev
    stage-packages:
      - libglu1-mesa
      - libxmu6
      - libxi6
      - liblapack3
      - libopencv-core4.2
      - libopencv-highgui4.2
      - libopencv-imgcodecs4.2  
      - libopencv-imgproc4.2
      - libarmadillo9
      - libjsoncpp1
      - libglfw3
      - libhdf5-103
      - libfreetype6
      - libpopt0
      - libopengl0
      - libblas3
      - libopenblas0-pthread

apps:
  stalefish:
    command: usr/bin/stalefish
  sfview:
    command: usr/bin/sfview

To debug the loading of shared libraries my installed snap called stalefish I did:

snap run --strace stalefish

Which shows all the locations that the linker searches for to find libblas.so.3.

The problem is that libblas.so.3 is in a blas/ subdirectory, so whereas the search includes:

/snap/stalefish/x1/usr/lib/x86_64-linux-gnu/libblas.so.3

from the strace line:

openat(AT_FDCWD, "/snap/stalefish/x1/usr/lib/x86_64-linux-gnu/libblas.so.3", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory

The file is actually to be found in this directory:

/snap/stalefish/x1/usr/lib/x86_64-linux-gnu/libblas.so.3/blas

So my task is to find out how to add this path to the set of paths searched for libraries - i.e. I need to control the linker in the snap.

I think that my problem is the same as the one in this forum post:

Yes, and the solution is to modify LD_LIBRARY_PATH by editing snapcraft.yaml like this (where I also had to add an entry for the lapack library):

name: stalefish
title: Stalefish
.
. [snip]
.
apps:
  stalefish:
    command: usr/bin/stalefish
    environment:
      "LD_LIBRARY_PATH": "$LD_LIBRARY_PATH:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/blas:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/lapack"
  sfview:
    command: usr/bin/sfview
    environment:
      "LD_LIBRARY_PATH": "$LD_LIBRARY_PATH:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/blas:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/lapack"

Glad to see you’ve found a solution!

LD_LIBRARY_PATH is the usual way you’d fix this problem, but there’s a subtle issue in the way you’ve defined yours above. I’d recommend removing the explicit $LD_LIBRARY_PATH: segment, because although this logically makes sense since you’re appending to any existing value, at the exact time that this line is evaluated there usually is no existing value, leading to a trailing colon which causes some subtle security concerns where LD will search the current working directory. Your snap if run from the command line would probably identify this happening and generate a warning.

Otherwise, you could save some space by setting an environment: attribute that effects the whole app by removing it from the apps: part and having it in the root of the document.

And you could also consider reorganising the snap itself, snap provides a few special attributes that reorganise files, so you could do something like this too, and then you wouldn’t need to modify LD_LIBRARY_PATH at all.

stage-packages:
[snip]
organize:
      usr/lib/*-linux-gnu/blas/*: usr/lib/
      usr/lib/*-linux-gnu/lapack/*: usr/lib/

Hi James,

Thank you very much for the helpful information. That will fix a warning that was emitted by snapcraft related to the empty LD_LIBRARY_PATH. I like the organize feature, too; I will try this out.

I’m half way there - only the OpenGL stuff to figure out for the other program in my snap… but that’s a query for another topic!

Seb

You can likely get OpenGL working using the Snapcraft Desktop Helpers or the Snapcraft Extensions, which might actually be as simple as:

apps:
 stalefish:
   command: usr/bin/stalefish
   extensions: [gnome-3-38]
 sfview:
   command: usr/bin/sfview
   extensions: [gnome-3-38]

The extensions deal with setting up a lot of common environment variables and add some extra plugs that are often used with desktop applications, this’d include OpenGL.

I put the LD_LIBRARY_PATH in a root-level environment: section which keeps the .yaml and the build neater, so that’s good.

Your suggestion to use extensions: [gnome-3-38] works! It does seem excessive to pull in all that gnome stuff for a program which is command-line controlled and uses only OpenGL + GLFW for window creation, but if that’s the best approach, I’m happy. I did notice it took quite a lot longer to install the snap with the gnome-3-38 extension, but the .snap file was no larger.

Thanks for all the help!

I’m now trying to get the snap to work with confinement: strict so that I can publish the app.

With confinement: strict set, I need to add plugs: to my apps: section, where I need - home for access to files in the user’s home directory, - x11 to allow the programs to draw to the X server and -opengl for the OpenGL program sfview. My apps: section is now:

apps:
  stalefish:
    command: usr/bin/stalefish
    plugs:
      - home
      - x11
  sfview:
    command: usr/bin/sfview
    extensions: [gnome-3-38]
    plugs:
      - home
      - x11
      - opengl

I get one warning now, that I don’t know how to resolve:

[seb@minimonster 09:49:12 Stalefish]$ /snap/bin/stalefish data/testimg.h5
...
[snip some stalefish program output]
...
(process:22963): Gtk-WARNING **: 09:49:22.733: Locale not supported by C library.
	Using the fallback 'C' locale.
Gtk-Message: 09:49:22.776: Failed to load module "appmenu-gtk-module"

(testimg.h5:22963): Gtk-WARNING **: 09:49:22.898: Failed to parse /etc/gtk-3.0/settings.ini: Permission denied

I notice that I don’t get this warning with sfview, because it has the [gnome-3-38] extension, which presumably does the magic of locale setting.

Can I resolve that ugly warning (it doesn’t actually affect my very simple program)?

Should I just add the [gnome-3-38] extension to stalefish?

Should I use the system-files interface to give access to /etc/gtk-3.0/settings.ini in case that would resolve it?

You can avoid the extensions but they help significantly in a few ways in the way the alternatives (snapcraft desktop helpers) don’t, so although it’s true they increase build time and install time to some degree, I’d say it’s usually worth doing if your app is compatible with them.

Adding the extension to both apps should fix the locale error ( there is some magic in the extension as you’ve guessed specifically for locale support), otherwise you could explicitly set the locale to something like C.UTF-8 with an environment attribute but ideally you’d follow the users settings. Despite being the Gnome extensions and thus implying they should have a dependency on an actual desktop context there’s nothing stopping you from using them on CLI apps (especially given CLI apps might just spawn windows later).

The system files interface approach is unlikely to be accepted by the review team in this instance ( adding it will work locally but distribution via the store will be blocked automatically until manually reviewed)

Ok, I’ll go with the gnome extension for both commands.

My final snapcraft.yaml, for reference/to help other new snapcrafters is:

name: stalefish
title: Stalefish
version: git
summary: Neuroscience tool
description: |
  Stalefish is a tool to analyse gene expression.
  From your brain slice images you can build 3D
  expression surfaces and then convert these into
  2D expression maps. For more details see...
grade: stable
confinement: strict
base: core20

parts:
  stalefish:
    plugin: cmake
    cmake-parameters:
    - -DCMAKE_INSTALL_PREFIX=/usr
    source-type: git
    source: https://github.com/ABRG-Models/Stalefish
    build-packages:
      - build-essential
      - cmake
      - wget
      - freeglut3-dev
      - libglu1-mesa-dev
      - libxmu-dev
      - libxi-dev
      - liblapack-dev
      - libopencv-dev
      - libarmadillo-dev
      - libjsoncpp-dev
      - libglfw3-dev
      - libhdf5-dev
      - libfreetype-dev
      - libpopt-dev
      - libopengl-dev
    stage-packages:
      - libglu1-mesa
      - libxmu6
      - libxi6
      - liblapack3
      - libopencv-core4.2
      - libopencv-highgui4.2
      - libopencv-imgcodecs4.2
      - libopencv-imgproc4.2
      - libarmadillo9
      - libjsoncpp1
      - libglfw3
      - libhdf5-103
      - libfreetype6
      - libpopt0
      - libopengl0
      - libblas3
      - libopenblas0-pthread

environment:
  "LD_LIBRARY_PATH": "$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/blas:$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/lapack"

apps:
  stalefish:
    command: usr/bin/stalefish
    extensions: [gnome-3-38]
    plugs:
      - home
      - x11
  sfview:
    command: usr/bin/sfview
    extensions: [gnome-3-38]
    plugs:
      - home
      - x11
      - opengl
1 Like