How to execute binaries inside a Snap app

@lucyllewy I think I am on Ubuntu 18 perhaps. I do not recall which I downloaded. Perhaps try the .deb version rather than the Snap, just to see if it runs on your machine or not? https://swach.io/download/

If that also doesn’t work, there must be some issue with Electron and your specific Ubuntu version or something.

@lucyllewy @jdstrand @ogra how do we proceed here? Is there some way I can hire someone to do some dedicated debugging of this? Seems like it would be very helpful to figure this out for any other Electron apps that ship binaries they need to execute as well.

You’re welcome to feed me some money in return, but it isn’t necessary (I have a liberapay) … However, I have found the root-cause of your problem. The imlib2 “loaders” in Ubuntu 18.04 have a hard-coded path within pointing to the installation location. Unfortunately, that means they don’t work inside snap packages out of the box. This is fixed by adding the following layout configuration:

layout:
  /usr/lib/x86_64-linux-gnu/imlib2:
    bind: $SNAP/usr/lib/x86_64-linux-gnu/imlib2

With this I have successfully taken a screenshot with Swach and extracted a color from it.

Note: that if you publish a version for a different cpu architechture you’ll need to include a different copy of scrot that is suitable and adjust both the x86_64-linux-gnu instances in the layout to match the other architecture. I don’t know how electron builder does the build, but if it calls snapcraft in any way you can likely replace the x86_64-linux-gnu with $SNAPCRAFT_ARCH_TRIPLET to have it automatically filled depending on the build target architecture.

There is another issue that caused the problem I indicated above where I was unable to get the Swach app to load. I had to manually alter the desktop-common.sh script to prevent it from executing the mv commands on lines 223 and 226. I’m not sure why, but they were trying to move my Documents folder onto itself.

2 Likes

@lucyllewy thanks for the tip! I’m working on figuring out how to add layout with electron-builder now, and should have something released soon.

Just to clarify, is this needed because the bundled scrot is expecting imlib2 to be available from /usr? I do have imlib2 in stage packages, so perhaps we should add something conditional that would use an internal scrot which was also in stage packages, instead of one bundled in a node module?

Your alternative would be to have the path in LD_LIBRARY_PATH … by default snapcraft will make sure that $SNAP/usr/lib/x86_64-linux-gnu is always set in your execution environment.

The problem is that the (staged) imlib deb installs the libraries into the imlib2 subdir which is simply not in your library path.

If it is easier to extend the environment variable in electron-builder (I use electron-packager for all my electron apps which allows me to use a plain snapcraft.yaml instead of having the tool generate it on the fly like electron-builder does) than to add a layout, you could just make sure $SNAP/usr/lib/x86_64-linux-gnu/imlib2 is appended to your $LD_LIBRARY_PATH …

Nearly, it’s not the imlib2 library but the imlib2 helpers that they call loaders which imlib2 loads dynamically from a fixed location. It does not use LD_LIBRARY_PATH to find those loaders.

Nope, it’s not the imlib2 library that is the problem. It is the loaders that the imlib2 library loads internally.

@lucyllewy so there is no way to fix with an environment variable then, it has to use layout?

ah, damned, yeah, you said “hardcoded path” sorry for adding confusion …

1 Like

correct. The imlib2 project has added an environment variable in 2019 to allow overriding their location, but the version of imlib2 in Ubuntu 18.04, which is used when targetting Core18 is from before that date.

Gotcha. electron-builder currently does not support changing the core or passing layout. There is a PR out for adding a layout option, so hopefully that gets merged soon. https://github.com/electron-userland/electron-builder/pull/5073

Once I am able to test that out, I will report back.

2 Likes

@ogra do you also use https://github.com/electron-userland/electron-installer-snap or just electron-packager? Could you elaborate on your setup for building electron apps a bit?

If I have a .deb file already, is there an easy way to generate a snap from that?

here is the source for an electron-builder based snap i’m using locally:

@ogra it’s not clear to me how that source is built. I don’t see any build commands or any references to electron-builder or electron-packager.

it is built like any other snap:

git clone https://github.com/ogra1/ubuntu-forum-client
cd ubuntu-forum-client
snapcraft

@ogra so you are not using electron-packager or electron-builder here? Electron developers are not familiar with Snapcraft, and I think many will face the same issues I have. Even the Snapcraft docs say to use electron-builder https://snapcraft.io/docs/electron-apps

I have an existing electron-forge build, that produces a working .deb package. I was hoping Snap provided some way to provide the .deb and a snapcraft.yml to create a Snap.

I’d love to see some better integrations with popular tooling, rather than having to learn everything there is to know about Snap before being able to publish. I’ve been working on helping PR in fixes for things and will help with documentation as well.

if you read the snapcraft.yaml carefully you will see it uses electron-packager …

@ogra as I mentioned, it would be nice to have explicit instructions on how to build for Snap, rather than relying on Electron devs to learn all about Snap before publishing. I don’t know all the fields in snapcraft.yml or how Snap does building and publishing. I did not know to even look in the snapcraft.yml for usage of electron-packager.

