go mod tidy错误信息:”但是go 1.16会选择”

huangapple go评论121阅读模式
英文:

go mod tidy error message: "but go 1.16 would select"

问题

当我运行go mod tidy时,会显示一些包的错误。

> go mod tidy

github.com/myrepo/myproj 导入
	go.k6.io/k6 导入
	go.k6.io/k6/cmd 导入
	github.com/fatih/color 从 github.com/fatih/color@v1.12.0 加载,
	但 go 1.16 将选择 v1.13.0

要升级到 go 1.16 选择的版本:
	go mod tidy -go=1.16 && go mod tidy -go=1.17
如果不需要与 go 1.16 兼容:
	go mod tidy -compat=1.17
其他选项,请参阅:
	https://golang.org/doc/modules/pruning

我已经安装了 go 1.17.9。这个错误的含义是什么,为什么会触发它?

英文:

When I run go mod tidy a few packages show an error

> go mod tidy

github.com/myrepo/myproj imports
	go.k6.io/k6 imports
	go.k6.io/k6/cmd imports
	github.com/fatih/color loaded from github.com/fatih/color@v1.12.0,
	but go 1.16 would select v1.13.0

To upgrade to the versions selected by go 1.16:
	go mod tidy -go=1.16 && go mod tidy -go=1.17
If reproducibility with go 1.16 is not needed:
	go mod tidy -compat=1.17
For other options, see:
	https://golang.org/doc/modules/pruning

I have go 1.17.9 installed. What's the meaning of the error and why is it being triggered?

答案1

得分: 18

这个错误与Go 1.17中引入的模块图修剪有关。

在Go 1.16中,最小版本选择的模块图包括完整的模块图,而在1.17中,该图仅包括直接依赖(有一些例外情况,请参阅上面的链接)。

现在,为了理解触发错误的原因,你可能需要查看Go 1.17发布说明

> 默认情况下,go mod tidy会验证与主模块相关的依赖项的选定版本是否与之前的Go版本(对于指定了go 1.17的模块,为Go 1.16)使用的版本相同[...]。

因此,当你运行go mod tidy时,它会报告Go 1.16“将选择”与Go 1.17修剪后的模块图中的版本不同的一个传递依赖项(github.com/fatih/color)。

这与构建的可重复性相关,因为go.sum包含在go.mod中指定的当前Go版本和上一个版本的校验和。在Go 1.17和Go 1.16的情况下,模块图实际上可能会发生变化,导致go.sum不一致。

错误消息提供了两个修复方法。

  1. go mod tidy -go=1.16 && go mod tidy -go=1.17 — 这将选择依赖项的版本为Go 1.16,然后为Go 1.17。

  2. go mod tidy -compat=1.17 — 这只是删除了Go 1.16的校验和(因此提示“不需要与go 1.16的可重复性”)。

在升级到Go 1.18之后,这个错误应该不会再出现,因为模块图将与Go 1.17中的加载方式相同。

英文:

This error is related to module graph pruning introduced in Go 1.17.

With Go 1.16, the module graph for Minimal Version Selection used to include the full module graph, whereas with 1.17 the graph includes only up to transitive dependencies (with some exceptions, see the link above).

Now to understand what triggers the error, you might want to look at the Go 1.17 release notes:

> By default, go mod tidy verifies that the selected versions of dependencies relevant to the main module are the same versions that would be used by the prior Go release (Go 1.16 for a module that specifies go 1.17) [...]

So when you run go mod tidy, it reports that Go 1.16 "would select" a version of a transitive dependency (github.com/fatih/color) that is different from the one that the pruned graph of Go 1.17 would.

This is relevant for build reproducibility, because go.sum contains the checksums for the current Go version specified in go.mod and the previous one. In case of Go 1.17 and Go 1.16 where the module graph effectively can change, go.sum would be inconsistent.

The error message suggests two fixes.

  1. go mod tidy -go=1.16 && go mod tidy -go=1.17 — this selects the dependency versions as Go 1.16 and then as Go 1.17

  2. go mod tidy -compat=1.17 — this simply removes the Go 1.16 checksums (hence the tip "reproducibility with go 1.16 is not needed").

The error should not present itself anymore after you upgrade to Go 1.18, because then the module graph will be loaded the same as in Go 1.17.

答案2

得分: 7

简单解释

错误 but go 1.16 would select 意味着在使用 Go 1.16(或更低版本)编译软件(编译二进制文件)后,您的软件在行为上存在更深层次的问题,与使用 Go 1.17(或更高版本)编译后的行为不同。

是什么导致了这个问题?:这可能完全超出您的控制范围,例如您的一个依赖项的无意更改可能会引入此问题作为副作用。(就像最近发生的 golang.org/x/oauth2 等问题,导致全球范围内的许多构建失败。)

我可以简单地避免运行 go mod tidy 吗? 是的,但这对于您实际的问题没有任何帮助。

