目录

Go 解决golinkname错误:must refer to declared函数/变量

背景

最近在编写 go 项目时

在 执行 go mod tidy 时报错,如下

golang.org/x/sys/unix
# golang.org/x/sys/unix
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/syscall_darwin.1_13.go:29:3: //go:linkname must refer to declared function or variable
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/zsyscall_darwin_amd64.1_13.go:27:3: //go:linkname must refer to declared function or variable
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/zsyscall_darwin_amd64.1_13.go:40:3: //go:linkname must refer to declared function or variable
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/zsyscall_darwin_amd64.go:28:3: //go:linkname must refer to declared function or variable
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/zsyscall_darwin_amd64.go:43:3: //go:linkname must refer to declared function or variable
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/zsyscall_darwin_amd64.go:59:3: //go:linkname must refer to declared function or variable
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/zsyscall_darwin_amd64.go:75:3: //go:linkname must refer to declared function or variable
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/zsyscall_darwin_amd64.go:90:3: //go:linkname must refer to declared function or variable
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/zsyscall_darwin_amd64.go:105:3: //go:linkname must refer to declared function or variable
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/zsyscall_darwin_amd64.go:121:3: //go:linkname must refer to declared function or variable
../../pkg/mod/golang.org/x/sys@v0.0.0-20200930185726-fdedc70b468f/unix/zsyscall_darwin_amd64.go:121:3: too many errors

关键错误:golinkname must refer to declared function or variable

⚠️:我用的是 mac 笔记本电脑(不过结论证明和电脑没关系)

解决

直接先说解决方法吧…

执行 go get -u 更新这个库即可:

go get -u golang.org/x/sys

更新完成之后重新执行 go mod tidy 就正常了

在官方 issue 和 网络文章的探索之后,发现这是由于有个库golang.org/x/sys 版本过旧导致出现这个错误

原因分析

在分析错误之前,得先明确go:linkname是什么?

go:linkname的核心作用——它是Go编译器的一个特殊指令,用于“将当前包的某个标识符(函数/变量),链接到另一个包中已声明的标识符”,哪怕那个标识符是未导出的(首字母小写)。

举个常见场景:标准库sync包的Pool有个未导出的getSlow函数,我们想在自己的代码里调用它,就可以用go:linkname做链接,相当于“给未导出标识符起一个当前包可见的别名”。

但正因为它绕开了Go的访问权限控制,编译器对其使用有严格校验——这也是“must refer to declared function or variable”错误的根源:编译器校验时发现,你要链接的目标根本不存在,或者链接方式不符合规则。

所以问题很明显, 看报错的是哪个包有问题,就说明这个包太旧了(有些变量和函数不存在),直接进行更新即可

从上文的报错日志可以看出我这里是因为本地的依赖pkg/mod/golang.org/x/sys 报错

因此我执行更新命令:go get -u golang.org/x/sys 便可以完美解决

补充说明:

如果你在业务代码中使用了 go:linkname, 那么千万别忽视go:linkname的“隐性风险”——它绕开了Go的访问控制,使用不当会导致程序兼容性差、易崩溃。这3个注意事项必须牢记:

  1. 必须导入unsafe包:只要使用//go:linkname指令,就必须在代码中导入_ "unsafe"(空白导入,只引入包不使用),否则编译会报“go:linkname used without importing "unsafe"”错误。
  2. 未导出目标可能随时变动:标准库或第三方库的未导出函数/变量,属于“内部实现”,没有兼容性承诺。比如Go 1.21修改了runtime包的内存分配函数,之前用go:linkname链接的函数可能失效,导致程序崩溃。
  3. Go modules环境下包路径要匹配:在Go modules项目中,链接自己项目的内部包时,包路径必须和go.modmodule声明一致。比如module github.com/xxx/proj,则内部包internal/utils的完整路径是github.com/xxx/proj/internal/utils,不能省略模块名。

总结

这似乎不能算是一个 bug,因为这一般由于电脑本地的 mod 缓存问题导致的,也勉强算是一个避坑点吧…

大家平时在使用 go 的过程中还遇到过哪些坑问题?欢迎大家在评论区分享交流!!!

版权声明

未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!

本文原文链接: https://fiveyoboy.com/articles/go-err-1/

备用原文链接: https://blog.fiveyoboy.com/articles/go-err-1/