I always use Debian stable on my work laptop. I also tend to use the provided version for most programming languages. Sometimes I need multiple versions for work or research related reasons. This isn't a problem with languages such as Haskell or Rust, but it tends to be a pain with others, Golang being the cause of these notes.
Making the default version more «default».
At the time of this writing, Debian 10 («buster») provides Golang 1.11. I need it to build Debian packages for a few applications, so it can be installed via APT
# apt install golang-1.11-go golang-1.11-doc golang-1.11-src
The first thing that will surprise you is that there's no «default»
version of /usr/bin/go
to use right away. Debian Golang packages install
their stuff under /usr/lib/go-<version>/
and you're left to your own
devices to adjust GOROOT
correctly for your environment, as the Golang
folks want you to. Later Golang revisions allow you to have multiple
binaries that hold the version as part of their name -- I cannot sanction
such buffoonery.
I want to have /usr/bin/go
pointing to my «default» version, thus keeping
things civil. Moreover, I want /usr/bin/gofmt
pointing to the matching one,
to avoid confusions and have my vim
setup work Just Right®. Since it's
possible to have multiple versions installed, I want to be able to change
from one version to the other.
Here's where Debian's update-alternatives(1)
shines.
# update-alternatives --install /usr/bin/go go /usr/lib/go-1.11/bin/go 50 \
--slave /usr/bin/gofmt gofmt /usr/lib/go-1.11/bin/gofmt
# ls -l /usr/bin/go
lrwxrwxrwx 1 root root 20 Sep 10 17:04 /usr/bin/go -> /etc/alternatives/go
# ls -l /etc/alternatives/go
lrwxrwxrwx 1 root root 23 Sep 10 17:05 /etc/alternatives/go -> /usr/lib/go-1.11/bin/go
# go version
go version go1.11.6 linux/amd64
The above command creates a new alternative group named go
with master
location /usr/bin/go
and priority 50
. The master location is set as a
symlink to /usr/lib/go-1.11/bin/go
. Finally, it sets a dependent
alternative /usr/bin/gofmt
to the matching /usr/lib/go-1.11/bin/gofmt
.
Alternatives are handled by having symlinks into /etc/alternatives
,
holding symlinks to the actual selection.
Now there's a default /usr/bin/go
I can use, with matching /usr/bin/gofmt
.
Installing additional Golang versions
Golang has one of the worst dependency management systems there are,
and its type system's shortcomings have forced third-party libraries
to jump through hoops to accommodate. One particularly nasty issue
is handling the SQL NULL
representation over a type system lacking
polymorphism. Long story short, to make the latest SQL library work,
one needs to have Golang 1.14.
Fortunately, Debian Backports provides Golang 1.14. After adding the the relevant APT source
# apt install golang-1.14-go golang-1.14-doc golang-1.14-src
Now, this is the version I want to have as default, therefore
# update-alternatives --install /usr/bin/go go /usr/lib/go-1.14/bin/go 100 \
--slave /usr/bin/gofmt gofmt /usr/lib/go-1.14/bin/gofmt
# ls -l /usr/bin/go
lrwxrwxrwx 1 root root 20 Sep 10 17:08 /usr/bin/go -> /etc/alternatives/go
# ls -l /etc/alternatives/go
lrwxrwxrwx 1 root root 23 Sep 10 17:08 /etc/alternatives/go -> /usr/lib/go-1.14/bin/go
# go version
go version go1.14 linux/amd64
The above command extends the existing go
alternative group, with
the new master location at /usr/lib/go-1.14/bin/go
with priority 100
.
It sets the matching dependent alternative /usr/bin/gofmt
to
/usr/lib/go-1.14/bin/gofmt
.
Now, we can check that there are indeed two alternatives
# update-alternatives --display go
go - auto mode
link best version is /usr/lib/go-1.14/bin/go
link currently points to /usr/lib/go-1.14/bin/go
link go is /usr/bin/go
slave gofmt is /usr/bin/gofmt
/usr/lib/go-1.11/bin/go - priority 50
slave gofmt: /usr/lib/go-1.11/bin/gofmt
/usr/lib/go-1.14/bin/go - priority 100
slave gofmt: /usr/lib/go-1.14/bin/gofmt
The highest priority set becomes the default for the system, in this case Golang 1.14 as I need.
Switching versions
To change the system-wide default, working as root
# update-alternatives --config go
There are 2 choices for the alternative go (providing /usr/bin/go).
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/lib/go-1.14/bin/go 100 auto mode
1 /usr/lib/go-1.11/bin/go 50 manual mode
2 /usr/lib/go-1.14/bin/go 100 manual mode
Press <enter> to keep the current choice[*], or type selection number: 1
update-alternatives: using /usr/lib/go-1.11/bin/go to provide /usr/bin/go (go) in manual mode
# go version
go version go1.11.6 linux/amd64
You can also use the --set
command line option to achieve
the same results.
What's missing...
At the time of this writing, Debian's Golang packages do not
provide automatic alternative management on installation or removal.
If you need additional versions, or remove ones you don't need,
remember to run update-alternatives
to add or remove them.
Note that update-alternatives
sets the global default alternative
only. If a user needs to work with a different version, they will
need to set up GOROOT
in their environment accordingly. At least
they can get the right value from update-alternatives --display go
...