这个代码怎么会编译不通过?Goland 新手常见问题解决:GOPATH 和 Go Modules 编译不成功
2019-09-25
自从 Go1.11 开始,官方开始支持依赖管理,这就是 Go Modules。如果你对 Go Modules 还不熟悉,请一定要掌握,Go 1.13 默认会使用它。推荐阅读 Go 官方博文,GCTT 译文:Go Modules 的使用方法。
新手学习的时候,对于 GOPATH 和 Go Modules 可能容易搞混,特别是,很多资料,依然是 GOPATH 的,而最新版本的一些 IDE 或编辑器可能默认使用 Modules,这样很容易出现一些“自己解决不了的问题”。(特别是即将发布的 Go1.13 会默认启用 Modules)
我们来看一个具体的例子,使用 Goland。(Go 版本:1.12.6)
创建项目 testgopath
如图,我们使用 GOPATH 模式。
之后,创建如下目录和文件:
其中,hello.go 文件代码如下:
package main
import "fmt"
func demo() { fmt.Println("This is demo")}
helloworld.go 文件代码如下:
package main
import "fmt"
func main() { fmt.Println("Hello") demo()}
(以上目录和代码来自球友咨询的问题)。
如何运行 GOPATH 项目
1)在 helloworld.go 文件右键弹出菜单,执行:Run "go build helloworld.go”,结果如下:
# command-line-argumentssrc/hello/hellowrold.go:7:2: undefined: demo
Compilation finished with exit code 2
很明显,无论是 go run 还是 go build ,多个文件的项目,只提供单个文件是不行的。
2)配置运行:go build hello ,采用 Package 的运行方式,很可能结果是:
can't load package: package hello: unknown import path "hello": cannot find module providing package hello
3)go build hello,选择 Directory 的方式,没有出现错误。
然而,执行 Run,我这里却报错了:
go: cannot find main module; see 'go help modules'
从错误提示可知,启用的是 Go Modules 而不是 GOPATH。原因是我在全局配置了 GO111MODULE=on。实际上,Go1.13 开始,默认也会启用 Modules,所以这个错误会很常见。
知道原因,我们就可以通过配置环境变量,禁用 Modules 来解决:
这次运行正常了!
4)如果你在 IDE 下怎么配置运行都不对时,你试试在终端执行。
GOPATH 模式下,对于 go build 来说,只要 GOPATH 正确,
go build hello
总是能成功;
上面的规则,在终端验证成功了,那么我们可以肯定,IDE 不成功的原因是 GOPATH 不对。(一样要注意 GO111MODULE 这个环境变量的值)
对于 Goland IDE 来说,我们打开 Preferences,在 Go > GOPATH 下,配置 Project GOPATH:
这时,我们再回到 Package 的运行模式重试,会发现也正常了。(如果不成功,一样需要加上 GO111MODULE=off)。
将项目改造为 module
将 GOPATH 项目改造为 module ,推荐阅读:迁移到 mod 只需 3 个步骤[1]。
针对上面的 testgopath,我们执行如下迁移动作:
cd /Users/xuxinhua/project/golang/testgopath
mv src/* . && rm -rf src
go mod init testgopath
这样,我们已经成功将项目改造为 module 模式了。
打开 Goland,很可能会发现多了一个 pkg 目录:
原因是,module 模式会将依赖和缓存写入一个 GOPATH 目录中,一般情况下是全局的 GOPATH(通常是 $HOME/go),因为我们上面为该项目制定了 Project GOPATH,所以出现了 pkg 目录。我们可以改为 Global GOPATH,同时删除 pkg 目录。
如何运行 module 项目
和运行 GOPATH 项目一样,我们使用三种方式运行,go build helloworld.go 的 File 方式肯定不行,我们着重看 Package 和 Directory 方式。
1)Directory 方式,如下配置:
一切正常!
2)Package 方式,如下配置:
这里说明两点:
Package path:testgopath/hello,也就是需要加上 module 的名字
报错了,提示找不到包
虽然报错,我们强制执行,点击工具栏 Run,会出现弹窗:
不管它,依然 Run(Continue Anyway)。会发现运行正常!这说明 Goland 误报了?
还记得我们通过 Goland 创建该项目时, 并没有选择 Go Modules(vgo)
模式。而且,如果你项目依赖了其他包,会提示各种找不到依赖包的错误。这时候,我们只需要将项目配置改为 Go Modules(vgo)
即可。
勾选 Enable Go Modules
国内环境下,一般需要配置 Proxy,具体可以参考我之前的文章:Go module 模式下解决“墙”问题[2]
这样配置后,发现红叉没了,运行一切正常。
总结
无论我们使用什么编辑器(IDE),遇到问题时,我们如果知晓原理,都能够轻松解决掉;如果不知晓原理,通过瞎配置或其他方式碰巧对了,下次遇到其他问题,你依然一脸懵逼。
因此,知其然并知其所然很重要!GOPATH 和 Go Modules 的环境问题搞明白了吗?建议按照文章的步骤自己实际试试,加深理解,有问题留言沟通。
补充:随着 Modules 成为趋势,慢慢请忘掉 GOPATH 吧!
基于 Go1.13 的话,建议执行:go env -w GOPROXY=https://goproxy.cn,direct
参考资料
迁移到 mod 只需 3 个步骤: https://studygolang.com/articles/17780
[2]
Go module 模式下解决“墙”问题: https://studygolang.com/topics/8737