2023-06-23
Go 1.21 will (probably) download newer toolchains on demand by default
For some time, Go modules have supported
specifying the minimum version of Go required by the module in
go.mod, through the go
directive. Once you can
have modules that specify a minimum Go version, you have a design
question of what should happen when an older version of Go tries
to do something with a module that says it requires a newer version
of Go. Up through Go 1.20 (more or less), Go's answer was to go
ahead and try anyway. Starting in Go 1.21, Go will refuse to be
this optimistic, and thus Go guarantees from 1.21 onward that a
module will always be processed with at least its minimum version
of Go. If this isn't possible, Go will stop with a clear error about
the situation.
(This behavior is backported to 1.19.11 and 1.20.6, in that starting from each of those Go will refuse to touch a module or workspace that specifies Go 1.21 or later.)
By itself this might be frustrating and awkward, so Go offers two
ways out. First, Go can search through your $PATH (or non-Unix
equivalent) to try to find the necessary minimum toolchain version,
and then automatically switch over to executing that version.
Second, if you don't have the necessary toolchain on your $PATH
already, Go can download an official release for you (or what should
be an official release) and then switch over to it. As of the current
Go 1.21 release candidate, the 'go
' command will do both of these
by default, first searching your $PATH and then trying to reach out
to the Internet to download a pre-built toolchain (if one exists).
How this works and is controlled is covered in the pre-release
documentation for Go Toolchains
and the Go 1.21 draft release notes.
(How Go decides on the (potential) authenticity of this downloaded toolchain is beyond the scope of this entry.)
Not everyone is going to be happy with the idea of the 'go
' command
downloading and running binaries from the Internet. If this is the
case for you, you need to set GOTOOLCHAIN
to either 'path
', if
you're happy to search $PATH for the right toolchain, or 'local
',
if you want to turn off this behavior entirely and have 'go
' just
fail. Unfortunately, Go before Go 1.21rc1 can't set this through
'go env -w
', so if you want to set this globally you'll need to
manually create or edit your Go configuration file (you can find
its location with 'go env GOENV
') so that it contains:
GOTOOLCHAIN=path
(Or 'local
', if you prefer.)
Or you can set a '$GOTOOLCHAIN
' environment variable. In various
automated build and testing environments, you may have no choice
but to inject this as an environment variable.
(It's also possible to change the default behavior of a Go installation, and I wouldn't be surprised if some Linux distributions did.)
Right now this behavior of downloading newer toolchains is either difficult or impossible to trigger, since there are no newer toolchains than Go 1.21rc1. Even after later versions are released, it may be hard to trigger and rare; realistically, I suspect we're not going to see much of this before Go 1.22 comes out, although we'll have to see.
My personal opinion is that the $PATH searching is perfectly sensible as default behavior, but downloading newer toolchain binaries over the Internet is not. I believe that there are a lot of situations where people don't want this, and the current default will force everyone to start injecting settings changes into all sorts of places to turn it off. It's possible that the Go developers will change their minds about the default before the release of Go 1.21, and I hope they do. I understand the convenience of their current default, but there's a balance between convenience and other factors.
(This elaborates on a Fediverse post that was triggered by the Go 1.21 draft release notes becoming available and providing clear documentation for this new feature.)