Multiple questions from a first time user

Hello, after two days studying the snap framework, I admit not all is clear to me. Here are the questions the documentation does not seem to answer:

  • What is stage, what is prime? Who and what decides what to go there and why should I care.
  • What determents the final content of the installed application (on the user machine). Snap can pack all dependencies, but what does it means in practice. The snap Directory structure in the documentation is vastly different then the real world snaps I have seen. This is in sharp contrast to mac bundles, where bundles are almost exactly the same for all apps. It seems snaps bundles OS libs, which is fine I guess, but completely unclear by what mechanism.
  • It is unclear how a snap registers itself to the OS in terms of icons and other resources like the hicolor packs I would ship in a deb.
  • The word snap is used very liberally. Sometimes it means the final installed application (/snap/hello), sometimes the installer itself. Things like “these files will not make it to the host, but will be in the final snap”. are very confusing.
  • It is not clear does creating a snap gives rock-solid grantees the app will work on every platform with snapd installed. For instance does a plugin:dump have dependency tracking as well or only when I build through snapcraft?

I guess my biggest problem is understanding what snapcraft job is (outside compile) and what it is required from me! Where on mac I create the bundle by myself, and the bundle is as-is after it goes though packaging and then later is as-is on the user computer, here we (I and snapcraft) both work over the some “final snap”, which later itself be transformed again to a “host snap”. This is very, very confusing if not documented thoroughly.
Even the very hard to use NSIS (on Windows) is more clear why I am doing the things I do, writing the code I write. Here i just don’t know what snapcraft will do if I don’t do x and if i do y, would it hinder snapcraft to create good “host snap”.

thank you

3 Likes

Hi! I’ll have a go at these! :smiley:

When snapcraft runs it goes through some main stages, pull, build, stage, prime, snap.

During build there may be numerous parts which depend on bits from other parts. These are ‘staged’ in stage/ which is accessible to all parts. Towards the end, during the prime stage, the parts that are needed in the snap are copied to prime/ and finally the snap is built from what’s in the prime/ directory.

You probably only need to care if you’re debugging why stuff isn’t appearing in the snap, or why one part can’t consume the contents of another.

The final contents of the snap is whatever was in prime/. That’s up to the developer of the snap. Whatever parts are built and packages are staged end up in prime will end up in the snap.

When the snap is installed the desktop file gets dropped in /var/lib/snapd/desktop/applications. The desktop file gets re-written to ensure the icon path is correct, which typically points to /snap/<snapname>/<revision>/meta/<snapname>png. Other resources will be typically inside your snap, however there’s work ongoing to expose system wide icons / themes to snaps.

Yeah, snap is a noun and a verb, like “Google”.

The goal is always that if a snap works on one system, it should work on any other system that supports snaps. If it doesn’t that’s a bug and we need to fix it.

The dump plugin doesn’t do anything other than take what it’s given and unpack it. You can move things around with organize: or use filesets to remove unnecessary files (like man pages), and add libraries with stage-packages:

Hope that helps.

1 Like

By build you mean snap build or application build or both?

By the final snap you are referring to the “installer snap”, or the one on the user machine? Is prime a snapshot of user machine’s snap?

Ok, the desktop from the gui folder is copied there. How about icons for filetypes I provide? As I said it is undocumented how a “host snap” is made know to the os (besides .desktop).
With deb - we copy we have a directory structure to copy to the host sytem
On mac the bundle is as-is and it is the os responsibility to be aware of it. No user input need, even if not installed into /Applications - the bundle will be scanned and the os knows it.
On windows - one must write to the registry to let windows know about your app.

I dont have a problem with the fact it is a noun and a verb but the fact it is used for at least two nouns - the installer and the host application.

In other words to get dependency tracking I have to compile through snapcraft? If that is the case how can i specify my local Qt-build to build with it and it to be packaged instead of some public Qt package?

thanks

