我正在尝试将
go mod tidy
的行为(以及 go.sum 的结果内容)与 go list -m all
的输出进行比较。
阅读文档,我了解 go.sum 包含在 go.mod 和依赖项的 go.mod 文件中声明的依赖模块的完整列表,go list -m all
显示在执行期间真正加载的模块。
举个例子,一个包含 logrus 和 prometheus 的应用程序如下:
go.mod
module mytest
go 1.14
require (
github.com/prometheus/common v0.4.0
github.com/sirupsen/logrus v1.8.1
)
main.go
package main
import "github.com/sirupsen/logrus"
import "github.com/prometheus/common/version"
func main() {
logrus.Info("Hello World")
logrus.Infof("Prometheus info: %v", version.Info())
}
go mod tidy
之后,go.sum显示了go.mod请求的logrus v1.8.1和prometheus v0.4.0的依赖1.2.0; go list -m all
仅显示 v1.8.1。
去.sum
[...]
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
[...]
Go列表的输出
[...]
github.com/sirupsen/logrus v1.8.1
[...]
应用程序真正使用的模块按
go list -m all
列出,这样正确吗?
潜在的问题是静态代码分析检测到 go.sum 中列出的不安全模块版本,但实际上这些版本不会出现在
go list -m all
中,因此它们不应该被应用程序真正使用,而只能在构建阶段选择合适的最小版本。
一些参考:
https://go.dev/ref/mod#go-mod-tidy
go mod tidy 的作用就好像所有构建标签都已启用,因此它会考虑 特定于平台的源文件和需要自定义构建的文件 标签,即使这些源文件通常不会被构建。
https://go.dev/ref/mod#go-sum-files
go.sum 文件可能包含模块的多个版本的哈希值。 go 命令可能需要从多个版本加载 go.mod 文件 依赖项以执行最小版本选择。戈萨梅 还包含不再需要的模块版本的哈希值 (例如,升级后)。
[...]此外,你的模块的 go.sum 记录了所有的校验和 构建中使用的直接和间接依赖项(因此您的 go.sum 通常会比您的 go.mod 列出更多的模块)。
https://github.com/golang/go/wiki/Modules#version-selection
使用最小版本选择算法来选择版本 构建中使用的所有模块。对于构建中的每个模块, 最小版本选择选择的版本始终是 要求明确列出的语义上最高的版本 主模块或其依赖项之一中的指令。
举个例子,如果你的模块依赖于模块
,它有一个A
,你的模块也依赖于模块require D v1.0.0
有一个B
,那么最小版本选择会选择 要包含在构建中的 D v1.1.1(假设它是列出的最高版本) 需要版本)。 [...] 查看所选模块版本的列表 (包括间接依赖),使用require D v1.1.1
。go list -m all
是的,正确地说应用程序真正“使用”的模块由
go list -m all
列出(根据您提供的链接的文档)。 “使用”表示在构建时选择用于编译应用程序的 go 代码的包。
我们的静态分析工具也遇到了类似的问题,我们必须更改配置以使用
go list -m all
的输出(转储到文件中)而不是 go.sum
。
不,
go list -m all
很可能会列出程序本身使用的模块的大型超集。如果您想知道程序中最终内置了什么,请构建它并运行 go version -m <prog>
。例如,给出以下 test.go
:
package main
import (
"fmt"
"github.com/spf13/viper"
)
func main() {
fmt.Println(viper.New())
}
go list -m all
将显示相当大的模块列表,代表如果您实际使用每个功能并拉入 github.com/spf13/viper
中的每个相应包,将会使用到的所有内容。
另一方面,运行
go build test.go
然后运行 go version -m test
将显示一个小得多的列表,代表 github.com/spf13/viper
的小子集及其实际使用的相应依赖项:
test: go1.22.1
path command-line-arguments
dep github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
dep github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
dep github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
dep github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
dep github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
dep github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
dep github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
dep github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
dep github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
dep github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
dep github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
dep golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
dep golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
dep gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
dep gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
build -buildmode=exe
build -compiler=gc
build CGO_ENABLED=1
build CGO_CFLAGS=
build CGO_CPPFLAGS=
build CGO_CXXFLAGS=
build CGO_LDFLAGS=
build GOARCH=amd64
build GOOS=linux
build GOAMD64=v1