The electron-packager docs say to use electron-installer-snap, which I have a current PR for allowing turning off sandboxing on. Without my PR, electron-installer-snap produces snaps that will fail the auto-review process every time.

The Snap docs say to use electron-builder, and I was told by many people here to use electron-builder, so I did that, and did many complicated steps to get my Snap built, and then had issues running things for months.

Just because these things are obvious for you and others in this forum does not mean they are obvious to everyone. Please understand that I am a web developer who does not use Linux and had never heard of Snapcraft until now.

well, i’m not an electron dev :slight_smile: (obviously)

what i know is that integration tools like electron-builder typically cover the most generic set of options but as soon as you get into more complex packaging tasks (like you do with your app) you normally hit their boundaries …

i’d just ship a snap/snapcraft.yaml in my source tree and use something like build.snapcraft.io to get the snap created … build.s.io will auto-build a snap into the edge channel for every commit you make to your branch …

@lucyllewy @ogra I tried adding the layout bit to my snapcraft.yml, but I am not sure if it was added. If it was, it is not working.

Where should layout go? Should it be in the root or under apps: swach: etc? Also, how do I check what the snapcraft.yml of a built snap looks like to ensure it was added?

I tried doing this to append it to the end as part of my build:

echo -e "layout:\n  /usr/lib/x86_64-linux-gnu/imlib2:\n    bind: $SNAP/usr/lib/x86_64-linux-gnu/imlib2" >> ./dist/__snap-amd64/snap/snapcraft.yml

@lucyllewy @ogra I was able to get it added to snapcraft.yaml. This is my resulting file:

base: core18
grade: stable
confinement: strict
parts:
  launch-scripts:
    plugin: dump
    source: scripts
  gnome-platform-empty-dirs:
    plugin: nil
    override-build: |
      mkdir -p "$SNAPCRAFT_PART_INSTALL/data-dir/themes" mkdir -p "$SNAPCRAFT_PART_INSTALL/data-dir/icons" mkdir -p "$SNAPCRAFT_PART_INSTALL/data-dir/sounds" mkdir $SNAPCRAFT_PART_INSTALL/gnome-platform
  app-files:
    plugin: dump
    source: app
    organize:
      '*': app/
    stage:
      - '-app/chrome-sandbox'
      - '-LICENSES.chromium.html'
  app:
    plugin: nil
    stage:
      - '-usr/lib/python*'
      - '-usr/bin/python*'
      - '-var/lib/ucf'
      - '-usr/include'
      - '-usr/lib/X11'
      - '-usr/share'
      - '-usr/sbin'
      - '-usr/bin'
      - '-usr/lib/*/libicudata.*'
      - '-usr/lib/*/libicui18n.*'
      - '-usr/lib/*/libgtk-*'
      - '-usr/lib/*/libgdk-*'
      - '-usr/lib/*/glib-*'
      - '-usr/lib/*/gtk-*'
      - '-usr/lib/*/gdk-*'
      - '-usr/lib/*/krb5'
      - '-usr/lib/systemd'
      - '-usr/lib/glib-networking'
      - '-usr/lib/dconf'
      - '-usr/lib/*/avahi'
      - '-usr/lib/*/gio'
      - '-usr/lib/*/libatk*'
      - '-usr/lib/*/libatspi*'
      - '-usr/lib/*/libavahi*'
      - '-usr/lib/*/libcairo*'
      - '-usr/lib/*/libcolordprivate*'
      - '-usr/lib/*/libcolord*'
      - '-usr/lib/*/libcroco*'
      - '-usr/lib/*/libcups*'
      - '-usr/lib/*/libdatrie*'
      - '-usr/lib/*/libdconf*'
      - '-usr/lib/*/libepoxy*'
      - '-usr/lib/*/libexpatw*'
      - '-usr/lib/*/libffi*'
      - '-usr/lib/*/libfontconfig*'
      - '-usr/lib/*/libfreetype*'
      - '-usr/lib/*/libgdk_pixbuf*'
      - '-usr/lib/*/libgdk_pixbuf_xlib*'
      - '-usr/lib/*/libgio*'
      - '-usr/lib/*/libglib*'
      - '-usr/lib/*/libgmodule*'
      - '-usr/lib/*/libgmp*'
      - '-usr/lib/*/libgnutls*'
      - '-usr/lib/*/libgobject*'
      - '-usr/lib/*/libgraphite2*'
      - '-usr/lib/*/libgssapi_krb5*'
      - '-usr/lib/*/libgthread*'
      - '-usr/lib/*/libharfbuzz*'
      - '-usr/lib/*/libhogweed*'
      - '-usr/lib/*/libicuio*'
      - '-usr/lib/*/libicutest*'
      - '-usr/lib/*/libicutu*'
      - '-usr/lib/*/libicuuc*'
      - '-usr/lib/*/libidn2*'
      - '-usr/lib/*/libjbig*'
      - '-usr/lib/*/libjpeg*'
      - '-usr/lib/*/libjson*'
      - '-usr/lib/*/libk5crypto*'
      - '-usr/lib/*/libkrb5*'
      - '-usr/lib/*/libkrb5support*'
      - '-usr/lib/*/liblcms2*'
      - '-usr/lib/*/libnettle*'
      - '-usr/lib/*/libp11*'
      - '-usr/lib/*/libpango*'
      - '-usr/lib/*/libpangocairo*'
      - '-usr/lib/*/libpangoft2*'
      - '-usr/lib/*/libpixman*'
      - '-usr/lib/*/libpng16*'
      - '-usr/lib/*/libproxy*'
      - '-usr/lib/*/librest*'
      - '-usr/lib/*/librsvg*'
      - '-usr/lib/*/libsecret*'
      - '-usr/lib/*/libsoup*'
      - '-usr/lib/*/libsqlite3*'
      - '-usr/lib/*/libtasn1*'
      - '-usr/lib/*/libthai*'
      - '-usr/lib/*/libtiff*'
      - '-usr/lib/*/libunistring*'
      - '-usr/lib/*/libwayland*'
      - '-usr/lib/*/libX11*'
      - '-usr/lib/*/libXau*'
      - '-usr/lib/*/libxcb*'
      - '-usr/lib/*/libXcomposite*'
      - '-usr/lib/*/libXcursor*'
      - '-usr/lib/*/libXdamage*'
      - '-usr/lib/*/libXdmcp*'
      - '-usr/lib/*/libXext*'
      - '-usr/lib/*/libXfixes*'
      - '-usr/lib/*/libXinerama*'
      - '-usr/lib/*/libXi*'
      - '-usr/lib/*/libxkbcommon*'
      - '-usr/lib/*/libxml2*'
      - '-usr/lib/*/libXrandr*'
      - '-usr/lib/*/libXrender*'
    stage-packages:
      - libnspr4
      - libnss3
      - libxss1
      - libappindicator3-1
      - libsecret-1-0
      - giblib1
      - libimlib2
      - libx11-6
      - libxcursor1
      - libxfixes3
      - scrot