那么对我来说有什么实际影响? 现在,您在 Go 1.16 和 1.17 之间无法实现构建的可重复性。如果您使用 Go 1.16 进行构建或测试,您的程序的行为可能与 Go 1.17+ 的行为略有不同。您的程序的编译使用了不同版本的依赖项。虽然差异很小,但是确实存在差异,而且比底层算法的细节更重要。

强制与 Go 1.17(或更高版本)兼容的构建

  1. 文档/通知所有人不要使用 Go 1.16 或更低版本编译您的代码。

  2. 确保您的持续集成不使用 Go 1.16 或更低版本。

  3. 在所有脚本、Makefile、流水线等中,将命令 go mod tidy 更改为:

go mod tidy -compat=1.17
这是一次迁移吗?我从未使用过 Go 1.16!#####

您可能会认为在您的 go.mod 文件中声明一个版本 go 1.17 强制使用该版本或更高版本的 Go。即使在这种情况下,一些 Go 1.16 的工具也会失败并显示 go.mod file indicates go 1.17, but maximum supported version is 1.16,强制执行这种直觉。有道理,对吗?不对。

残酷的现实是,某些代码库(也可能包括您的代码库)可以使用 Go 1.16 或 Go 1.15 进行编译,只要编译的模块不包含仅在后续 Go 版本中添加的功能!核心团队不希望为这种人为的构建过程悄悄引入问题。这就是为什么需要明确决定是否保留或放弃这种向后兼容性。

另一种选择:使用 Go 1.16 的依赖算法

go mod tidy -go=1.16 && go mod tidy -go=1.17

将最后一个数字提升到您的最大版本,例如如果您使用的是 1.18:

go mod tidy -go=1.16 && go mod tidy -go=1.18

后面的 -go=1.17(或 -go=1.18)标志表示您希望将语言特性限制在 1.17(或 1.18)。

前面的 -go=1.16 只是临时的,并会立即被覆盖。那么为什么还需要它呢?嗯,它需要用于副作用:它在 go.mod 中留下了一个标记。1.17(或 1.18)看到了这个标记,因此它不会使用新的依赖修剪算法。相反,它选择与 1.16 相同的版本,并将它们持久化到 go.mod 中。

英文:

Simple explanation

The error but go 1.16 would select means there is now a deeper problem with how your compiled software (compiled binary) behaves after being compiled with Go 1.16 (or below) instead of Go 1.17 (or above).

What introduced this problem?: this may be entirely out of your control, for example an innocent change in one of your dependencies can introduce it as a side effect. (As recently seen with golang.org/x/oauth2 and similar which has broken a lot of builds around the world.)

Can I simply avoid running go mod tidy? Yes, but this does nothing about your actual problem.

What is the practical impact then for me? It's that as of now you have no build reproducibility between Go 1.16 and 1.17. If you use Go 1.16 to build or test, the behavior of your program may be subtly different compared to that of Go 1.17+. The compilation of your program takes different versions of the dependencies. Very slightly different, but different, and it's more important than the intimate details of the underlying algorithm.

Force build compatibility with Go 1.17 only (or above)

  1. Document/communicate that nobody is supposed to compile your code with Go 1.16 or below.

  2. Make sure your continuous integration is not using Go 1.16 or below.

  3. In all your scripts, Makefiles, pipelines, etc., change command go mod tidy to:

go mod tidy -compat=1.17
Is this a migration? I have never used Go 1.16!

You might think that declaring a version go 1.17 in your go.mod enforces usage of that Go version or higher. Even some Go 1.16 tools in that case do fail with go.mod file indicates go 1.17, but maximum supported version is 1.16, enforcing that intuition. Makes sense, right? Nope.

The brutish reality is that some codebases of that kind (and maybe yours too) can be compiled with Go 1.16 or Go 1.15 as long as the compiled module doesn't include features only added in later Go versions! The core team doesn't want to silently introduce problems for such contrived build processes. This is why you are faced with the decision to explicitly keep or explicitly drop that kind of backward compatibility.

Alternative: use the Go 1.16 dependency algorithm

go mod tidy -go=1.16 && go mod tidy -go=1.17

bumping the last number to your max version, so if you are on 1.18:

go mod tidy -go=1.16 && go mod tidy -go=1.18

The latter -go=1.17 (or -go=1.18) flag declares that you want to cap the language features at 1.17 (or 1.18).

The former -go=1.16 is only transient and immediately overwritten. Why is it needed then? Well, it is needed for a side effect: it leaves a mark in go.mod. The 1.17 (or 1.18) sees the mark and because of that it doesn't use the novel algorithm of dependency pruning. Instead it chooses the same versions as 1.16 would and persists them into the go.mod.

huangapple
  • 本文由 发表于 2022年4月23日 02:26:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/71973152.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定