Parts, together with plugins, are one of the key components to any snapcraft project, what follows intends to explore what parts can do after a quick recap on some concepts.
base in snapcraft defines where the building of a snap should take place and once it is built, where it should run.
As an example, two prominent bases are
core18.When building, these use a stack based out Ubuntu 16.04LTS for the former and Ubuntu 18.04LTS for the latter. This information is encoded in the project’s
snapcraft.yaml as a top level keyword
snapcraft will trigger the correct behaviour.
Read more about bases here
A part is the basic building block for a snapcraft project, it defines the recipe to build a specific source, a basic example of a part can be:
parts: hello-part: source: gnu-hello.tar.gz plugin: autotools
The plugins defined in a part have the knowledge on how to build that specific source, to get a list of the available plugins run
Find more about using the different language specific plugin guides here
All parts, by means of the logic encoded in the plugins, go through a lifecycle. These are the lifecycle steps each part goes through irrespective of the chosen plugin:
Each of these lifecycle steps is exposed through the command line and can be part specific or apply to all parts in a project:
snapcraft pull [<part-name>]
snapcraft build [<part-name>]
snapcraft stage [<part-name>]
snapcraft prime [<part-name>]
For completion, the resulting snap is generated by calling
snapcraft snap which is also the implicit command, so usually this is invoked as just
Each lifecycle step depend on the previous, so to reach the desired lifecycle step, all prior lifecycle steps need to have run.
Parts can also depend on each other, this is usually exposed through the
after keyword in
snapcraft.yaml. This adds a new dependency to the lifecycle in that all dependant parts must be staged prior for the depending parts’ lifecycle can run.
Each part when run through its lifecycle (the lifecycle itself depends on the selected plugin) will have different working directories:
parts/<part-name>/srcused to pull the source during the pull step.
parts/<part-name>/buildused to build the pulled sources during the build step.
parts/<part-name>/installa location to privately install built artifacts during the build step
stagea shared place where parts can expose artifacts to other parts such as development libraries, headers or others (e.g.; pkgconfig files).
primea shared place where the final artifacts are to be placed, this directory is the reflection of the resulting snap.
overriding the lifecycle
Sometimes the default behaviour of a plugin is not enough or not desired, for this purpose there are two methods:
- Using the
override-<step-name>keyword (read more on overriding steps)
- Using a local plugin, by inheriting from the parent or scaffolding from the original (read more on local plugins)
When a part is run, snapcraft sets the following environment variables so they can be accessed through overrides or build specific logic for a project that contemplates snapcraft in its code path (e.g.; a
Makefile that has an install target that transparently contemplate
These are the exposed directory related environment variables, cosideration on how the lifecycle works should be taken when using some of these:
- SNAPCRAFT_PROJECT_DIR: the absolute path to the root of the snapcraft project
- SNAPCRAFT_PART_SRC: absolute path to where a part’s sources are pulled, it is also the part’s working directory for the pull step
- SNAPCRAFT_PART_BUILD: absolute path to where a part’s sources are built, it is also the part’s working directory for the build step
- SNAPCRAFT_PART_INSTALL: absolute path to where a part’s is to install artifacts to be staged.
- SNAPCRAFT_STAGE: absolute path to where files are staged.
- SNAPCRAFT_PRIME: absolute path to where files are primed.
Certain facilitating environment variables are also set:
- SNAPCRAFT_ARCH_TRIPLET: the architecture triplet used for the selected base.
- SNAPCRAFT_PARALLEL_BUILD_COUNT: the preferred amount of jobs the project is to be built with
- SNAPCRAFT_PROJECT_NAME: the snapcraft project name (i.e.;
- SNAPCRAFT_PROJECT_VERSION: the snapcraft project version as set in
- SNAPCRAFT_PROJECT_GRADE: the snapcraft project grade as set in
And lastly, specific build flags are also set:
- CFLAGS: empty unless
afteris used in the part and headers are staged in the common include paths for which they will be included (i.e.; paths added with
- CPPFLAGS: same behavior as CFLAGS
- CXXFLAGS: same behavior as CFLAGS
- LDFLAGS: empty unless
afteris used in the part and headers are staged in the common library paths (i.e.; paths added with
- PKG_CONFIG_PATH: empty unless
afteris used in the part and .pc files are staged in the common pkgconfig paths.
A plugin can also add its own set of environment variables or expand on these existing build related ones.
It is sometimes useful to override or expand on the defaults, for that, the
build-environment keyword can be used, here’s a basic example:
parts: hello-part: source: gnu-hello.tar.gz plugin: autotools build-environment: - CFLAGS: "$CFLAGS -O3" # add -O3 to the existing flags - LDFLAG: "-L$SNAPCRAFT_STAGE/non-standard/lib" # override default flags and search for libraries in a non-standard path
When considering the GNU build tools, the same applies and when using different bases, different build flags could be applied depending on the selected base.
On Ubuntu based bases you can verify which hardening flag has been applied to your built artifacts by running
hardening-check against your built binaries in the priming area.
As an example:
hardening-check prime/usr/bin/indicator-sensors prime/usr/bin/indicator-sensors: Position Independent Executable: yes Stack protected: yes Fortify Source functions: yes Read-only relocations: yes Immediate binding: yes