Does setting environment variables work with override-build?

Hi!
I have found examples on a mailing list of using prepare to setup environmental variables that the build is looking for for settings, but I have not found any examples of this for override-build.

I am trying to set a environment variable to set the path to the documentation, which is a pdf file that a button should open. I have tried this:

    override-build: |
      export QXMLEDIT_INST_DOC_DIR=${SNAP}/meta/gui/
      snapcraftctl build

This does not seem to be setting the environment variable for the snapcraftctl build. Any help on how to accomplish this would be appreciated.

Frederick

1 Like

I have this problem as well, customize PATH variable doesn’t seem to be effective.

Possible related bug: Bug #1600035 “no way to differentiate between build-time and run…” : Bugs : Snapcraft

I filed a new bug to snapcraft regarding this particular issue: Bug #1778174 “Environment variable customization should be possi…” : Bugs : Snapcraft

Sorry @frederickjh, this post wasn’t in the snapcraft category so I never saw it (I’ve fixed that now).

I’m afraid snapcraftctl doesn’t quite work this way, nor was it designed to. When you run snapcraftctl build, snapcraftctl isn’t the utility actually building, it’s still the parent snapcraft CLI, which is running under its own environment. When you call snapcraftctl build, you’re literally saying “please run the build exactly as you would have otherwise”. If you need to customize the build process to this extend, you’ll need to completely override it in the scriptlet, or implement a plugin that exports the proper environment for the build process.

Beyond that, note that the environment variable $SNAP has no meaning in snapcraft-- it only means something when the resulting snap is installed. Which means the environment variable you’re setting there isn’t valid anyway, so I’m not quite clear what you’re trying to do.

1 Like

Is the build-environment key still on the roadmap? I would really like to have PATH-override without replacing the entire build process with scriptlets (or extending a Python plugin).

@Lin-Buo-Ren would you mind explaining your use-case, please? We strive to ensure the snapcraft CLI is predictable and reliable even when building on a clean system, and such things tend to not work in that situation. There may be a better way to accomplish what you desire.

I use it to replace some default commands that don’t work, or at least not working easily.

