Snapcraft build-on hint for builders

Here’s the proposal from when base snaps weren’t a thing: https://lists.ubuntu.com/archives/snappy-app-devel/2016-April/000654.html

On that proposal we basically explored a key to hint builders for what architecture to build on, it had the form of:

target-architectures: [arch1, arch2, arch3]

Where archX could be any architecture tag as used on snaps today such as amd64 or arm64.

Given base snaps and to be future proof we probably want to extend that to something like:

build-on:
    ubuntu: [amd64, arm64]
    fedora: [amd64]

I know that fedora probably has a different naming for architectures, but we should want to keep consistency with what snapcraft produces for architectures.

A builder can then build on everything it supports in that dictionary/list.

4 Likes

Just to be clear, we’ll still support things like ubuntu: [any] (build on any supported architecture, produces architecture-dependent snap), right? This should probably be the common case; hardcoding lists of architectures has proven really very troublesome in the past for new-port enablement work.

Ideally we’d also support ubuntu: [all] (build on one supported architecture, produces architecture-independent snap that can be used on any architecture), though I don’t recall whether that would require additional support in the store; and indeed the full language supported by dpkg, since Launchpad uses dpkg-architecture's comparison facilities to decide which builders to dispatch a build to and it would be helpful to be able to reuse that code.

I seem to remember that being how the store worked initially, anyway. I expect no changes would be necessary.

Hi,

At the risk of re-opening old debates, this doesn’t seem like something that belongs in snapcraft.yaml to me. To my mind, the contents of snapcraft.yaml should describe the thing being built, whereas this is more about how to build the snap. I’m also concerned that we need to be careful how we document this feature, lest it be seen as “oh, snaps are just for Ubuntu” - separating this into a separate file makes the distinction between “what the snap is” and “how the snap is built” clearer, i think.

Would it be possible to separate “auto-build configuration” from the snap configuration itself?

Architecture-independent snaps aren’t fat snaps, just ones that contain no architecture-dependent code. Let’s please not conflate the two concepts.

Fair enough. Edited (although my comment still applies).

Well to be fair, snapcraft is all about how to build the snap. I think it is more of a social thing as well, since you might as well be able to build everywhere but only want to support your snap for architectures X, Y and Z, and only when the base snap is suse.

omission of ubuntu should mean exactly that.

Good point - these wouldn’t make their way into the snap.yaml, I assume?

That doesn’t make sense to me. Omitting build-on might reasonably mean that, sure, but for example:

build-on:
    fedora: [amd64]

… seems to say that the snap can only be built on Fedora, which is certainly a reasonable thing to want to express (for example if building the snap relies on build-packages or stage-packages that only exist in Fedora).

1 Like

Good point, So any as a string or a list? Either way there’d have to be checks to avoid [any, amd64] constructs.

This is what I get for being up so late as I was yesterday.

I think a list would be simplest and most consistent, so [any]. Ideally we’d just import the .deb rules directly so that we could reuse the same logic, and those rules already forbid things like [any, amd64]. With the possible exception of source, basically all of it still makes sense, and there doesn’t seem to be a compelling need to reinvent the semantics, just to rephrase the concrete syntax.

@niemeyer this was also one of the topics we ran out of time to discuss at the sprint. Can you please take a look?

There are several different aspects related to this topic which we need to take into account:

  1. What architectures the snap that was built can run on
  2. What architectures the snap may be built for
  3. What architectures is the snap being built for
  4. What base the snap that was built will run on
  5. What bases the snap may be built for
  6. What Linux distribution may the snap be built on
  7. What base should be used when the snap is built on a particular Linux distribution

The conversation so far has handled these topics somewhat implicitly, and at times it feels like some unintentional bridging between these ideas is taking place. This is worrying since people not participating in this debate will be unable to tell what particular aspect is covered and how to do what they want.

So, I propose we start off with a minimalist approach that focuses on the common cases and on a reasonable user experience for people doing the usual. For example, most people will not be building their snaps in multiple distributions, as by the end of the day a single snap will be pushed into store, and that single snap will be on a single base.

Also, it feels strange that we’re trying to separate multiple architectures upfront depending on the Linux distribution. In practice, the parts that compose the snap will in most cases define what architectures are supported by the snap, and these are not dependent on a particular distribution.

Along similar lines, the base will often be dependent on the system that is being used to create the snap instead of on the particular project being built. For example, if one builds a snap with packages from Fedora, it doesn’t make much sense to use a base that was created out of ubuntu 16.04.

So, circling back into the original point, I’m concerned about just putting syntax in without understanding in more detail the problems we’re solving and how people are supposed to use it (or how to understand it).

Perhaps we can take some apparently “safe” first steps:

  • Define a system-wide default base internal to snapcraft. When not specified, snapcraft will attempt to build using a base that is appropriate for the local system if one exists, or complain if it can’t map the local system into an appropriate base.
  • Accept a new optional “base” field in snapcraft.yaml, which allows overriding the system default and request that a particular base be used for the built snap (one base).
  • Further explore why the “architectures” field is not enough. Having multiple architecture fields will certainly be confusing, so if this is not enough we need to write down the exact problems we have today with this field and fix those.

Does that sounds reasonable?

The architectures field in snapcraft.yaml behaves the same way it did in snap.yaml and it basically hints the store into on what architectures to offer this snap.

