Advanced Grammar for Layouts (or workaround)

I’ve built an amd64 snap that includes the OpenJDK JRE.

I’m working with a pre-built binary which expects the Java binary at /usr/bin/java8. For amd64, I’m able to solve this problem with a layout:

  /usr/bin/java8:
    symlink: $SNAP/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java

The problem is that this symlink path is architecture-specific. If I build the snap on arm64, the openjdk folder is not going to be under java-8-openjdk-amd64. I’d like to use the Advanced Grammar feature, but that’s not allowed for layouts.

I’m installing the JRE as a stage-package, so it’s installed using apt.

    stage-packages:
      ...
      - openjdk-8-jre-headless

What’s the path of least resistance to resolving this?

I don’t need other packages such as the JDK or full JRE and would rather not use the Java plugin.

I don’t know if there is any way to do this today either… but maybe we could support something like $SNAPCRAFT_ARCH, or otherwise allow a user to specify arch-dependent variables and apply them on layouts? @sergiusens

You could make a “trampoline” symlink in your snap which is arch-dependent and point the layout at that symlink, so you would have something like:

layout:
    usr/bin/java8:
        symlink: $SNAP/usr/bin/java-trampoline

parts:
    symlink-trampoline:
         plugin: nil
         override-build:
             mkdir -p $SNAPCRAFT_PART_INSTALL/usr/bin/
             if [ "$(arch)" = "arm64" ]; then
                 ln -s ../../usr/lib/jvm/java-8-openjdk-arm64/jre/bin/java $SNAPCRAFT_PART_INSTALL/usr/bin/java-trampoline
             elif [ "$(arch)" = "amd64" ]; then 
...

Admittedly this is made awkward by the absence of --target-arch in modern snapcraft versions, so you can’t really use $SNAPCRAFT_ARCH_TRIPLET

1 Like

Thank you, that worked! I was trying to do something along those lines using raw layouts but wasn’t able to. I think your solution is best.

The following code works on amd64. I haven’t been able to test on arm64 because of another issue (not on a raspberry pi), but It shouldn’t take many modifications to make it work. I’ll test armv7 soon.

...
parts:
  mypart:
    stage-packages:
      ...
      - openjdk-8-jre-headless
    override-build: |
      # execute default build step
      snapcraftctl build

      cd "$SNAPCRAFT_PART_INSTALL/usr/lib/jvm" || exit 2

      # This dir will be a symlink to java-8-openjdk-<arch>
      OPENJDK_DIR_SYMLINK="java-8-openjdk-arch-symlink"

      case $(arch) in
        x86_64)
          OPENJDK_DIR="java-8-openjdk-amd64"
          ;;
        aarch64)
          OPENJDK_DIR="java-8-openjdk-arm64"
          ;;
        armv7l)
          OPENJDK_DIR="java-8-openjdk-armhf"
          ;;
        *)
          echo "arch $(arch) not supported"
          exit 3
          ;;
      esac

      ln -s "$OPENJDK_DIR" "$OPENJDK_DIR_SYMLINK" || \
        (echo "failed to link $OPENJDK_DIR_SYMLINK -> $OPENJDK_DIR" \
        && exit 4)
...
layout:
  ...
  /usr/bin/java8:
    symlink: $SNAP/usr/lib/jvm/java-8-openjdk-arch-symlink/jre/bin/java
1 Like

@ijohnson I would second making a $SNAPCRAFT_ARCH or similar. I am going to have to do the same thing that @zjoseal did in his snap to make this build on other platforms.

layout:
  /usr/lib/girepository-1.0:
    bind: $SNAP/usr/lib/x86_64-linux-gnu/girepository-1.0
  /usr/lib/gio:
    bind: $SNAP/usr/lib/x86_64-linux-gnu/gio

for girepository and gio, you can do:

layout:
  /usr/lib/$SNAPCRAFT_ARCH_TRIPLET/girepository-1.0:
    bind: $SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/girepository-1.0
  /usr/lib/$SNAPCRAFT_ARCH_TRIPLET/gio:
    bind: $SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/gio

Presumably, @cjp256 mentioned $SNAPCRAFT_ARCH as a potential comparable variable to $SNAPCRAFT_ARCH_TRIPLET that includes just the architecture instead of the full GNU Toolchain triplet.

@lucyllewy Awesome, Thanks!