go 1.11 前必须设 gopath,因工具链仅识别 $gopath/src 下的代码,否则报 cannot find package 或 main;go get 将包存入对应 import 路径,go install 要求包路径映射到 $gopath/src 子目录。

Go 1.11 之前为什么必须设 GOPATH
因为老版本 Go 工具链(go build、go get)默认只认 $GOPATH/src 下的代码,所有依赖、主模块、第三方包都得塞进去。不设或设错,go run main.go 会报 cannot find package 或直接找不到 main 函数。
常见错误现象:
-
go: cannot find main module(其实不是模块问题,是当前路径不在$GOPATH/src子目录下) -
import "github.com/user/repo"失败,但go get github.com/user/repo却把包下到$GOPATH/src/github.com/user/repo,而你的代码在桌面,根本没连上
实操建议:
- 必须确保项目路径形如
$GOPATH/src/github.com/yourname/project,否则go install不生效 -
GOPATH可以是多个路径,用:分隔(Linux/macOS)或;(Windows),但只有第一个用于写入(go get安装目标) - 别把
GOPATH设成/usr/local/go或GOROOT,会污染 SDK
go get 在 GOPATH 模式下到底做了什么
它不是“下载源码”那么简单——而是:解析 import 路径 → 去对应 VCS(git/hg/svn)拉取 → 解压到 $GOPATH/src/<import-path></import-path> → 编译安装二进制到 $GOPATH/bin(如果含 main)。
立即学习“go语言免费学习笔记(深入)”;
关键点:
- 路径必须合法:比如
go get github.com/gorilla/mux会存到$GOPATH/src/github.com/gorilla/mux;但go get ./localpkg会失败,因为./不是远程导入路径 - 没有
go.mod时,go get -u会升级所有 transitive 依赖,可能破坏兼容性(无版本锁定) - 若本地已有同名目录但不是 git 仓库,
go get会报fatal: not a git repository并退出,不会覆盖
为什么 go build 有时能跑通,go install 却失败
因为 go build 只编译当前目录(或指定包),不关心是否在 $GOPATH/src;而 go install 要求:1)当前是 main 包;2)该包路径必须能映射回 $GOPATH/src 的某个子路径,才能决定往 $GOPATH/bin 写哪个可执行文件名。
典型场景:
- 你在
~/project/cmd/app写了main.go,但~/project不在$GOPATH/src下 →go install报no install location for directory - 你在
$GOPATH/src/example.com/a,运行go install,生成的二进制叫a,不是app—— 名字来自最后一级目录名,不是main.go文件名 - 如果
GOBIN被设了,go install会优先写入那里,而非$GOPATH/bin
从 GOPATH 迁移到 module 模式时最常漏掉的一步
删掉 GOPATH 环境变量后,仍保留旧项目结构(比如还在 $GOPATH/src/xxx 下开发),会导致 go 命令陷入“半 module 模式”:go list 认为你在 module 外,但 go build 又试图读 go.mod,结果行为不一致。
真正干净切换的关键动作:
- 在项目根目录执行
go mod init example.com/myproj(哪怕只是临时名字) - 删掉所有
$GOPATH/src/xxx的软链接或复制,把代码挪到任意非GOPATH路径下(比如~/code/myproj) - 确认
GO111MODULE=on(Go 1.16+ 默认开启,但老 shell 可能残留off) -
go mod tidy后检查go.sum是否生成,没生成说明还在 fallback 到 GOPATH 查找
容易被忽略的是:即使你不用 go get,只要项目里有 import "some/old/pkg" 且该包只存在于 $GOPATH/src,go build 就仍会去那里找——module 模式不会自动忽略 GOPATH,除非明确关掉它。










