构建: “ Can not find package”(即使设置了 GOPATH)

即使我已经正确地设置了 GOPATH,我仍然不能得到“构建”或“运行”来找到我自己的软件包。我做错了什么?

$ 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
385585 次浏览

编辑: 因为你的意思是 GOPATH,看到 法斯马特回答(否决)

正如在“ 我怎样才能找到我的包裹?”中提到的,您需要将包 xxx放在目录 xxx中。

参见 语言规范:

package math

共享相同 PackageName的一组文件形成了一个包的实现。
实现可能要求包的所有源文件都位于相同的目录中。

代码组织提到:

在构建一个导入包“ widget”的程序时,go命令在 Go 根目录中查找 src/pkg/widget,然后ーー如果没有找到包源ーー它会在每个工作区中按顺序搜索 src/widget

(“ workspace”是 GOPATH中的一个路径条目: 该变量可以引用多个路径,以便将‘ src, bin, pkg’作为路径)


(原答案)

您还应该将 GOPATH设置为 ~/go,而不是 GOROOT,如“ 如何编写 Go 代码”所示。

Go 路径用于解析导入语句,由 Go/build 包实现并记录在案。

GOPATH环境变量列出了寻找 Go 代码的位置。
在 Unix 上,该值是一个冒号分隔的字符串。
在 Windows 上,该值是分号分隔的字符串。
在 Plan 9中,值是一个列表。

这与 GOROOT不同:

Go 二进制发行版假设它们将安装在 /usr/local/go(或 Windows 下的 c:\Go)中,但是可以将它们安装在不同的位置。
如果要这样做,在使用 Go 工具时,需要将 GOROOT环境变量设置为该目录。

您是否尝试过将 去吧的绝对目录添加到您的“路径”中?

export PATH=$PATH:/directory/to/go/

它不工作,因为您的 foobar.go源文件不在名为 foobar的目录中。go buildgo install尝试匹配目录,而不是源文件。

  1. $GOPATH设置为一个有效的目录,例如 export GOPATH="$HOME/go"
  2. foobar.go移动到 $GOPATH/src/foobar/foobar.go,建筑应该可以正常工作。

其他建议措施:

  1. $GOPATH/bin添加到 $PATH
  2. main.go移动到 $GOPATH/src的子文件夹,例如 $GOPATH/src/test
  3. go install test现在应该在 $GOPATH/bin中创建一个可执行文件,可以通过在终端中键入 test来调用它。

遵循 Go 约定! (吃了苦头) ,检查旧版本和 拿开。安装最新版本。

对我来说,解决办法是不同的。我在一个共享的 Linux 服务器上工作,在多次验证我的 GOPATH和其他环境变量之后,它仍然不能工作。我遇到了几个错误,包括“无法找到包”和“无法识别的导入路径”。在尝试用 这个解决方案重新安装后,按照 Golang.org上的说明(包括 卸载部分)仍然遇到问题。

我花了一些时间才意识到还有一个旧版本没有被卸载(运行 go version然后又运行 which go... ... DAHH) ,这让我想到了 这个的问题并最终解决了。

尽管公认的答案仍然是正确的,即需要将目录与包名称匹配,但是您确实需要迁移到使用 Go 模块,而不是使用 GOPATH。遇到这个问题的新用户可能会对提到使用 GOPATH (就像我一样)感到困惑,因为它们现在已经过时了。因此,我将尝试解决这个问题,并在使用 Go 模块时提供与防止这个问题相关的指导。

如果您已经熟悉 Go 模块并且正在经历这个问题,请跳到我下面更具体的部分,其中包括一些很容易忽略或忘记的 Go 约定。

本指南讲授围棋模块: https://golang.org/doc/code.html

使用 Go 模块组织项目

一旦您迁移到 Go 模块,就像那篇文章中提到的那样,组织项目代码如下所述:

存储库包含一个或多个模块 一起发布的相关 Go 软件包 通常只包含一个模块,该模块位于 其中一个名为 go.mod 的文件声明了模块路径: 模块中所有包的导入路径前缀 包含目录中包含 go.mod 文件的包 以及该目录的子目录,直到下一个子目录 包含另一个 go.mod 文件(如果有的话)。

每个模块的路径不仅作为其 包,但也指示 go 命令应该查看的位置 下载。例如,为了下载模块 Golang.org/x/tools ,go 命令会查询储存库 由 https://golang.org/x/tools表示(在这里描述更多)。

导入路径是用于导入包的字符串 Import 路径是它的模块路径,在 例如,模组 github.com/google/go-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 模块,为什么可能会出现这个错误。

确保导入的函数已被导出

请注意,如果无法从另一个文件访问函数,则需要确保已经导出了函数。正如我提供的第一个链接中所描述的,函数必须以要导出的大写字母开头,并且可以导入到其他包中。

目录名称

