Qubes has recently published a release canditate for version 4.0. I’m upgrading my system, and taking some notes as I go…

Users of Qubes know that template VMs tend to lag behind the latest release of an OS. As I write, for example, a Qubes template is based on Fedora 26, while Fedora 27 was released almost 3 months ago. I mention this not to fault the Qubes team, who do great work. Rather I’m setting the stage that the template based on Fedora 26 may not have the latest and greatest dependencies required by some software projects.

Prepare

I cloned the fedora-26 template to a new one called f26-devel. In f26-devel I install software development tools and dependencies. Most of these I can install via dnf. But occasionally the version available of the dependency is not recent enough and I want to build from source.

I created an appvm called build-f26 where those dependencies will be compiled. This appvm is based on the f26-devel template.

Build

  1. Download and build the dependency in the build-f26 appvm.

  2. Use qvm-copy-to-vm to send the built package to f26-devel.

  3. On f26-devel, install it.

That’s all. Any appvm based on f26-devel will have that version of the dependency available.

Examples

Boost

Projects often need the latest version of Boost. I have more than on appvm that needs Boost version 1.66 right now. I took the following steps to build it only once and have it available in multiple VMs.

In build-f26

wget https://dl.bintray.com/boostorg/release/1.66.0/source/boost_1_66_0.tar.gz
tar xvzf boost_1_66_0.tar.gz
./bootstrap.sh --prefix=/opt/boost_1_66_0
./b2
sudo ./b2 install

Note that I’ve chosen a version-specific directory under /opt/ to install into. I might need different versions for different projects.

The last step in build-f26 is to move the built package into the template, f26-devel

qvm-copy-to-vm f26-devel /opt/boost_1_66_0

…then on f26-devel, move the package to the install directory…

sudo mv ~/QubesIncoming/build-f26/boost_1_66_0 /opt/

Great, Boost 1.66.0 is installed on my devel template. But, it is a non-standard location. So I add this snippet to my .bashrc (on each of my devel appvms)…

# boost
if [[ $- == *i* ]] && [ -d /opt/boost_1_66_0 ]; then
    export BOOST_ROOT=/opt/boost_1_66_0
    export CPLUS_INCLUDE_PATH=/opt/boost_1_66_0/include:$CPLUS_INCLUDE_PATH
    export LIBRARY_PATH=/opt/boost_1_66_0/lib:$LIBRARY_PATH
fi

Go (golang)

Building Go from source not only gets you the latest version. It also gets some libraries that Fedora’s build doesn’t include for license reasons.

Start on f26-build. Install an older version of go, which is needed to bootstrap the latest version.

sudo dnf install golang

Installing this version of golang on the appvm will not survive a reboot (I’m installing on the appvm, not the template), but that’s okay…we need this only long enough to bootstrap the new version.

Still on f26-build, compile Go from source

git clone https://go.googlesource.com/go
cd go
git checkout go1.10.1
cd src
./clean.bash
GOROOT_BOOTSTRAP=/usr/lib/golang/ GOROOT_FINAL=/opt/go1.10.x ./all.bash

Note that I’ve chosen a version-specific directory under /opt/ to install into. I might need different versions for different projects.

The Go build script has not actually moved anything into /opt/go1.10.x. So the last step is to move the files, omitting the git repository and unneeded directories, to make the installation smaller.

# Exit go/src directory
cd ../..

# Sync files to /opt/..., excluding unnecessary items.
sudo rsync --exclude .git --exclude /test --exclude go-build -r go/ /opt/go1.10.x

Last step on build-f26 is to copy the installed package to the f26-devel template.

# Select "f26-devel" when `qvm-copy` presents a dialog box.
qvm-copy /opt/go1.10.x

On template f26-devel, move the package to the right place.

# Use `cp`, not `mv` so root owns in the files
sudo cp -r ~/QubesIncoming/build-f26/go1.10.x /opt/
# Clean up QubesIncoming
rm -r ~/QubesIncoming/build-f26/go1.10.x

Great, Go 1.10 is installed on my devel template. But, it is a non-standard location. So I add this snippet to my .bashrc (on each of my devel appvms)…

# golang
# This section should follow other sections that build $PATH
if [[ $- == *i* ]] && [ -d /opt/go1.10.x ]; then
    export NOGOPATH=$PATH
    export GOPATH=$HOME/go # $HOME/go is now the default $GOPATH
    export GOROOT=/opt/go1.10.x # $GOROOT not needed when compiled from source.
    export PATH=$GOROOT/bin:$PATH:$GOPATH/bin

    # Use `gopath /path/to/my/project` to switch between multiple projects.
    gopath(){
	GOPATH=`readlink -f $1`
	export PATH=$GOROOT/bin:$NOGOPATH:$GOPATH/bin:$HOME/go/bin
	export GOPATH=$GOPATH:$HOME/go
    }
fi

Fin

That’s all, folks!