DEV Community

Cover image for Fixing a Snapcraft Build that had been Broken for Two Years
Tomas Gallucci
Tomas Gallucci

Posted on

Fixing a Snapcraft Build that had been Broken for Two Years

As I stated in my introduction, the first piece of work I did on Packet Sender was fix the Snapcraft build.

What is Snapcraft?

It has been a while since I've worked with Ubuntu, so I wasn't up to speed with how Ubuntu was now doing things like package management.

As I understand it, apt and/or apt-get is still a thing, but Snapcraft is the new shiny.

Snapcraft is more than just an app repository, though. It's a build system, dependency manager and a packager. Ergo, the vertical integration means you don’t have to keep multiple tools in sync.

The Problem

When building Packet Sender with Snapcraft, the product would build, link and run. But as soon as you ran it, it would crash with the following error message:

/snap/packetsender/49/usr/local/bin/packetsender: error while loading shared libraries: libpxbackend-1.0.so: cannot open shared object file: No such file or directory

.dll(s) and .so(s)

I grew up in the '90s. This meant that, unfortunately, I grew up in the age of Microsoft, meaning I started on PCs. While I remember Windows 3.1's UI, I didn't really start using computers until Windows 95. My first machine was a Windows 98 box.

I tell you this so you know that I grew up knowing what a .dll is because I grew up using Windows.

Simply put, a .dll is a shared library. The idea was that instead of having to compile common libraries into executables and thus bloat the size of executables and the amount of memory they needed, vendors could deliver a shared library that would be loaded into memory once and could be called at run time by any running process that needed them. Of course, Microsoft being Microsoft, this was poorly engineered.

.sos1 are the same idea but on *nix. Thankfully, they had time to learn from Microsoft's mistakes.

What does the error message mean?

Simply put, what the error message was trying to tell us was that when the code was compiled, we assumed the .so files would be in a given place, but they weren't.

One common way to fix this is with the LD_LIBRARY_PATH environment variable or linker flags, but hard-coding paths inside a Snap is brittle — the locations can change between builds or base snaps.

I did the work back in February but am just now writing up this work in August. In addition to potentially hardcoding a wrong path, there were other problems with this approach. I think I had tried either changing the Qt library or version of the library we were pulling in, but that didn't work.

In my introduction, I mentioned that I used Grok to help me solve this problem. Grok suggested using libproxy1v5 and adding a LD_LIBRARY_PATH environment variable. But this did not solve the problem.

The breakthrough

It was at that point Dan Nagle suggested using the kde-neon-6 Snapcraft plugin.

The kde-neon-6 extension pulls in a complete, well-configured Qt 6 stack that already knows how to locate its own shared libraries (including the missing libpxbackend-1.0.so). Because the libraries are staged correctly by the extension, we no longer had to chase paths ourselves.

This had several consequences:

  1. I was able to remove all but two of the stage-packages
  2. I was able to remove several of the build-packages
  3. The build had to be converted to CMake because KDE prefers CMake.
  4. The executable went from 165MB to just under 6MB!

The reason for 1 & 2 is that kde-neon-6 already bundles and correctly stages the Qt 6 libraries we needed. This was key to being able to remove so many stage-packages and build-packages manual packages we had been listing. In turn, the executable size was reduced by ~96% (165MB to ~6MB)!

Point #3 was a blessing in disguise in that, qmake (Qt's build system) is deprecated. So moving the Snapcraft build to CMake means we solve that problem now instead of kicking the can down the road.

multi-arch for damn near free

Finally, if you look at this commit you'll see that we were previously building for amd64 on amd64:

amd64:
    build-on: [amd64]
    build-for: [amd64]
Enter fullscreen mode Exit fullscreen mode

by adding three more lines of yaml, we were able to add arm64:

arm64:
    build-on: [arm64]
    build-for: [arm64]
Enter fullscreen mode Exit fullscreen mode

So now every Snapcraft build produces both an amd64 and an arm64 binary. The practical payoff? Packet Sender can run on Raspberry Pi hardware.


If you found this post useful, consider supporting my Open Source software work directly by donating directly at https://www.paypal.com/paypalme/realprofessortom


  1. the extension stands for "shared object" 

Top comments (0)