Specifying architecture on cross-compilations

I updated the post to more clearly separate context, problem description, proposal and implementation. Please let me know if there’s more need for clarification.

It’s a bit more clear, but I’m still missing something.

When you say “apt-get build-dep can be used, provided the host has source packages configured, to figure out the multi-arch equivalent of a set of packages”, that sounds to me like magic which we don’t want. We have an explicit syntax defining which packages should be installed on which architectures. All we want, I believe, is to be able to use the existing “on” syntax which @ogra asked for and which is already being used in snapcraft.yaml in stage-packages.

Also, as a minor note, we’re not adding the support for “:native” in snapcraft.yaml, right? That sounds implied and not very useful.

@sergiusens Can you please organize a call with the three of us, plus @ogra and @mvo? We’ve been discussing this for a bit too long without much clarity, so a call will probably help sorting out these details more easily.

Done. I was planning on creating an alternate post going over what each thing is in a “clearing the air” type of prose, I might do it anyways, just wondering now if I should do it after the call.

1 Like

We need less posts on this topic, rather than more. Part of the issue is precisely that we have so many concurrent conversations about what is apparently the same thing.

We just had a very nice call on this topic (thanks for organizing @sergiusens) and the agreements feel quite promising. In a nutshell:

  1. The existing “on <arch>:” syntax will be accepted under build-packages as well
  2. The default architecture for packages under “on <arch>” is the one from the build machine
  3. Packages under “on <arch>:” are installed only when the build machine has that architecture
  4. A new “to <arch>:” statement will be supported in build-packages and stage-packages
  5. The default architecture for packages under “to <arch>:” is the target architecture
  6. Packages under “to <arch>:” are installed only when the target architecture is the one listed, which includes both a cross-compilation towards that architecture and a native build on that architecture
  7. The two statements may be used together as “on <arch> to <arch>:” to precisely specify the case of a particular cross-compilation
  8. The default architecture for packages under “on <arch> to <arch>:” is the target architecture
  9. The default architecture for top-level packages (those outside of any “on” or “to” sections) is the one from the build machine
  10. The following suffixes may be used after any package name under stage-packages and build-packages to override the default architecture:
    10.1. “:native” - package must have architecture of the build machine
    10.2. “:target” - package must have the target architecture
    10.3. “:<arch>” - package must have the specified architecture
3 Likes

Then that means snapcraft needs to pre-process the entire package set directives so that they can be handled in a backend independent manner. I currently don’t know how I’m going to handle a mix of these with the soon-to-be made RPM backend…

In case it’s not clear from the above: while the :native suffix happens to have the same name as Debian’s, :target is entirely new. And both can be implemented as literal replacements to whatever the backend’s syntax is for a package from a specific architecture.

The PR resolving these items is here.

2 Likes

I proposed a PR implementing :target.

I have PRs for the following parts of the proposal:

#1639

#1800

One question came up last week: there will be two ways to use the new “to” statement, given the above proposal, which wasn’t specifically discussed - or at least not recorded anywhere that I’m aware of.

on i386:
  - to armhf:
    - hello

on i386 to armhf:
  - hello

If on..to is implemented, like I did in my branch, we still get the nested style for free given the way the grammar works. Do we want to make it an error so only on ie86 to armhf is allowed?

Please no, that’s a redesign-- it breaks the recursive nature of the grammar.

The fact that you can write the same thing two ways is more insidious than it first appears. Note that the two examples given above look like they’re writing the same thing, but they’re not.

Say you have a part definition like this:

my-part:
  plugin: nil
  stage-packages:
    - on i386 to i386: [hello]

Odd, I know, but bear with me. If you’re on an amd64 machine, this rule should be impossible to match. And indeed, hello is never fetched, regardless of whether you run snapcraft or snapcraft --target-arch=i386.

However, if that same part were written this way:

my-part:
  plugin: nil
  stage-packages:
    - on i386:
      - to i386: [hello]

You get the same behavior when running snapcraft, but when you run snapcraft --target-arch=i386 it actually fetches hello:i386. This is because the standalone on statement uses the target arch for its selectors, not the host (similar to the to command). So these look the same, but they’re not. The new “on X to Y” is actually an entirely new “on” statement that works differently. This inconsistency is a problem, in my opinion, because they intuitively look like they should be doing the same thing.

If we fix the inconsistency by changing how the standalone “on” statement behaves to match, then why do we have an “on X to Y” statement at all? Why not just support the nested structure that we get for free with the addition of the to statement?

1 Like

Yes, the nested and non-nested statements should definitely work the same way, otherwise it’ll be very arbitrary and confusing.

Thanks for catching that, Kyle.

If we change the on statement, then, do we still need a new on X to Y statement? Or can we just introduce the to statement and have people write the nested version? Seems more succinct to not have two ways of writing the same thing.

