Snapcraft advanced grammar

Several fields in snapcraft.yaml are dependent on the architecture or the operating system being exposed to Snapcraft. This is accomplished using a specific and advanced syntax within the YAML consumed by the snapcraft command.

The following build-packages section, for example, evaluates and then defines which build packages to install depending on the target environment (to) for the snap:

    build-packages:
      - to arm64:
        - g++-multilib-arm-linux-gnueabihf
        - gcc-multilib-arm-linux-gnueabihf
      - else:
        - gcc-multilib
        - g++-multilib

This advanced grammar is made up of three nestable statements: to, on and try.

The to statement

    - to <selector>:
        <grammar>|<primitive>
    - else:
        <grammar>|<primitive>

The body of the to clause is taken into account if every (AND, not OR) selector is true for the target environment.

The only selectors currently supported are host and target architectures (e.g. amd64 ).

<primitive> may be either a list or a scalar, depending on whether the keyword is a command-delimited list of names or not.

If the to clause doesn’t match and is immediately followed by an else clause, the else clause must be satisfied. A to clause without an else clause is considered satisfied even if no selector matched. The else fail form allows for the generation of an error if a to clause is not matched.

Optionally an ‘on’ statement can precede a 'to' in the same line to form a compound statement. Used this way, the selectors of both statements have to be true. That is to say, both the build environment and the target have to be true for the body of the clause to be taken into account.

The on statement

    - on <selector>[,<selector>...]:
        <grammar>|<primitive>
    - else[fail]:
        <grammar>|<primitive>

The body of the on clause is taken into account if every (AND, not OR) selector is true for the build environment.

The only selectors currently supported are host and target architectures (e.g. amd64).

<primitive> may be either a list or a scalar, depending on whether the keyword is a command-delimited list of names or not.

If the on clause doesn’t match and is immediately followed by an else clause, the else clause must be satisfied. An on clause without an else clause is considered satisfied even if no selector matched. The else fail form allows for the generation of an error if a to clause is not matched.

The try statement

    - try:
        <grammar>|<primitive>
    - else:
        <grammar>|<primitive>

The body of the try clause is taken into account only when all primitives contained within it are valid (primitive validity is determined on a keyword-specific basis). If they are not all valid, and are immediately followed by else clauses, those are tried in order, and one of them must be satisfied. A try clause with no ‘else’ clause is considered satisfied even if it contains invalid primitives.

<primitive> may be either a list or a scalar, depending on whether the keyword is a command-delimited list of names or not.

Warning:

The try statement does not work with builds using a base snap of core22 or later.

Example

The following two examples will set different environment variables for the build stage, depending on the host (on) and target (to) architectures:

    build-environment:
      - on amd64 to arm64:
        - FOO: BAR
      - on amd64 to armhf:
        - FOO: BAZ
    build-environment:
      - on amd64 to [arm64,armhf]:
        - FOO: BAR
      - on amd64 to riscv64:
        - FOO: BAZ
1 Like

Converted from the legacy documentation.

It would be really helpful if examples were provided for the usage of on and to.

3 Likes

This documentation is clear as mud. :face_with_hand_over_mouth: Please add some examples for on and to.

I am trying to figure out how to dump architecture-specific tarballs.

As I read it, “try” has been dropped from SC7, so should this page be updated? Or is there another page for SC7 grammar?

I’m still concerned that not all of this is valid under SC7 and core22.

I’ve added the following note, but I’d like @degville to take a look to figure out better words than I can do.

Thanks for adding this!

…and currently the advanced grammar doesn’t work for configuring plug-in lists-of-strings.

I think this could do with a more concrete explanation of the syntax or an example of valid syntax, because I found it quite confusing.

The way the example is written, it isn’t obvious that in the case of multiple selectors in either on or to that the entire thing is a tuple. For instance, it leads me to think the below is correct:

  - on amd64 to arm64,[armhf]:

But it certainly isn’t.

It’s worth noting, however, that such a usage won’t result in an error (or even a warning message!)

It may be obvious to others who are familiar enough with YAML, but it wasn’t to me – you’d think I’d know by now, too!

To really pull out what advanced grammar actually looks like in practice, I’d suggest a concrete example:

    build-environment:
      - on amd64 to arm64:
        - FOO: BAR
      - on amd64 to armhf:
        - FOO: BAZ
    build-environment:
      - on amd64 to [arm64,armhf]:
        - FOO: BAR
      - on amd64 to riscv64:
        - FOO: BAZ

Note that I think the aforementioned lack of warning or error is a bug.

Likewise, I think it’s a bug that snapcraft won’t accept a space in the to selector; using a space is valid for all other tuples (I always use spaces in my tuples…) and yet it results in an error and a message:

Bad snapcraft.yaml content:
- spaces are not allowed in 'on ... to' selector (in field 'parts.my-part.build-environment')   

Further notes:

I think:

<primitive> may be either a list or a scalar, depending on the keyword.

Is too unclear; depending on what about the keyword? The answer I think is “if the keyword is multiple comma-delimited names”, but it’s very vague.

I also think:

Currently the only selectors supported are host architectures (e.g. amd64 ).

Should be fixed. Firstly, both host and target architectures are supported selectors (per the example above), but also that these are the only valid selectors should be made more clear, like updating it to read:

The body of the on clause is taken into account if every (AND, not OR) selector is true for the build environment.

Note:

Currently the only selectors supported are host and target architectures (e.g. amd64 ).

Hi @dilyn. Thank you so much for such a detailed set of suggestions for this page. I think I’ve now incorporated all of them, while also trying to simplify what this page was trying to accomplish. Thank you!

1 Like