How to execute a binary file inside a snap

I have a binary file (written in C) and I’d like to build/wrap a snap of it. This binary file also uses some additional libraries (lib1.a, lib2.a, etc.). Is there a way I can do this? I tried to search on the canonical website but I couldn’t find much. Any suggestion on how to start?

You might find some useful information on the docs for building C applications here.

If it’s a pre-compiled binary, you can use the dump plugin and include libraries with the stage-packages keyword:

parts:
  part-1:
    source: .
    plugin: dump
    stage-packages:
      - lib1
      - lib2

Otherwise, I would recommend looking at the tutorials here: https://snapcraft.io/docs/creating-a-snap

Yes, it’s a pre-compiled binary and I already use the dump plugin. I have a directory like this:

project
  release
  snap
  snapcraft.yaml

and my snapcraft.yaml is:

name: examplebinarysnap
base: core20
version: '0.1'
summary: example snap
description: |
  This is description.

grade: devel
confinement: devmode
architectures:
   - build-on: amd64

parts:
  examplebin:
    plugin: dump
    source: release
    stage-packages:
      - lib1.a
      - lib2.a
      - lib3.a
      - c-binary #mybinary. Here?

apps:
  examplebin:
    command: examplebin

Should the c-binary be on the stage-packages section?

If I try to run “snapcraft” I get the error “Failed to fetch stage packages: Error downloading packages for part ‘fdoclientbin’: The package ‘lib1.a’ was not found…”

Are these libraries part of your project and in your release directory? Or are they in the Ubuntu repositories? The stage-packages keyword is fetches libraries with apt.

If everything (binary and libraries) is inside release/, then you don’t need the stage-packages keyword at all. The dump plugin copies the contents of release/ into the snap package.

These libraries are needed by the main binary (c-binary), they are not on the Ubuntu repositories. So if I understand correctly this is all I need in the parts section:

parts:
  examplebin:
    plugin: dump
    source: release

Correct?

Also, I get the error “Failed to generate snap metadata: The specified command ‘examplebin’ defined in the app ‘examplebin’ does not exist. Ensure that ‘examplebin’ is installed with the correct path.”

I suppose this is not the correct way to write the apps section…

Correct!

The apps section would look something like this:

apps:
  part-os-release:
    command: bin/os-release.sh

I pulled that from https://snapcraft.io/docs/defining-a-command.

You also may need to add an environment key with LD_LIBRARY_PATH in your snapcraft.yaml so your binary can load your libraries. You should be able to find some references for that on the forum or in the documentation.

Thank you very much. One last question though. What is the “bin/os-release.sh”? I do not have an .sh to run, just my binary in C.

bin/os-release.sh is just an example executable file to call. You can replace that to the filepath of your binary.

Thank you very much. Now the snapcraft process ends successfully. Then I install the snap with “snap install snap_name.snap --devmode” and I can run the binary with “snap_name.part-name”.

About the LD_LIBRARY_PATH , how I have to set this variable in the snapcraft.yaml?

apps:
  examplebin:
    command: mybinary
    environment:
      LD_LIBRARY_PATH: ???

Glad to hear you were able to package it!

Yes, that’s how I would recommend setting it. You can append to it with:

apps:
  examplebin:
    command: mybinary
    environment:
      LD_LIBRARY_PATH: $LD_LIBRARY_PATH:$SNAP/<path-to-your-custom-library-directory>

P.S. If you set the app name to the snap name, you can execute it directly.

i.e.

name: examplebinarysnap
...

apps:
  examplebinarysnap:
    command: bin/os-release.sh

Then you can execute it as examplebinarysnap instead of examplebinarysnap.<app-name>.

1 Like

All my custom libraries are in the “release” directory along with my binary so I suppose the correct directory for LD_LIBRARY_PATH is:

LD_LIBRARY_PATH: $LD_LIBRARY_PATH:$SNAP/release

Is it correct?

However, if I do so I get the error "CVE-2020-27348: A potentially empty LD_LIBRARY_PATH has been set for environment in… "

You can remove the self-reference, just LD_LIBRARY_PATH: $SNAP/release will be fine. If you include the self-reference, you’ll trigger the security warning above.

The other $LD_LIBRARY_PATH folders are handled elsewhere in runtime environment, so you’ll still get e.g $SNAP/lib/ & etc as appropriate.

2 Likes

Thank you very much for all your answers. I have one last problem I’m facing.

When I run the examplesnap executing my binary I get the error “error while loading shared libraries: libcurl-gnutls.so.4: cannot open shared object file: No such file or directory”. This “libcurl-gnutls.so.4” is not a library I have in my “release” directory (along with my binary) but I don’t understand why it needs it.

If I run my binary like “./mybinary” without any snap wrapping it works fine.

Any ideas?

You’d need to include libcurl-gnults (add it as a stage package) in your snap and update LD_LIBRARY_PATH to point at it.

With some specific libraries, you might find that they make a subdirectory in the usual folder, e.g $SNAP/lib/x86_64-linux-gnu/example-library, and place the .so files in there; where it wouldn’t be checked by default. Often this is because there’ll be a post-install hook in the apt package that handles symlinks in “real” environments, but those hooks aren’t executed for snaps. I don’t know if that library is one, but given the variety of implementations of TLS, I suspect it might be.

Aside from using $LD_LIBRARY_PATH to point to it directly, you could also consider modifying your snapcraft.yaml to move the file up a level into the normal search path; assuming that this might be the issue. Same end result but might be cleaner than having architecture-specific workarounds to set $LD_LIBRARY_PATH properly.