“build” is a stage in the snapcraft lifecycle. Some parts might be using the dump plugin in which case it just unpacks the source. For parts which use other plugs like make or cmake, snapcraft will run the right tool for the job which yes, may end up compiling something.

The developer runs snapcraft which makes a snap out of what’s in prime/. The user installs the snap which means they end up with a copy of whatever was in prime/ on the developer machine (or a machine under their control).

Snapcraft creates a .snap file which you’d upload to the store. Technically the snap is just a compressed archive containing all your binaries and assets and a small amount of metadata. Users will download and “install” that snap. The snap resides on the users machine typically under /var/lib/snapd/snaps and gets mounted (not unpacked) and appears under /snap/<snapname>.

With snap the user just “snap install foo” (or installs via a GUI like GNOME Software). As I mentioned, the snap is not unpacked, it is just mounted. Any icons you ship will be inside that snap archive, not unpacked all over the user file-system like a deb is.

snap is a binary which communicates with snapd. A .snap file is a compressed loopback file containing applications/libraries/kernels/drivers etc.

Much like “zip” is a command and “.zip” is a file, or “flac” is a command and “.flac” is a file. This is pretty common on Linux.

No. It’s possible to dump a pre-compiled binary (Qt or otherwise) into the snap as a part, which specifies stage-packages: which lists all the dependencies (assuming they’re available in the Ubuntu archive as debs), or the snapcraft.yaml may have separate parts for each of the dependencies if they’re not available in the archive.

What controls what is in the prime (hence the end user snap)? With prime I can influence it, but how is craft affecting it? I see the directory structure but real world snaps are hardly like that. Is this explicit programmer decision or craft’s one or both? I guess it is both, but I still want to know what craft does by itself without trail and error debugging. All should be documented - if you add this, snapcraft will add this and that to the user binary.

So for the moment, .desktop is the only kind of communication and I can’t really provide filetype icons as everything is basically private resource for the bundle?

Yeah, but the fact that snap is a stage for creating a snap, but that is not the user snap, as this one is actually in prime is not very friendly.
“Final snap” - is it the end user experience directory or the package. Sure, it is the package, but then, one reads the docs (snaps/structure) and it clear a snap is the final directory: “This section describes the directories found within a snap and details their content.”

This overloading is confusing (IMHO) as these are separate concepts, despite the fact that a .snap is “almost” the directory and .snap “does not really install”. Also, other platforms have almost the exact same concepts (especially mac) and there is no confusion there. Bundle (the end user directory), delivered as .pkg or .dmg.

I see. However these stage-packages are dumbed into the user snap, is this right? Does it matter if the user already has these or not?

thanks

P.S. Consider making the documentation a wiki so users can add to it.

When using snapcraft the package author defines what is primed into the .snap package. This is done via the parts stanza of the snapcraft.yaml which defines sources and what to do with them, the simplest being the dump plugin which just copies the source into the staging directory. Once in the staging directory snapcraft will follow any rules specified via organize and prime settings on the individual parts and copies the result into the prime folder which is then zipped-up into the .snap file.

Using snapcraft is the easiest way to create .snap packages, but is not the only way. You can create the package using your own methods and finishing by calling squashfs to zip-up the files you want in your package. If you do it this way, you need to be sure that you include the relevant files and folders specified in the directory structure post you linked previously in addition to your application’s files. This is the hands-on complex method that I wouldn’t advise unless you really understand snap package internals.

Anything you can specify in a .desktop file should still function when your application is inside a snap package. The main thing to be aware of is that icons need to be specified using the ${SNAP} variable followed by the full path to the icon:

Icon=${SNAP}/usr/share/icons/scalable/my-super-awesome-app.svg

I really can’t grok what you’re trying to say here. The snap utility is used for installing and managing packages, and is not used for the creation of any package files. The utility for creating snap packages is generally snapcraft but may be any other build system that outputs a snap package, such as electron’s electron-builder.

