英文:
What version of Go is used to compile dependencies?
问题
每当编译一个Go程序时,编译主代码和依赖代码时使用的Go版本是否相同?
英文:
Whenever compiling a Go program, is same version of Go used to compile the main code as well dependency code ?
答案1
得分: 3
是的,依赖项是使用与您的代码相同的编译器进行编译的,因此它们是相同的版本。
Go模块可以在其go.mod
文件中声明一个最低版本指令,例如:
module example.com/mymodule
go 1.14
这会以两种方式影响编译器行为:
如果依赖项go.mod
中指定的版本比编译器的版本更新,它将尝试进行编译,但如果遇到错误,则会输出一条消息来警告用户该模块是针对更新版本的Go编写的。
如果依赖项go.mod
中指定的版本比编译器的版本旧,那些在指定版本之后引入的语言特性将被拒绝。
英文:
Yes, the dependencies are compiled with the same compiler as is used for your code, and therefore it is the same version.
Go Modules may declare a minimum version directive in their go.mod
like so:
module example.com/mymodule
go 1.14
This influences compiler behaviour in two ways:
If the version specified in the dependencies go.mod
is newer than the compiler's version, it will attempt to compile, but if an error is encountered then a message will be output to warn the user that the module has been written with a newer version of Go in mind.
If the version specified in the dependencies go.mod
is older than the compiler's version, language features introduced after the specified version will be rejected.
答案2
得分: 2
这是一个有趣的问题,答案有些微妙。
对于旧版本的Go来说,答案很简单:每个依赖都是使用你本地运行的Go版本进行编译的。如果你正在运行Go 1.9,并且你有为Go 1.10构建的依赖项,编译器将不会察觉到,并尝试使用Go 1.9编译Go 1.10的代码。只要该依赖项中没有使用新功能,一切都会正常工作。同样,如果你有一个为Go 1.8编写的依赖项,它也将使用Go 1.9进行编译。
然而,对于现代版本的Go以及使用go.mod
文件的任何项目(或依赖项),行为是不同的。从Go Modules参考文档中我们了解到:
- 对于模块内的包,编译器会拒绝使用go指令指定版本之后引入的语言特性。例如,如果一个模块有指令
go 1.12
,它的包就不能使用像1_000_000这样的数字字面量,因为这是在Go 1.13中引入的。
这意味着你的依赖项只会使用其声明版本的Go中可用的功能。然而,它们仍然是使用现代的Go运行时构建的。因此,你所使用的Go版本中的任何性能增强、安全改进等都会被使用。
此外,同一文档的下一行说:
- 如果旧版本的Go构建了模块的一个包并遇到编译错误,错误会指出该模块是为较新的Go版本编写的。例如,假设一个模块有
go 1.13
,一个包使用了数字字面量1_000_000
。如果该包使用Go 1.12构建,编译器会指出该代码是为Go 1.13编写的。
这意味着如果你尝试使用Go 1.19构建程序,并且其中一个依赖项声明了版本1.20,并且存在编译错误,编译器的输出将提醒你可能存在的兼容性问题。如果没有编译错误,你可能永远不会注意到差异(因为假设声明了1.20的依赖项实际上并没有使用任何新的1.20编译器功能)。
这将比以前更加明显,可能在Go 1.22中,假设更少出错的循环变量作用域的提案被接受并及时实施。由于这个提案将以一种不向后兼容的方式改变循环变量的处理方式。假设这个提案进入Go 1.22,这意味着任何声明为go 1.21
或更早版本的模块将使用旧的循环语义,而任何声明为go 1.22
或更新版本的模块将使用新的循环语义。这将是Go第一次明显违背其向后兼容的承诺,尽管可以说有充分的理由(因为这个循环变量的问题几乎困扰着每个人)。
英文:
This is an interesting question, and has a somewhat nuanced answer.
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).
<hr>
This will have a much more noticeable impact than before, probably in Go 1.22, assuming the less error-prone loop variable scoping proposal is accepted and implemented in time. As this proposal will change the way loop variables are handled in a non-backward compatible way. Assuming this does make it into Go 1.22, this means that 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 will be 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).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论