Background
Snapcraft currently supports an architectures
keyword that one can use to specify the architectures on which the snap runs. However, this has proven to be a confusing feature, for a few reasons:
- The same
snapcraft.yaml
file is used to build the snap for multiple architectures, and yet if one used thearchitectures
keyword, each of these snaps (regardless of the architecture on which it was built) claimed it ran on the same set of architectures. - It’s not at all uncommon for someone to provide a list of architectures in the
snapcraft.yaml
using this keyword, and then build the snap on build.snapcraft.io. The expectation is typically that it will build the snap for the architectures “requested”, when in fact that’s not the purpose of this keyword, nor does build.snapcraft.io use it in this manner.
Proposal
The proposal is to rework this keyword to better match user expectations. The architectures
keyword will be restructured into a list of more explicit objects, specifying both build and run architecture(s):
architectures:
- build-on: [<build arch 1>, <build arch 2>]
run-on: [<run arch 1>, <run arch 2>]
Note that, while both of these can be a list, if the list is a single item they can also be simplified to a scalar (e.g. build-on: amd64
). The default value for run-on
is the value of build-on
.
This keyword will remain completely optional. By default, Snapcraft will continue to build a snap that claims it runs on the same architecture as the build environment. Also, similar to what it does today, it will support all
as a valid run-on
architecture to denote a snap that can run everywhere (e.g. a snap that is only shell scripts).
Regarding CI systems (such as build.snapcraft.io), they can use this keyword to determine the architectures to use to build this snap: if none are specified, build all architectures. Otherwise, build only the ones specified.
Another piece to this puzzle when it comes to CI systems is the concept of a “build set”, defined to be the set of snaps built from the same snapcraft.yaml
at the same point in time (the same commit, if we’re talking git). This set of snaps could be managed as a set instead of needing to manage each revision on its own. This proposal assumes that the CI system will fail the entire build set if any one of the builds fail (e.g. given a build set of amd64, i386, and armhf, if the armhf build fails, the entire build set is considered to have failed regardless of whether or not amd64 and i386 succeeded). To that end, one can use build-error: ignore
to indicate an experimental/in-progress architecture that should be counted as part of the build set if it succeeds, but not cause the rest of the build set to fail if it fails.
Examples
Example 1
architectures:
- build-on: i386
run-on: [amd64, i386]
Snapcraft’s interpretation
If running on an i386 host, Snapcraft will build a snap that claims it runs on both amd64 and i386. If running elsewhere, Snapcraft will follow its default behavior, building a snap that runs on the build architecture.
CI systems’ interpretation
As there is a single non-scalar object in this list, CI systems know to produce only a single snap. Checking the build-on
key, they know that it needs to be built on i386.
Example 2
architectures:
- build-on: amd64
run-on: all
Snapcraft’s interpretation
If running on an amd64 host, Snapcraft will build a snap that claims it can run on all architectures. If running elsewhere, Snapcraft will follow its default behavior, building a snap that runs on the build architecture.
CI systems’ interpretation
CI systems can assume that the user only wants the snap built on amd64.
Example 3
architectures:
- build-on: amd64
run-on: amd64
- build-on: i386
run-on: i386
Which is the same as:
architectures:
- build-on: amd64
- build-on: i386
Snapcraft’s interpretation
As far as Snapcraft is concerned, this is no different from its default behavior.
CI systems’ interpretation
CI systems can assume that the user only wants the snap built on amd64 and i386, and the resulting snaps are to be considered a build set (e.g. if amd64 succeeds but i386 fails, the entire set should be considered to have failed).
Example 4
architectures:
- build-on: amd64
run-on: amd64
- build-on: i386
run-on: i386
- build-on: armhf
run-on: armhf
build-error: ignore
Snapcraft’s interpretation
Again, as far as Snapcraft is concerned, this is no different from its default behavior.
CI systems’ interpretation
CI systems can assume that the user only wants the snap built on amd64, i386, and armhf. While the resulting snaps are considered a build set, armhf may fail. If it does, release the rest of the build set as normal (i.e. don’t fail the entire build set if armhf fails). If amd64 or i386 fails, however, still consider the entire build set to have failed.
Example 5
architectures:
- build-on: [amd64, i386]
run-on: all
Snapcraft’s interpretation
If building on amd64 or i386, Snapcraft will produce a snap that claims it runs on all architectures. If running elsewhere, Snapcraft will follow its default behavior, building a snap that runs on the build architecture.
CI systems’ interpretation
There is only a single non-scalar item in architectures
, so CI systems know there is only a single snap to be produced from this, and the resulting snap will claim it runs on all architectures. However, the snap author has specified that either amd64 or i386 could be used to produce this snap, which leaves it up to the CI system to decide which architecture to use. Which one has a smaller build queue?
Example 6
architectures: [amd64, i386]
Which is the same as:
architectures:
- build-on: [amd64, i386]
Which is the same as:
architectures:
- build-on: [amd64, i386]
run-on: [amd64, i386]
Snapcraft’s interpretation
If building on amd64 or i386, Snapcraft will produce a snap that claims it runs on both amd64 and i386. If running elsewhere, Snapcraft will follow its default behavior, building a snap that runs on the build architecture. Note that this is a different interpretation of the currently-supported syntax.
CI systems’ interpretation
There is only a single non-scalar item in architectures
, so CI systems know there is only a single snap to be produced from this, and the resulting snap will claim it runs on both amd64 and i386. However, the snap author has specified that either amd64 or i386 could be used to produce this snap, which leaves it up to the CI system to decide which architecture to use. Which one has a smaller build queue?
Example 7
architectures:
- build-on: amd64
run-on: all
- build-on: i386
run-on: i386
Snapcraft’s interpretation
Technically Snapcraft could work with this, and treat it similarly to Example 5. However, in this proposal it is an error, mostly to inform the user because of the CI systems’ interpretation of this.
CI systems’ interpretation
There are two non-scalar items in architectures
, which implies that two snaps will be built. However, one of the snaps to be produced would claim it runs on i386, while the other would claim it runs everywhere (including i386). That means they would both be released to i386, which is likely not what the developer intended (since the user will only receive the latest). This is an error case.