The original introduction of this was fat packages. We can change the semantics, but this is how architectures works today:

name: my-package
architectures: [amd64]
...
parts:
    source: .
    plugin: dump

Regardless of the architecture (armhf, amd64, i386) this is ran on this will happen

$ snapcraft
Snapped my-package_1.0_amd64.snap

With snap.yaml containing a architectures: [amd64] entry.

And for

name: my-package
architectures: [amd64, armhf]
...
parts:
    source: .
    plugin: dump

Will result in

$ snapcraft
Snapped my-package_1.0_multi.snap

With snap.yaml containing a architectures: [amd64, armhf] entry.

If left out, snapcraft will set it to the architecture of the build host.

So in essence it is the architectures to say it will work on at runtime but not where this build should be triggered on.

We don’t do breaking changes in the format, but the use case of this is so confusing that we have not promoted it but I don’t mind breaking the semantic meaning of this in snapcraft and tell people that want to dump a python file and create a snap on amd64 to push it to pi to just use --target-arch (for the few not knowing about this already).

This feature is really old as well, I wasn’t in the snapcraft conversations at that time:

commit a86d80aa22f8b728ec116ad87a652f34d1571992
Author: <redacted>
Date:   Tue Jul 28 16:00:10 2015 -0400

    Look in library-triplet locations and set architectures in package.yaml

So that is the explanation of why it is not enough, but it is so backwards that if there is consensus I don’t mind changing this behavior with the caveat of knowing this might break some existing builds.

If reconsidering how the architectures field works, please also keep in mind the following:

  • 64bit snaps that ship 32bit binaries that run in compat mode (eg, amd64 wine snap that can run both 64bit and 32 bit windows applications on a 64bit machine)
  • 32bit snaps that ship (some) 64bit binaries that run on the kernel’s native architecture (this is highly specialized but needed for systems with a 64bit kernel snap and 32bit core snap. I’ve been told by CE that devices using a 64 bit kernel with 32 bit userland is important for certain classes of embedded (IoT) devices (and something at least the snapd security policy currently handles))

IME, we don’t have to handle these specially-- in both cases publishers will produce snaps that match the architecture of the core snap, but ship (a few) binaries that might be for the other arch. Today this all works ok and I mention these use cases for if we change things we don’t break them going forward.

Luckily the behavioral change is to make it something builders can respect to have information on where to build in the builder pool of architectures and not what the resulting architecture would be which would be determined by the host used to build.

So, if the host is amd64 and I dump in 32bit binaries in there, or regardless of what parts I use, the architecture would be amd64 unless I use --target-arch which would trigger cross compiling mode.

2 Likes

@niemeyer I gave this more thought and I don’t think it would be wise to change the semantic meaning of architectures in snapcraft.yaml as it will mean that it has a different meaning than the architectures field in snap.yaml which would be more confusing when we speak of each interchangeably.

@sergiusens This is not necessarily true, and I don’t see a clear proposal above to make a judgement on it.

Trying to drive this topic to a more concrete change, here is a proposal: what if we allowed the architecture field to be defined like this:

architectures:
  - [armhf]
  - [amd64, i386] 

The behavior of snapcraft when it sees a field like that is to build all the architecture sets it can. Each set will result in a single snap, and the value in snap.yaml will be the set itself (either armhf or amd4, i386 in the case above).

We may also introduce an --arch flag that tells snapcraft to only build the snaps that work on that particular architecture. In the example above, both --arch=i386 and --arch=amd64 would cause snapcraft to only build the second snap, even it knows how to build an arm snap.

How does that sound?

1 Like

Debian basearch names are too ambiguous at times. For example: both armv6hl and armv7hl would be Debian’s armhf or RPM’s armhfp base arch name but are fundamentally incompatible. Heck, armv7hl and armv7hnl itself can be problematic. As long as we’re willing to ignore the fact that our base arch definitions include incompatible architectures, base arch names are fine. However, this will bite us. Even in Debian, this is a problem, because Raspbian armhf is not the same as Debian armhf, and that makes binaries incompatible with the simplistic model presented by dpkg.

Several months back, I proposed we move from base arch names to platform triples to eliminate ambiguity (as far as I know, both RPM and dpkg can use components of a platform triple to resolve to the understood platform), which @mvo thought wasn’t a bad idea. And at least with the DNF package manager, we need to know the “real-ish” architecture to be able trigger foreign architecture mode (doing armv7hl stuff on x86_64, for example). However, that’s a drastic revamp of how things work.

The idea of any architecture should be implied when not specified. It’s something that I’ve considered a weird quirk of Debian that you specify this (in RPM, this is implied when architectures are not specified).

The all architecture (equivalent to the RPM noarch architecture) is perfectly fine for arch-less snaps, but I think those don’t exist in practice. The nature of how snaps work mean that it’s rather difficult to have such a snap exist, and if it does, it’s really by accident rather than intentionally. I think it’d be a bad idea to support such a thing, as snaps are not granular enough.

I also agree with @niemeyer that architecture is a trait separate from the system base, and usually is an overarching one (excuse the pun!). Often, architectures do not change across platform bases, so it doesn’t make sense to force redefinition across different distribution selections.

That also said, I think using Debian logic for architectures will bite us hard, and we should avoid it. It’s too simple, and there’s enough cases that can be conceived where this will produce unexpected results.

1 Like