Go build:“找不到包”(即使设置了 GOPATH)
Posted
技术标签:
【中文标题】Go build:“找不到包”(即使设置了 GOPATH)【英文标题】:Go build: "Cannot find package" (even though GOPATH is set) 【发布时间】:2012-10-24 05:19:16 【问题描述】:即使我正确设置了GOPATH
,我仍然无法通过“go build”或“go run”来找到我自己的包。我做错了什么?
$ echo $GOROOT
/usr/local/go
$ echo $GOPATH
/home/mitchell/go
$ cat ~/main.go
package main
import "foobar"
func main()
$ cat /home/mitchell/go/src/foobar.go
package foobar
$ go build main.go
main.go:3:8: import "foobar": cannot find package
【问题讨论】:
我去github.com/adonovan/gopl.io/tree/master/ch1/helloworld时遇到了同样的问题,原因应该是它没有名为helloworld.go的文件。通过匹配包名和文件名去获取作品。 也可能是你需要升级Go。我有一个类似的问题,我有使用 go.mod 定义模块的现有代码。在一台测试机器上,我下载了代码并试图编译它,但是 Go 给了我各种与 GOPATH 相关的错误并且无法找到模块。这是 Go 版本 1.7。我升级 Go 后,它就可以正常工作了。 键入这是终端以获取最新说明$ go help gopath
【参考方案1】:
编辑:既然您指的是 GOPATH,请参阅 fasmat 的 answer(已投票)
如“How do I make go find my package?”中提到的,需要将包xxx
放在目录xxx
中。
见Go language spec:
package math
一组共享相同
PackageName
的文件构成一个包的实现。 一个实现可能要求一个包的所有源文件位于同一个目录中。
Code organization 提到:
在构建导入包“
widget
”的程序时,go
命令会在 Go 根目录中查找src/pkg/widget
,然后——如果在那里找不到包源——它会搜索src/widget
在每个工作区中按顺序排列。
(“工作区”是您的GOPATH
中的路径条目:该变量可以引用多个路径以使您的“src, bin, pkg
”成为)
(原答案)
您还应该将GOPATH
设置为~/go,而不是GOROOT
,如“How to Write Go Code”所示。
Go 路径用于解析导入语句。它由 go/build 包实现并记录在案。
GOPATH
环境变量列出了查找 Go 代码的位置。 在 Unix 上,该值是以冒号分隔的字符串。 在 Windows 上,该值是以分号分隔的字符串。 在计划 9 中,值是一个列表。
这和GOROOT
不同:
Go 二进制发行版假定它们将安装在
/usr/local/go
(或 Windows 下的c:\Go
)中,但可以将它们安装在不同的位置。 如果这样做,则需要在使用 Go 工具时将GOROOT
环境变量设置为该目录。
【讨论】:
还有一个short video intro来设置GOPATH 抱歉,我已经编辑了原始问题。我到处说 GOROOT,我的意思是 GOPATH。【参考方案2】:您是否尝试将 go 的绝对目录添加到您的“路径”中?
export PATH=$PATH:/directory/to/go/
【讨论】:
$PATH 与你的 go 包路径无关。【参考方案3】:它不起作用,因为您的 foobar.go
源文件不在名为 foobar
的目录中。 go build
和 go install
尝试匹配目录,而不是源文件。
-
将
$GOPATH
设置为有效目录,例如export GOPATH="$HOME/go"
将foobar.go
移动到$GOPATH/src/foobar/foobar.go
,构建应该可以正常工作。
其他推荐步骤:
-
将
$GOPATH/bin
添加到您的$PATH
通过:PATH="$GOPATH/bin:$PATH"
将main.go
移动到$GOPATH/src
的子文件夹,例如$GOPATH/src/test
go install test
现在应该在 $GOPATH/bin
中创建一个可执行文件,可以通过在终端中输入 test
来调用它。
【讨论】:
这不是bug吗?我的GOPATH=/usr/local/go-pkgs
,所以 Go 在 /usr/local/go-pkgs/src/<package-name>
中查找源代码,但 go get
将其放入 /usr/local/go-pkgs/src/gopkg.in/<package-name>
。为什么我必须在安装后手动移动我的所有包?这简直是愚蠢的。
go get
通常将包放入$GOPATH/src/
,因此如果您调用go get domain.com/path/to/package
,它将最终放入$GOPATH/src/domain.com/path/to/package
。我猜你尝试从gopkg.in
获取包裹?如果是这样,那是绝对预期的行为,你应该用他们的全名导入它们;例如import "gopkg.in/yaml.v1"
和 described in the docs。
啊,我明白了。谢谢你驱散我的无知。【参考方案4】:
TL;DR:遵循 Go 约定! (教训惨重),检查旧的 go 版本和remove 他们。安装最新版本。
对我来说,解决方案是不同的。我在一个共享的 Linux 服务器上工作,在多次验证了我的 GOPATH
和其他环境变量之后,它仍然无法正常工作。我遇到了几个错误,包括“找不到包”和“无法识别的导入路径”。尝试按照golang.org(包括uninstall部分)的说明使用this解决方案重新安装后仍然遇到问题。
我花了一些时间才意识到还有一个旧版本尚未卸载(运行go version
然后再次运行which go
...DAHH)这让我遇到了this 的问题并最终解决了。
【讨论】:
【参考方案5】:虽然关于需要将目录与包名匹配的公认答案仍然是正确的,但您确实需要迁移到使用 Go 模块而不是使用 GOPATH。遇到这个问题的新用户可能会对提到使用 GOPATH (就像我一样)感到困惑,这些现在已经过时了。因此,我将尝试解决此问题并提供与使用 Go 模块时防止此问题相关的指导。
如果您已经熟悉 Go 模块并且遇到此问题,请跳到下面我更具体的部分,其中涵盖了一些容易忽略或忘记的 Go 约定。
本指南讲授 Go 模块:https://golang.org/doc/code.html
使用 Go 模块组织项目
一旦您迁移到该文章中提到的 Go 模块,请按照描述组织项目代码:
一个存储库包含一个或多个模块。一个模块是一个集合 一起发布的相关 Go 包。一个 Go 存储库 通常只包含一个模块,位于 存储库。一个名为 go.mod 的文件声明了模块路径: 模块内所有包的导入路径前缀。模块 包含包含其 go.mod 文件的目录中的包 以及该目录的子目录,直到下一个子目录 包含另一个 go.mod 文件(如果有)。
每个模块的路径不仅作为其导入路径前缀 包,但也指示 go 命令应该查找的位置 下载它。例如,为了下载模块 golang.org/x/tools,go 命令会查询存储库 由https://golang.org/x/tools 表示(此处有更多描述)。
导入路径是用于导入包的字符串。一个包 导入路径是它的模块路径,与其在 模块。例如,模块 github.com/google/go-cmp 包含一个 包在目录 cmp/ 中。该包的导入路径是 github.com/google/go-cmp/cmp。标准库中的包不 有一个模块路径前缀。
你可以像这样初始化你的模块:
$ go mod init github.com/mitchell/foo-app
您的代码无需位于 github.com 上即可构建。不过,最好的做法是构建模块,就好像它们最终会被发布一样。
了解尝试获取包裹时会发生什么
这里有一篇很棒的文章讨论了当您尝试获取包或模块时会发生什么:https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 它讨论了包的存储位置,并将帮助您了解如果您已经在使用 Go 模块,为什么会出现此错误。
确保导入的函数已经导出
请注意,如果您无法从其他文件访问函数,则需要确保已导出函数。正如我提供的第一个链接中所述,函数必须以大写字母开头才能导出并可以导入到其他包中。
目录名称
另一个关键细节(如已接受的答案中所述)是目录名称是定义包名称的内容。 (您的包名称需要与它们的目录名称匹配。)您可以在此处查看示例:https://medium.com/rungo/everything-you-need-to-know-about-packages-in-go-b8bac62b74cc
话虽如此,包含您的 main
方法(即您的应用程序的入口点)的文件在某种程度上不受此要求的约束。
例如,我在使用这样的结构时遇到了导入问题:
/my-app
├── go.mod
├── /src
├── main.go
└── /utils
└── utils.go
我无法将utils
中的代码导入我的main
包中。
但是,一旦我将main.go
放入它自己的子目录中,如下所示,我的导入工作正常:
/my-app
├── go.mod
├── /src
├── /app
| └── main.go
└── /utils
└── utils.go
在该示例中,我的 go.mod 文件如下所示:
module git.mydomain.com/path/to/repo/my-app
go 1.14
当我在添加对 utils.MyFunction()
的引用后保存 main.go 时,我的 IDE 自动拉入对我的包的引用,如下所示:
import "git.mydomain.com/path/to/repo/my-app/src/my-app"
(我正在使用带有 Golang 扩展的 VS Code。)
请注意,导入路径包含包的子目录。
处理私人回购
如果代码是私有仓库的一部分,您需要运行 git 命令来启用访问。否则,您可能会遇到其他错误 本文提到了如何为私有 Github、BitBucket 和 GitLab 存储库执行此操作:https://medium.com/cloud-native-the-gathering/go-modules-with-private-git-repositories-dfe795068db4 这个问题也在这里讨论:What's the proper way to "go get" a private repository?
【讨论】:
【参考方案6】:我通过将 go env GO111MODULE 设置为关闭解决了这个问题
go env -w GO111MODULE=off
注意:设置 GO111MODULE=off 将关闭最新的 GO 模块功能。
参考:Why is GO111MODULE everywhere, and everything about Go Modules (updated with Go 1.17)
GO111MODULE 与 Go 1.16
从 Go 1.16 开始,默认行为是 GO111MODULE=on,这意味着如果 你想继续使用旧的 GOPATH 方式,你将不得不强制 Go 不要使用 Go Modules 功能:
导出 GO111MODULE=off
【讨论】:
【参考方案7】:在最近从 1.14 开始的 go 版本中,我们必须在构建或运行之前执行 go mod vendor
,因为默认情况下 go 将 -mod=vendor
附加到 go 命令。
所以在做了go mod vendor
之后,如果我们尝试构建,我们将不会遇到这个问题。
【讨论】:
我希望这很快就会出现在搜索结果的更高位置,因为这正是我需要知道的。 这行得通!去 v1.17 。你能详细解释一下这里到底发生了什么吗?【参考方案8】:如果您有一个有效的$GOROOT
和$GOPATH
,但在它们之外进行开发,如果包(您的或其他人的)尚未下载,您可能会收到此错误。
如果是这种情况,请尝试go get -d
(-d 标志阻止安装)以确保在运行、构建或安装之前下载包。
【讨论】:
【参考方案9】:跑步 go env -w GO111MODULE=auto
为我工作
【讨论】:
【参考方案10】:对我来说,上述解决方案均无效。但是我的 go 版本不是最新的。我已经下载了最新版本并在我的mac os中替换了旧版本,之后它完美运行。
【讨论】:
【参考方案11】:无需编辑 GOPATH 或其他任何东西,就我而言,只需执行以下操作:
/app
├── main.go
├── /utils
└── utils.go
在需要的地方导入包。这可能不直观,因为它与 app 路径无关。您还需要在包路径中添加 app:
main.go
:
package main
import(
"app/util"
)
在 app 目录下,运行:
go mod init app
go get <package/xxx>
go build main.go
/go run main.go
你应该很高兴。
GOPATH = /home/go
appPath = /home/projects/app
用go mod init app
创建一个合适的go.mod和go.sum(删除之前的旧)
之后,使用go get github.com/example/package
解决所有依赖项,例如缺少包。
【讨论】:
以上是关于Go build:“找不到包”(即使设置了 GOPATH)的主要内容,如果未能解决你的问题,请参考以下文章