Install straight to stage space

I am still a bit confused about the separation of a part’s “install” and the common “stage” space.

The part lifecycle documentation says that the stage phase comes right after the build phase. So I assume that before the next part is built, a previous part’s “install” space has been copied to the “stage” space already. However, if I try to build a snap with three parts, it appears that when a consecutive part is built, the stage space is still empty.

As a workaround, I have to reference every install space manually like this:

qt6-base:
  source: git://code.qt.io/qt/qtbase.git
  plugin: cmake

qt6-qt5compat:
  source: git://code.qt.io/qt/qt5compat.git
  plugin: cmake
  cmake-parameters:
  # this is required because "qt6-base" hasn't been staged yet
  - -DCMAKE_PREFIX_PATH=${SNAPCRAFT_STAGE}/../parts/qt6-base/install/usr/local/Qt-6.2.2/

my_qt_app:
  source: git://path/to/my_qt_app.git
  plugin: cmake
  cmake-parameters:
  # again, this all has to be done because parts haven't been staged yet
  - -DCMAKE_PREFIX_PATH=${SNAPCRAFT_STAGE}/../parts/qt6-base/install/usr/local/Qt-6.2.2/
  - -DQt6Core5Compat_DIR=${SNAPCRAFT_STAGE}/../parts/qt6-qt5compat/install/root/parts/qt6-base/install/usr/local/Qt-6.2.2/lib/cmake/Qt6Core5Compat/

Especially setting the Qt6Core5Compat_DIR is quite ridiculous. It’s not possible to figure out this path without actually opening a shell inside the snap.

Why does snapcraft not run the “stage” phase right after each part’s “build” phase?

How can I install every part straight into the stage space? I tried to use -DCMAKE_PREFIX_PATH=/${SNAPCRAFT_STAGE} but this was always interpreted relative to SNAPCRAFT_PART_INSTALL.

Shouldn’t parts be installed into a common space, such that consecutive dependant parts do not have to manually set all these paths?

Each part is built in a separate directory, but it can use the contents of the staging area if it specifies a dependency on other parts using the after keyword. See Step dependencies for more information.

from https://snapcraft.io/docs/parts-lifecycle

E.g.

my_qt_app:
  after: [qt6-base, qt6-qt5compat]

Thanks, that explains a lot.

I found:

By default, snapcraft runs the same lifecycle step of all parts before moving to the next step.

Does that mean, by default, snapcraft runs all “build” phases before doing any of the “stage” phases? This would explain my observation.

But why is this a sensible behaviour? I thought that the after keyword is only required if the parts are not listed in the order in which they are supposed to be built. Snapcraft only builds a single part at a time anyway, so in the case above qt6-qt5compat will always be built after qt6-base, even without specifying after.

I think it makes more sense if, by default, all phases of a part are run and parts run in the order in which they are listed in the parts section.

because not all snaps use parts that depend on another, if you do not declare that you want this (by setting the before and after keywords) snapcraft will just process each part separately … if you change one part, only this single part will be re-built (and re-staged/re-primed) … if you declared the order, depending parts will be re-built too …

if snapcraft would by default process all parts in order and not use the before/after keywords it would not be possible to do such isolated re-builds, it would always have to re-build all parts

That is not the problem. Snapcraft always only builds one part at a time. Independently of if a part is referenced by an after or not, snapcraft should just always run the “stage” phase after the “build” phase for every part.

With explicitly providing an after, this could be set implicitly by the order in which parts are listed in the parts section. In the case above, this would be implicitly setting:

qt6-qt5compat:
  after: [qt6-base]

These are two distinct issues:

  1. always run “stage” after “build” for every part, independently of after
  2. if not provided, set after implicitly by the order of parts in parts

sorry, i was seemingly not clear, with “process” i meant indeed each of the phases (build, stage, prime) …

the point is that the staged files are by default not tainting other parts and are not causing a dependency re-processing if you only change one part …

if you would force a default dependency chain, building something like a kodi snap on armhf would be extremely painful (on a Pi thats roughly a 4h build) when you just try to adjust some lines in the launcher script that is provided by a different part …

when you just try to adjust some lines in the launcher script that is provided by a different part

Ok, I can imagine a situation where a default dependency chain is no optimal.

But what about always running the “stage” phase after “build”? Is there a reason why this does not happen by default? All parts are staged at some point in time, why can this not happen always right after the build?

I’d like to know, too.

The way the parts processing algorithm is implemented (all parts go through each step before advancing to the next step, except when after is used) makes sense if you consider that you can set a target step to reach and then advance from there one step at a time in subsequent runs (snapcraft pull to pull all parts, then snapcraft build to build all parts, and so on).