parts:
  # This pseudo part setups version 6 of GCC, which is not available
  # in Ubuntu 16.04 software source.
  # To use it simply add a dependency to this part and prepend
  # "$SNAPCRAFT_STAGE"/bin to the command search PATHs
  gcc-6:
    plugin: nil
    # Poedit sources will be used when `source` is ommitted, avoid this
    # behavior
    override-pull: 'true'
    override-build: |
      sudo apt --yes install software-properties-common

      # Install newer GCC from Toolchain test builds PPA
      sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
      sudo apt update
      sudo apt --yes install cpp-6 gcc-6 g++-6

      # Make fake executable search path for build systems that don't
      # honor CC and CXX environmental variables
      mkdir \
        --parents \
        "${SNAPCRAFT_PART_INSTALL}"/bin
      # DISABLED: Replaced by ccache-gcc-6
      #ln \
        #--force \
        #--symbolic \
        #"$(which gcc-6)" \
        #"${SNAPCRAFT_PART_INSTALL}"/bin/gcc
      #ln \
        #--force \
        #--symbolic \
        #"$(which g++-6)" \
        #"${SNAPCRAFT_PART_INSTALL}"/bin/g++
      ln \
        --force \
        --symbolic \
        "$(which cpp-6)" \
        "${SNAPCRAFT_PART_INSTALL}"/bin/cpp

    filesets:
      executables:
        - bin/*
    stage:
      - $executables
    override-prime: 'true'

  # This pseudo part setups Compiler cache(ccache) to the stage dir.
  #
  # To use it simply add a dependency to this part and prepend
  # "$SNAPCRAFT_STAGE"/bin to the command search PATHs
  ccache:
    after:
      - gcc-6
    override-pull: 'true'
    build-packages:
      - ccache
    plugin: nil
    override-build: |
      mkdir \
        --parents \
        "${SNAPCRAFT_PART_INSTALL}"/bin
      ln \
        --force \
        --symbolic \
        "$(which ccache)" \
        "${SNAPCRAFT_PART_INSTALL}"/bin/gcc-6
      ln \
        --force \
        --symbolic \
        "$(which ccache)" \
        "${SNAPCRAFT_PART_INSTALL}"/bin/g++-6
      ln \
        --force \
        --symbolic \
        ./gcc-6 \
        "${SNAPCRAFT_PART_INSTALL}"/bin/gcc
      ln \
        --force \
        --symbolic \
        ./g++-6 \
        "${SNAPCRAFT_PART_INSTALL}"/bin/g++
    filesets:
      executables:
        - bin/*
    stage:
      - $executables
    override-prime: 'true'

@Lin-Buo-Ren that’s quite a ways beyond the intended purpose of scriptlets. If you want to enable ccache on your host, go for it, snapcraft will use it. If you want to enable it in CI, go for it. What you’re doing here is not really supported. However, I will point out that you get get bin in the staging area in the PATH another way: make sure parts that need it have after: [ccache] specified. For example, run snapcraft pull with your parts like this:

# ...

parts:
  part1:
    plugin: nil
    override-build: |
      install -d $SNAPCRAFT_PART_INSTALL/bin
      echo "#!/bin/sh\necho 'hello there'" > $SNAPCRAFT_PART_INSTALL/bin/this-is-a-test
      chmod a+x $SNAPCRAFT_PART_INSTALL/bin/this-is-a-test

  part2:
    plugin: nil
    override-pull: this-is-a-test
    after: [part1]

You’ll see that part2 can use the executable placed by part1:

$ snapcraft pull
Preparing to pull part1 
Pulling part1 
'part2' has prerequisites that need to be staged: part1
Preparing to build part1 
Building part1 
Staging part1 
Preparing to pull part2 
Pulling part2 
hello there
1 Like

@kyrofa I have a case where I would like to set CC and OMPI_CC environment variables in the build environment, because I need to compile with the gcc-6 binary instead of gcc and OpenMPI. Any idea how to accomplish that in the yaml file?

Thanks for the reply. I was a way. The maintainer of the program I am trying to snap, QXmlEdit, has since change the make configuration to help me with this issue but it is still not working.

QXmlEdit has a User Manual button that should open a pdf manual. This does not work. In the terminal it spews out: “user-open error: no such file or directory” because it cannot find the manual. The default folder path QXmlEdit looks for the manual according to the maintainer is in /opt/qxmledit/.

I am trying to figure out what to set the path to in the make configuration so that it is found by QXmlEdit.

The path to the folder holding the PDF documentation file when QXmlEdit is running appears to be /snap/qxmledit/29/opt/qxmledit/. The question is what path do I need to give as a qmake option so that it can be found.

You can see the discussion between myself and the QXmlEdit developer on this github issue.

Thanks in advance for any pointers you can give me to figure this out!
Frederick

@kyrofa See this comment in that issue and the next about the qmake config option that the developer added.

You could do away with /snap/qxmledit/current/opt/qxmledit, maybe it could be a relative path, too? If not done right, it would be relative to $PWD so not great.

@Saviq I just tried /snap/qxmledit/current/opt/qxmledit as the path but this also is not working. QXmlEdit is not finding the PDF document. Even though evince /snap/qxmledit/current/opt/qxmledit/QXmlEdit_manual.pdf opens the PDF.

So maybe the problem isn’t the path but rather the way it tries to open it? The only supported way for snaps to open files in other apps is through calling xdg-open (which QDesktopServices.openUrl uses by default, so that should work).

What’s the error you’re seeing when trying to open that file? Can you see any relevant DENIED messages in the kernel log?

The message when run in the terminal is:
user-open error: no such file or directory

I ran tail -f /var/log/kern.log while clicking on the “User Manual” button but no message were added.

I am checking with the developer on how QXmlEdit is opening the PDF.

Here is the source code that is trying to open the PDF manual.

void ApplicationData::showUserManual()
{
    QString resourceHelp = getDocsDir() + "/" + HELP_FILE ;
    QDesktopServices::openUrl(QUrl::fromLocalFile(resourceHelp));
}

This appears to be the method that you thought was acceptable @Saviq, correct?