Search code examples
gocompilation

What version of Go is used to compile dependencies?


Whenever compiling a Go program, is same version of Go used to compile the main code as well dependency code ?


Solution

  • This is an interesting question, and has a somewhat nuanced answer, that has changed over the years.

    For older versions of Go, the answer was simple: Every dependency was compiled with whichever version of Go you're running locally. If you were running Go 1.9, and you had dependencies built for Go 1.10, the compiler would be none the wiser, and attempt to compile the Go 1.10 code using Go 1.9. So long as no new features were used in that dependency, it would all work fine. Likewise, if you had a dependency written for Go 1.8, it would also be compiled using Go 1.9.

    However, for modern versions of Go, and any projects (or dependencies) using a go.mod file, behavior is different. From the Go Modules Reference we learn that:

    • For packages within the module, the compiler rejects use of language features introduced after the version specified by the go directive. For example, if a module has the directive go 1.12, its packages may not use numeric literals like 1_000_000, which were introduced in Go 1.13.

    What this means is that your dependencies will only use features available in their declared versions of Go. They're still built using the modern Go runtime, however. So any performance enhancements, security improvements, etc, found in your version of Go, which is newer than the dependency's declared version, are still used.

    Further, the next line of the same document says:

    • If an older Go version builds one of the module’s packages and encounters a compile error, the error notes that the module was written for a newer Go version. For example, suppose a module has go 1.13 and a package uses the numeric literal 1_000_000. If that package is built with Go 1.12, the compiler notes that the code is written for Go 1.13.

    So this means that if you attempt to build a program using Go 1.19, and one of the dependencies declares version 1.20 and there is a compilation error, the compiler output will inform you of the potential compatibility problem. If there are no compilation errors, you'll probably never notice the difference (because presumably the dependency which declared 1.20 isn't actually using any new 1.20 compiler features).


    Update for Go 1.21

    As of Go 1.21, the Go version specified in go.mod or go.work is considered a strict minimum requirement. It will also, by default, automatically download a newer toolchain, if your current toolchain is older than the one specified as required in go.mod. Read more in the Go 1.21 release notes.


    Update for Go 1.22

    As of Go 1.22, this will has a much more noticeable impact than before, mostly relating to the less error-prone loop variable scoping change. This changed the way loop variables are handled in a non-backward compatible way. Any module that declares go 1.21 or earlier will use the old looping semantics, and any declaring go 1.22 or newer will use the new looping semantics. This is the first noticable time that Go has broken its backward compatibility promise, though arguably for good reason (since this loop variable thing trips up virtually everyone).