There is no “final snap” that is different from other snap packages. There is a snap package period. With snapcraft there are intermediate steps which it takes in order to build the snap package, but other builders may do it differently. The “directories found within a snap” refers to the required portions only, where they must be present for the snap package to be recognised as such and be installable. The snap package may also contain other directories, and most certainly will contain other files which comprise the actual application being packaged. Personally I tend to use the Linux Filesystem Hierarchy Specification for inspiration where I will include in packages that I create a <snap>/lib, <snap>/etc, <snap>/usr and so-on, mostly because that means I can use most build systems as-is such as autotools or cmake.

The snap package is a compressed filesystem. That means it has directories within, which are made visible via a loop-back mount which is anchored into /snap. The snap package isn’t almost a directory, it is a squashfs filesystem within a single file called your-snap-package-name.snap which is accessed via a call very similar to executing in the command-line:

mount -o loop /path/to/your-snap-package-name.snap /snap/your-package-name/x1

I’m not sure what you mean by “dumbed into the user snap”. If you mistyped “dumped” then yes, when using snapcraft, the .deb packages specified in the stage-packages section of a part are unpacked from their .deb containers and copied into the stage directory. Once there, and all the parts have been built the stage directory is copied, honoring any rules specified in organize and prime sections of each part in the yaml, into the prime directory which finally is compressed into a squashfs filesystem saved as a .snap file in the directory you called snapcraft from.

1 Like

That was actually, pretty clear and useful, thanks. Can you please add something like that in the docs. Some pipeline (why not with a diagram) would be very helpful so one can see an overview of the whole system + extension points.

Ok, got it. Please add a doc section “How snaps integrate with the system” or something, thanks.

About the use of snap word. I don’t think it is confusing with the snap utility.
I do think It is confusing how pull, build, stage, prime lead to (the final) snap, but prime is (as per documentation) “a snap”.
I will not argue about it any more, just wanted to point out, for someone from the outside, it feels like an overloaded word. Probably the final directory structure should not be called snap (as well). One is snap payload the other is snap package. If the same word is both for them (without disambiguation) it makes it hard to follow (and document, for that matter) to a newcomer.

About dump and dependencies. The way I understand it - to get dependencies automatically covered, I need to compile with craft. Otherwise I must put the packages manually into the package, right?

thanks

An application running from a snap package is usually confined via the package being confinement: strict. That means it’s view of the system on which it is installed is very restricted, and overseen via apparmor and seccomp security controls to prevent it from straying outside it’s boundary. Because of this confinement, anything the application needs, such as shared object libraries, needs to be either bundled into the snap package or provided by the core snap package for them to be found. The easiest way to approach that is to assume that you need to bundle anything other than libc.

A sticking point at the moment is that the location of bundled libraries needs to be specified via LD_LIBRARY_PATH envionment variable which works like the PATH variable but for libraries rather than executables. Snapcraft adds some common defaults into command-your-app.wrapper based on which plugs you enable. That file is the entry point for running your application (if you add multiple apps entries then there will be multiple .wrapper scripts) but other locations will need to be added if these are insufficient. It looks like snapcraft varies what it writes into these scripts depending upon which plugs you have specified, but that is news to me :-).

Wow, that is pretty important information. From the documentation I was under the impression strict was mainly read access restriction to the filesystem (and devices), not shut down from the entire, system libraries included. But that means under devmode an app could behave differently, loading different libraries? On the other hand, it makes sense dependencies to be exclusively in snap land.

Specifics aside, I like this approach, as it matches the other systems, notably Windows. On Windows you get your (new) program to run “anywhere” (older systems) by having the users install VS redistributable on their old systems. Of course, you can’t call new Windows APIs, but still have c++17 for instance. On mac you just flag the oldest version you want to support and live with the limitations of that era, but all will run from that era forward as long as the APIs are not removed.

Anyway, a core to represent the entire system is nice and simple. It is a different story what that snap should contain, as I would expect GUI libs to also be there.

What about rpath, that should work, right?