编程语言大多都有依赖管理方面的工具,比如 Java 的 Maven、Gradle ,Javascript 的 npm,Python 的pip。
Go 也有这方面的工具,不过由于历史原因,这方面挺乱的。
GOROOT
GOROOT 是用来告知 Go 当前的安装位置的,这个环境变量不是必须设置的,
Go 默认就是安装在 /usr/local/go 目录下。
当 Go进行编译的时候,SDK 的 system libariry 库就是在这个目录下寻找。
GOPATH
GOPATH 的目的是为了告知 Go,当需要代码的时候,去哪里查找。
这里的代码,其实就是 package ,包括本项目和引用外部项目的代码。
GOPATH可以随着项目的不同而重新设置。
这个环境变量必须设置。
一般会设置两个 GOPATH 。
第三方的 libairy 就下到第一个 GOPATH ,而自己的项目就放在第二个 GOPATH 。
GOPATH下会有3个目录:src, bin, pkg。
- src目录:go编译时查找代码的地方
- bin目录:go get godep这种bin工具的时候,二进制文件下载的目的地
- pkg目录:编译生成的lib文件存储的地方。
vendor
GOPATH 有个问题,就是当项目导入的包,改了或者删了,那代码的编译自然就无法通过。
之所以会造成这样的情况,应该跟 Google 大部分代码就放在一个大仓库里有关,在 Google 的代码仓库里没有发生这种问题的环境。
为了解决这个问题,官方引入了 vendor属性 。
go在1.5版本引入了vendor属性 (默认关闭,需要设置go环境变量GO15VENDOREXPERIMENT=1), 并在1.6版本中默认开启了vendor属性。
这个 vendor 实际上就是项目根目录的一个 vendor 目录。
在编译的时候优先在 vendor 下寻找依赖,找不到再去 GOPATH 下寻找依赖,
如果复制一份到这个目录下,这样以后编译就不怕 GOPATH 的依赖出现变动了 。
这个时候进行编译时寻找依赖的顺序就成了: vendor -> GOPATH -> GOROOT
vendor目录还有一些问题:
- 没有版本管理
- 项目依赖的包,需要手动复制到 vendor 目录下
社区在 vendor 基础上开发了多个管理工具。
常用的如下:
- godep
- glide
- govendor
官方也开发了一个管理工具:dep ,到现在(2019-08-31)都还没有 release 版本。。。
modules
modules 是 Go v1.11 引入的 依赖管理feature 。
目前该功能默认关闭,到下一个版本 v1.13 将默认开启。
别的不说,总算是有官方的版本管理了,只是苦了之前社区那些工具的开发者。
我是这两天开始才开始学习的 Go,现在是 Go v1.12.9 ,主要记录一下 modules 。
modules官方定义:
模块是相关Go包的集合。modules是源代码交换和版本控制的单元。 go命令直接支持使用modules,包括记录和解析对其他模块的依赖性。modules替换旧的基于GOPATH的方法来指定在给定构建中使用哪些源文件。
Go 为了保持兼容,目前一个项目想要使用 modules 需让项目存放在非 GOPATH/src 目录下。
使用
依赖包的存放位置变更为 $GOPATH/pkg ,多个项目可以共享 package,省硬盘!
设置 GO111MODULE
GO111MODULE 有三个值:off, on和auto(默认值)。
-
GO111MODULE=off,go 命令行将不会支持 module 功能,寻找依赖包的方式将会沿用旧版本那种通过 vendor 目录或者 GOPATH 模式来查找。
-
GO111MODULE=on,go命令行会使用 modules,而一点也不会去 GOPATH 目录下查找。
-
GO111MODULE=auto,默认值,go 命令行将会根据当前目录来决定是否启用 modules 功能。
GO111MODULE=auto 的判断可以分两种情况:
-
当前目录在GOPATH/src之外且该目录包含go.mod文件
-
当前文件在包含go.mod文件的目录下面。
go mod
Go 提供了 go mod 命令来管理包。
可以使用 go help mod 查看各种参数的作用。
初始化项目
想要使得一个项目变成 mod 项目 ,可以执行 go mod init
go mod init 本模块的路径 //初始化生成go.mod 文件
go.mod文件一旦创建后,它的内容将会被go toolchain全面掌控。go toolchain会在各类命令执行时,比如go get、go build、go mod等修改和维护go.mod文件。
go.mod 语法 :
- module 本模块的路径,所有本模块下的包共享这个路径前缀
- require 指定的项目需要的依赖模块,模块遵循语义化版本
- replace 替换 import 模块的路径
- exclude 排除某个模块,使之不能被 import
go.sum
当下载依赖包,并把依赖信息添加到 go.mod 文件中,同时把依赖版本哈希信息存到 go.sum 文件中:
//go.sum
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
github.com/Anderson-Lu/gofasion v0.0.0-20190530065914-6a05b679ee48 h1:Y0um3nHCQDleEpQzahJAkT8mvKTlLqvjoIqZYIAJgAw=
github.com/Anderson-Lu/gofasion v0.0.0-20190530065914-6a05b679ee48/go.mod h1:nJfnu9e1b/lczgULa3laeoUzeadR3ylEgYj8zpXO+Wc=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
go.sum 作用:当编译的时候,校验引入的依赖和上一次引入的依赖是不是同一个依赖。
升级版本
假设当前一个依赖的版本为 v1.0.0,那我们升级依赖有两种方式:
1.
使用 go get, 运行 go get,如果有版本的更改,那么 go.mod 文件也会更改
- 运行
go get -u将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号) - 运行
go get -u=patch将会升级到最新的修订版本 - 运行
go get package@version将会升级到指定的版本号
go mod 命令
go mod edit -require="package@version"
go mod tidy
go mod edit -require 可以主动修改 go.mod 文件中依赖的版本号,然后通过 go mod tidy 对版本进行更新。
go mod tidy: 它会自动清理掉不需要的依赖项,同时可以将依赖项更新到当前版本。
可能发生的问题
依赖无法下载
使用 go mod 和 go get 的时候,可能会因为一些特殊原因,无法下载需要的一些依赖。
解决方法:
1.设置 GOPROXY 环境变量
set GOPROXY=“https://goproxy.io”
2.给 git 配置代理
因为拉取 git 项目, go get 底层也是使用的 git 命令。
相应的,我们可以给当前项目配置一下 git config 。
- http代理
git config --global https.proxy http://127.0.0.1:1080
git config --global https.proxy https://127.0.0.1:1080
git config --global --unset http.proxy
git config --global --unset https.proxy
- socks代理
git config --global http.proxy 'socks5://127.0.0.1:1080'
git config --global https.proxy 'socks5://127.0.0.1:1080'
git config --global --unset http.proxy
git config --global --unset https.proxy