2

I'd like to make sure people aren't using Go 1.12 or older when compiling my application; mainly because this:

return fmt.Errorf("foo: %w", err) 

Will compile fine in Go 1.12, but won't actually behave as expected as it requires runtime changes in Go 1.13 or newer to pick up on that %w.

And even there are changes which introduce a compile error, such as binary literals or _ in numeric literals, a nicer "you need Go 1.13 or newer"-message would be better and less confusing, as not everyone may be familiar with Go and know what to do with a syntax error (it seems some people still use rather old Go versions).

I added go 1.13 to my go.mod file, but I can still compile it fine with older versions (and adding go 1.16 and compiling with Go 1.15 also works).

Is there any way to require a minimum Go version when compiling an app to prevent runtime errors and display a friendly error message?

2 Answers 2

6

The easiest way I could figure out is adding a new file with +build !go1.13; since Go version build tags are added for all newer versions (Go 1.14 has go1.14, go1.13, go1.12, etc.) it will compile only for versions older than Go 1.13, and will be ignored for any newer versions:

// +build !go1.13 package main func init() { "You need Go 1.13 or newer to compile this program" } 

This introduces a deliberate compile error, which results in a reasonably nice error message:

$ go install ./cmd/app # zgo.at/app/cmd/app cmd/app/old.go:8:2: "You need Go 1.13 or newer to compile this program" evaluated but not used 
Sign up to request clarification or add additional context in comments.

3 Comments

TIL; nice hack. You can also mention the minimum version in go.mod, but that won't prevent you from compiling with an older version.
Yeah, that doesn't actually do all that much @TehSphinX, although it does disables incompatible features in newer Go versions IIRC so you can't "accidentally" use them. But as far as I know, that's all it really does. I forgot to mention this, but I'll update the question to point out this doesn't work as one might expect.
Yes, it will just try to compile with the old version anyway and only output an error if compilation fails. Which it doesn't with your fmt example.
1

TL;DR: If you use go version 1.21 or older, the version your go.mod specifies will be used for compilation.

From https://go.dev/ref/mod#go-mod-file-go:

The go directive sets the minimum version of Go required to use this module. Before Go 1.21, the directive was advisory only; now it is a mandatory requirement: Go toolchains refuse to use modules declaring newer Go versions.

https://go.dev/doc/toolchain

Starting in Go 1.21, the Go distribution consists of a go command and a bundled Go toolchain, which is the standard library as well as the compiler, assembler, and other tools. The go command can use its bundled Go toolchain as well as other versions that it finds in the local PATH or downloads as needed.

In the standard configuration, the go command uses its own bundled toolchain when that toolchain is at least as new as the go or toolchain lines in the main module or workspace. For example, when using the go command bundled with Go 1.21.3 in a main module that says go 1.21.0, the go command uses Go 1.21.3. When the go or toolchain line is newer than the bundled toolchain, the go command runs the newer toolchain instead

See also: https://go.dev/blog/toolchain

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.