The reason why these two statements should obviously do the same thing is also the reason why it seems fine to have the two of them: they express exactly the same idea, with the same terms and almost the same syntax. Forcing people to use the nested style for trivial cases doesn’t feel like a relevant win, and it’s definitely not more succinct.

I meant “succinct” as in clarity, not brevity, but yeah, point taken. If the on statements behave the same way, we should be able to re-use one to make the other so the code side makes me happier. @kalikiana does that sound like a good path?

From the original comment from Gustavo it seems that this is what we want:

parts:
    plugin: nil
    stage-packages:
        - on <host-arch> to <target-arch>: [hello]

And

parts:
    plugin: nil
    stage-packages:
        - on <host-arch>:
            - to <target-arch>: [hello]

Meaning the standalone on statement should use <host> for its selectors. This expresses the intent of the snapcraft.yaml author that cross compilation is supported, but only when running from <host>.

I installed the snapcraft 2.38 edge channel on my ubuntu 16.04 x86 host to try out the “to” keyword in my stage-packages parts section. When I ran snapcraft --target-arch=armhf, the command failed with the following summary (I’ve excluded the line-by-line python error messages):

apt.cache.FetchFailedException: E:Failed to fetch http://security.ubuntu.com/ubuntu/dists/xenial-security/main/binary-armhf/Packages 404 Not Found [IP: 91.189.88.161 80], E:Failed to fetch http://us.archive.ubuntu.com/ubuntu/dists/xenial/main/binary-armhf/Packages 404 Not Found [IP: 91.189.91.26 80], E:Failed to fetch http://us.archive.ubuntu.com/ubuntu/dists/xenial-updates/main/binary-armhf/Packages 404 Not Found [IP: 91.189.91.26 80], E:Failed to fetch http://us.archive.ubuntu.com/ubuntu/dists/xenial-backports/main/binary-armhf/Packages 404 Not Found [IP: 91.189.91.26 80], E:Some index files failed to download. They have been ignored, or old ones used instead.

Any ideas what I’m doing wrong? My snapcraft.yaml file is as follows:

name: netdata # you probably want to 'snapcraft register ’
version: ‘0.1’ # just for humans, typically ‘1.2+git’ or ‘1.3.2’
summary: netdata in snap form # 79 char long summary
description: |
Attempt to build a snap for the netdata applicaiton
grade: devel # must be ‘stable’ to release into candidate/stable channels
confinement: devmode # use ‘strict’ once you have the right plugs and slots

apps:
netdata:
command: netdata
plugs: [network-bind, hardware-observer]

parts:
my-part:
plugin: autotools
source-type: git
source: https://github.com/firehol/netdata
build-packages:
[zlib1g-dev,
uuid-dev,
libmnl-dev,
pkg-config,
curl]
stage-packages:
- to armhf:
[libghc-zlib-dev, uuid-runtime]

snapcraft uses the host machines sources.list by default … there are no armhf binaries on the “archive.ubuntu.com” machine (or its various mirrors like us.archive.ubuntu.com) … i bet if you temporary replace the sources.list with one from an armhf machine that error will go away …

Here is an example one …

deb http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted universe
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe

One general note on YAML in the forum: you need to indent by 4 spaces to render it as “preformatted text”, or use the button above the text field while selecting it. So this is what I tested with:

name: netdata
version: 0.1
summary: netdata in snap form
description: |
  Attempt to build a snap for the netdata applicaiton
grade: devel
confinement: devmode

apps:
  netdata:
    command: netdata
    plugs: [network-bind, hardware-observer]

parts:
  my-part:
    plugin: autotools
    source-type: git
    source: https://github.com/firehol/netdata
    build-packages: [zlib1g-dev, uuid-dev, libmnl-dev, pkg-config, curl]
    stage-packages:
      - to armhf: [libghc-zlib-dev, uuid-runtime]

From the looks of your error, it seems like your sources.list for armhf is wrong. It should look like this (note ports.ubuntu.com is slightly different to the standard archive mirrors):

deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted
deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted
deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ xenial universe
deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ xenial-updates universe
deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ xenial multiverse
deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ xenial-updates multiverse
deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports xenial-security main restricted
deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports xenial-security universe
deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports xenial-security multiverse

Now, building the snap, this is what I get:

> snap info snapcraft | grep -E 'tracking|installed'
tracking:    edge
installed:   2.38+git28.4c7edab (1033) 53MB classic
> snapcraft --target-arch=armhf
[...]
configure: error: C compiler cannot 
create executables
See `config.log' for more details

Said config.log contains this:

/home/rumo/dev/netdata/parts/my-part/install/usr/bin/ld: cannot find /usr/lib/arm-linux-gnueabihf/libc_nonshared.a

Adding libc6-dev-armhf-cross to build-packages didn’t seem to suffice as a quick build fix as it’s still hard-coding the path. But I hope this will get you a bit further.

Edit: Seems like @ogra was responding as I was still drafting my response :smiley: My sources.list is slightly more complete but both should do the trick.