另一个重要的细节(正如在已接受的答案中提到的)是,目录的名称定义了包的名称。(您的包名称需要与它们的目录名称相匹配。)你可以在这里看到这样的例子: < a href = “ https://medium.com/rungo/everything-You-need-to-know-about-package-in-go-b8bac62b74cc”rel = “ norefrer”> 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 代码。)

注意,导入路径包含包的子目录。

处理私人回购

如果代码是私有回购的一部分,则需要运行 git 命令来启用访问。否则,你可能会遇到其他错误这篇文章提到了如何为私有的 Github,BitBucket,和 GitLab repos 做这些事情: < a href = “ https://medium.com/cloud-national-the- 收集/go-module-with-private-git-storeitories-dfe795068db4”rel = “ norefrer”> https://medium.com/cloud-native-the-gathering/go-modules-with-private-git-repositories-dfe795068db4 这里也讨论了这个问题: 什么是“获取”私有存储库的正确方法?

我解决了这个问题通过设置我的去环境 GO111MODULE 关闭

go env -w  GO111MODULE=off

注意: 设置 GO111MODULE = off 将关闭最新的 GO 模块功能。

参考资料: 为什么到处都是 GO111MODULE,以及所有关于 Go 模块(用 Go 1.17更新)的东西

GO111模块与 Go 1.16

在 Go 1.16中,默认行为是 GO111MODULE = on,这意味着如果 如果你想继续使用旧的 GOPATH 方式,你就必须强制下围棋 不要使用 Go 模块功能:

出口 GO111MODULE = off

在最近1.14以后的 go 版本中,我们必须在构建或运行之前执行 go mod vendor,因为在默认情况下 go 将 -mod=vendor附加到 go 命令。 因此,在做了 go mod vendor之后,如果我们尝试构建,我们将不会面临这个问题。

如果您有一个有效的 $GOROOT$GOPATH,但是正在它们之外开发,如果包(您的或其他人的)没有被下载,您可能会得到这个错误。

如果是这种情况,请尝试 go get -d(- d 标志防止安装) ,以确保在运行、构建或安装之前下载了包。

运行 go env -w GO111MODULE=auto对我有用

对我来说,以上的方法都不管用。但我的版本不是最新的。我已经下载了最新的版本,并在我的 mac 操作系统中替换了旧版本,之后它完美地工作了。

没有编辑 GOPATH 或任何东西,在我的情况下只是工作如下:


/app
├── main.go
├── /utils
└── utils.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

创建一个适当的 去吧 Mod加油go mod init app(删除旧之前)

然后用 go get github.com/example/package解决所有依赖项,比如丢失的包。

简而言之,即使使用 GO111MODULE = on,您也可以使用以下导入语法解决导入问题:

import <your_module_name>/<package_name>

Your _ module _ name -> 模块名,可以在模块的 go.mod 文件的第一行找到。

例如: github.com/nikhilg-hub/todo/todobackend

Package _ name -> 模块中包的路径。

例如: orm

所以导入声明应该是这样的:

import "github.com/nikhilg-hub/todo/ToDoBackend/orm"

根据我的说法,我们需要指定模块名 + 包名,因为我们可能需要在两个或更多不同的模块中使用相同的包名。

注意: 如果您从同一个模块导入一个包,您仍然需要像上面那样指定完整的导入路径。

我在构建 Docker 文件时也遇到过类似的问题:

[1/3] STEP 9/9: RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go
api/v1alpha1/XXX.go:5:2: cannot find package "." in:
/workspace/client/YYY/YYY.go

这只有在构建 Dockerfile 时才会出现,本地构建可以正常工作。

问题出在我的 Dockerfile 文件中遗漏了一个声明:

COPY client/ client/
  • 应将 GOROOT设置为您的安装目录(/usr/local/go)。
  • 应该将 GOPATH设置为你的工作目录(类似于 /home/username/project_folder)。 将 GOPATH 不应该设置为 GOROOT,因为您自己的项目可能需要安装软件包,建议不要将这些软件包放在 Go安装文件夹中。看看这个 链接了解更多。

我不明白为什么会发生这种情况,我们必须能够从任何地方导入我们的文件在其巢,因为我已经发现,如果我们有一个以上的巢,这将抛出一个错误。

package main


import (
"fmt"
"indexer/source/testPackage3" // this will be show a GOROOT error.
"indexer/testPackage"
"indexer/testPackage2"
)


func main() {
fmt.Println("Agile content indexer -")
fmt.Println(testPackage.Greeting())
fmt.Println(testPackage2.Greeting())
fmt.Println(testPackage3.Greeting())
}




├── testPackage2
│   ├── entry2.go
│   └── source
│       └── entry3.go

最后,我只想告诉你,entry3.go 文件在导入到我的主文件(在这个例子中是 main.go)时无法工作,我不明白为什么,因此,我只是选择在我需要导出的包中使用深度文件夹。

SEE THE STRUCTURE

Go ,导入时 入口2开始可以正常工作,但是 进入3.go 不能正常工作。

此外,目录和包的名称必须相同,这样才能在导入它们时正常工作。