plugs:
  gnome-3-28-1804:
    interface: content
    target: $SNAP/gnome-platform
    default-provider: gnome-3-28-1804
  gtk-3-themes:
    interface: content
    target: $SNAP/data-dir/themes
    default-provider: gtk-common-themes
  icon-themes:
    interface: content
    target: $SNAP/data-dir/icons
    default-provider: gtk-common-themes
  sound-themes:
    interface: content
    target: $SNAP/data-dir/sounds
    default-provider: gtk-common-themes
name: swach
version: 0.1.40
summary: Swach
description: A robust color management tool for the modern age.
architectures:
  - amd64
apps:
  swach:
    command: command.sh
    plugs:
      - desktop
      - desktop-legacy
      - home
      - x11
      - wayland
      - unity7
      - browser-support
      - network
      - gsettings
      - audio-playback
      - pulseaudio
      - opengl
    adapter: none
    environment:
      DISABLE_WAYLAND: '1'
      TMPDIR: $XDG_RUNTIME_DIR
      PATH: '$SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/sbin:$SNAP/bin:$PATH'
      SNAP_DESKTOP_RUNTIME: $SNAP/gnome-platform
      LD_LIBRARY_PATH: '$SNAP_LIBRARY_PATH:$SNAP/lib:$SNAP/usr/lib:$SNAP/lib/x86_64-linux-gnu:$SNAP/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH:$SNAP/lib:$SNAP/usr/lib:$SNAP/lib/x86_64-linux-gnu:$SNAP/usr/lib/x86_64-linux-gnu'
icon: snap/gui/icon.png
layout:
  /usr/lib/x86_64-linux-gnu/imlib2:
    bind: $SNAP/usr/lib/x86_64-linux-gnu/imlib2

However, I am now getting an error when trying to publish the snap.

Traceback (most recent call last):
  File "/snap/snapcraft/4969/bin/snapcraft", line 33, in <module>
    sys.exit(load_entry_point('snapcraft==4.0.7', 'console_scripts', 'snapcraft')())
  File "/snap/snapcraft/4969/lib/python3.6/site-packages/click/core.py", line 829, in __call__
    return self.main(*args, **kwargs)
  File "/snap/snapcraft/4969/lib/python3.6/site-packages/click/core.py", line 782, in main
    rv = self.invoke(ctx)
  File "/snap/snapcraft/4969/lib/python3.6/site-packages/click/core.py", line 1259, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/snap/snapcraft/4969/lib/python3.6/site-packages/click/core.py", line 1066, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/snap/snapcraft/4969/lib/python3.6/site-packages/click/core.py", line 610, in invoke
    return callback(*args, **kwargs)
  File "/snap/snapcraft/4969/lib/python3.6/site-packages/snapcraft/cli/store.py", line 198, in upload
    snap_revision
  File "/snap/snapcraft/4969/lib/python3.6/site-packages/snapcraft/storeapi/v2/channel_map.py", line 276, in get_revision
    raise ValueError(f"No revision information for {revision_number!r}")
ValueError: No revision information for 25
You can find the traceback in file '/tmp/tmpgaxh1rix/trace.txt'.

Any ideas what the problem is now?