Eli's Blog

1. Go Modules

1.1 简介

Go Modules 是官方最新的包管理方式,它解决了如下问题:

  • 所有的依赖包必须在 GOPATH 下,但同一个库只能保存一个版本
  • 工作目录必须在 GOPATH/src 目录下

使用 Go Modules 之后,可在 GOPATH/src 之外创建目录和管理包

设置 go mod 和 go proxy:

1
2
3
4
5
go env -w GOBIN=/Users/eli/go/bin
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct

go env

GO111MODULE:

  • on: 强制使用modules, 不再去GOPATH下查找
  • off: 不使用modules,去GOPATH和vendor下查找
  • auto: 默认值,如果当前目录下有go.mod文件,则使用modules

1.2 基础命令

1
2
3
4
5
6
7
8
9
10
11
12
go help mod

go mod <command> [arguments]

download download modules to local cache
edit edit go.mod from tools or scripts
graph print module requirement graph
init initialize new module in current directory
tidy add missing and remove unused modules
vendor make vendored copy of dependencies
verify verify dependencies have expected content
why explain why packages or modules are needed

1.3 基本使用

1.3.1 初始化

1
2
3
go mod init github.com/elihe2011/gomod

go get -u github.com/gin-gonic/gin

生成的文件:

  • go.mod: 模块管理文件
    • module语句: 指定包的名字(路径)
    • require语句: 指定的依赖项模块
    • replace语句: 可以替换依赖项模块
    • exclude语句: 可以忽略依赖项模块
  • go.sum: 记录依赖看的版本和哈希值

解决获取包时的代理错误:

1
2
3
4
5
6
7
8
$ go get -u github.com/gin-gonic/gin

go get github.com/gin-gonic/gin: module github.com/gin-gonic/gin: Get "https://proxy.golang.org/github.com/gin-gonic/gin/@v/list": dial tcp 34.64.4.113:443: i/o timeout

# go包管理,默认使用的是proxy.golang.org,在国内无法访问,换为
go env -w GOPROXY=https://goproxy.cn,direct # 七牛云

go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct

1.3.2 下载指定版本的依赖库

1
2
3
4
5
6
7
8
9
10
11
# 当前模块和支撑包
go list -m all

# 可用版本
go list -m -versions github.com/gin-gonic/gin

# 删除无效的modules
go mod tidy

# 获取指定版本
go get github.com/gin-gonic/gin@

1.4 编译打包

1.4.1 使用GOPATH模式进行打包

1
2
3
export GO111MODULE=off
export CGO_ENABLED=0
go build -a -v -o app main.go

1.4.2 使用vendor目录下包来进行打包

1
2
3
export GO111MODULE=on
export CGO_ENABLED=0
go build -mod=vendor -a -v -o app main.go

1.5 go modules包管理特点

  • 第三方包存储路径:$GOPATH/pkg/mod
  • $GOPATH/pkg/mod 下可以保存相同包的不同版本
  • 当项目放在 $GOPATH/src 时,GO111MODULE=auto 自动模式
  • 依赖包中的地址失效了怎么办?比如 golang.org/x/… 下的包都无法下载怎么办?
    • 在go.mod文件里用 replace 替换包,例如
      replace golang.org/x/text => github.com/golang/text latest
      这样,go会用 github.com/golang/text 替代golang.org/x/text,原理就是下载github.com/golang/text 的最新版本到 $GOPATH/pkg/mod/golang.org/x/text下

2. govendor

govendor只是用来管理项目的依赖包,如果GOPATH中本身没有项目的依赖包,则需要通过go get先下载到GOPATH中,再通过govendor add +external拷贝到vendor目录中。Go 1.6以上版本默认开启GO15VENDOREXPERIMENT环境变量。

2.1 安装

1
go get -u -v github.com/kardianos/govendor

2.2 常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 初始化, 生成vender目录等
govendor init

# 添加包
govendor add github.com/fvbock/endless
govendor add +external

# 移除包
govendor remove github.com/fvbock/endless
govendor remove +unused

# 查看包
govendor list

# 列出所有缺失、过期和修改过的包
govendor status

# 本地存在 vendor.json 时候拉去依赖包,匹配所记录的版本
govendor sync

# 获取包
govendor get github.com/gorilla/websocket
govendor fetch github.com/gorilla/websocket

2.3 包状态

状态 缩写状态 含义
+local l 本地包,即项目自身的包组织
+external e 外部包,即被 $GOPATH 管理,但不在 vendor 目录下
+vendor v 已被 govendor 管理,即在 vendor 目录下
+std s 标准库中的包
+unused u 未使用的包,即包在 vendor 目录下,但项目并没有用到
+missing m 代码引用了依赖包,但该包并没有找到
+program p 主程序包,意味着可以编译为执行文件
+outside o 外部包和缺失的包
+all a 所有的包