Libraries not found in classic snaps

Hi,

I’ve created a couple of classic snaps of Electron applications, text editors. I’ve found that some of the libraries bundled via stage-packages: are not being found by the application.

This came to light on Ubuntu GNOME 17.04 which doesn’t ship gconf2 by default. Electron applications require gconf2 and the classic snaps fail to find libgconf-2.so.4, although it is included in the snap.

What is the correct technique to ensure classic snaps can find all their bundled libraries? Here is an example snapcraft.yaml for the Atom snap I am publishing so you can see how things are currently setup. As you can see my attempts to coerce LD_LIBRARY_PATH aren’t working.

name: atom
version: 1.18.0
summary: A hackable text editor for the 21st Century.
description: |
  Atom is a free and open source text editor that is modern,
  approachable, and hackable to the core.

grade: stable
confinement: classic

parts:
  atom:
    plugin: dump
    source: https://github.com/atom/atom/releases/download/v1.18.0/atom-amd64.deb
    source-type: deb
    # Correct path to icon.
    prepare: |
      sed -i 's|Icon=atom|Icon=/usr/share/pixmaps/atom\.png|g' usr/share/applications/atom.desktop
    after:
      - desktop-gtk2
    stage-packages:
      - gconf2
      - libasound2
      - libnotify4
      - libnspr4
      - libnss3
      - libpulse0
      - libxss1
      - libxtst6

apps:
  atom:
    # Correct the TMPDIR path for Chromium Framework/Electron to
    # ensure libappindicator has readable resources.
    # Coerce LD_LIBRARY_PATH so libgconf-2.so.4 can be found in the snap.
    command: env TMPDIR=$XDG_RUNTIME_DIR LD_LIBARY_PATH=$SNAP/usr/lib/x86_64-gnu-linux/usr/lib ${SNAP}/bin/desktop-launch ${SNAP}/usr/share/atom/atom
    desktop: usr/share/applications/atom.desktop
1 Like

you’d need a wrapper … https://bugs.launchpad.net/bugs/1694982

2 Likes

Note that while the application may require libgconf to be present to run, the security policy won’t allow the application to talk to gconf (it can load the library of course since it is an antiquated settings technology that isn’t required on modern desktop systems (it can load the library of course). This is almost always a harmless denial with the applications trying various compat settings schemes and they happily move along (eg, to gsettings).

Thanks @ogra. I see that is merged in snapcraft 2.31. I’ll test locally and wait for the 2.31 SRU for my Launchpad builds.

i dont think there is anything snapcraft can do here (rather snapd would have to add $SNAP/{usr/,}lib to LD_LIBRARY_PATH on execute).

you will still have to ship a wrapper in your snap… like the one i pointed to in the bug for the classic snapcraft snap …

1 Like

Ahhh, I didn’t read the commit carefully. I misunderstood that to be something snapcraft would do when creating a classic snap. Understand now, thanks. I’ll update my snaps accordingly.

well, perhaps a fix to snapd/snap-confine might be possible to seed the var by default when classic snaps are executed, i’ll leave it to @niemeyer and @zyga-snapd to decide that :slight_smile:

snapd won’t fiddle with the environment in that way, but it’s trivial to do that without a wrapper by just adding an environment variable in snapcraft.yaml.

Maybe a remote part with a desktop-launch that works on classic?
I don’t think it’s easy to add all the environment variables required in the snapcraft.yaml.

2 Likes

since this just came up again from a solus bug that @ikey pointed to https://dev.solus-project.com/T4390 i actually took a look at the launcher inside the atom snap …

#!/bin/sh

if test "$1" = "classic"; then
    shift
    case $SNAP_ARCH in
        amd64)
            TRIPLET="x86_64-linux-gnu"
            ;;
        armhf)
            TRIPLET="arm-linux-gnueabihf"
            ;;
        arm64)
            TRIPLET="aarch64-linux-gnu"
            ;;
        *)
            TRIPLET="$(uname -p)-linux-gnu"
            ;;
    esac

    export LD_LIBRARY_PATH=$SNAP/usr/lib:$SNAP/usr/lib/$TRIPLET   
fi

# Correct the TMPDIR path for Chromium Framework/Electron to ensure
# libappindicator has readable resources.
export TMPDIR=$XDG_RUNTIME_DIR

exec ${SNAP}/bin/desktop-launch $@

the snap ships many libs in $SNAP/lib and $SNAP/lib/$TRIPLET but neither is added to LD_LIBRARY_PATH

If the trend is to continue, it would be beneficial to at least build the electron runtime in a snap with confinement: classic to have a proper runtime, heck, maybe this could be shared through a content plug/slot interface to reduce the size of snaps.

FWIW, I’ve been thinking about doing something similar for python.

why would the electron runtime have anythig to do with it, the libs in the snap are simply not found because $SNAP/lib and friends are not in LD_LIBRARY_PATH …

those two paths: $SNAP/lib and $SNAP/lib/$TRIPLET should be added by snapcraft to the LD_LIBRARY_PATH by placing them into the $SNAP/command-$SNAP.wrapper which is what actually gets launched first

ogra@styx:~$ cat /snap/atom/current/command-atom.wrapper 
#!/bin/sh
exec "$SNAP/bin/electron-launch" classic ${SNAP}/usr/share/atom/atom "$@"

not here…

oh, might that be omitted in classic snaps then? This is from corebird which I’ve not done anything special:

#!/bin/sh
export PATH="$SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:$PATH"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$SNAP/lib:$SNAP/usr/lib:$SNAP/lib/x86_64-linux-gnu:$SNAP/usr/lib/x86_64-linux-gnu"
export LD_LIBRARY_PATH="$SNAP/lib/x86_64-linux-gnu:$SNAP/usr/lib:$SNAP/usr/lib/x86_64-linux-gnu:$SNAP/usr/lib/x86_64-linux-gnu/pulseaudio:$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH=$SNAP_LIBRARY_PATH:$LD_LIBRARY_PATH
exec "desktop-launch" libopenh264-launch pulse-launch gstreamer-launch $SNAP/usr/bin/corebird "$@"

The only line that I influenced by declarations in the snapcraft.yaml is the exec line. IIRC if you add an environment: declaration it will add those variables in this script before the exec, too.

Well, the current wrapper in the atom snap definitely doesnt have it. I created https://github.com/snapcrafters/atom/pull/3 that should help … if you want to experiment with “environment:” instead. feel free :slight_smile:

Are you suggesting all electron and python snaps should use “confinement: classic”? That would be… unfortunate.

Especially since I can’t run any classic snaps due to how they are designed and implemented.

No no no. I am suggesting that if you intend to snap up an electron or python app with classic confinement you should compile the runtime to have the appropriate dynamic linker loader and rpaths setup.

To ease that, I suggested created prebuilts for people to replace or consume from (through the content interface).

1 Like

No worries, that is not what I suggested. The current approach is fine for when the execution environment doesn’t change, that is everything != classic confined.