摘自:
http://blueskykong.com/2019/02/18/go-dep-1/
https://www.cnblogs.com/apocelipes/p/10295096.html#vcs-semver
GOPATH和GOROOT
GOROOT的目的就是告知go当前的安装位置,默认go会安装在/usr/local/go下,但也允许自定义安装位置(通过 export GOROOT=$HOME/go1.9.3
指定)。编译的时候从GOROOT去找SDK的system libariry
GOPATH必须要设置,GOPATH告知go,需要代码(包括本项目即内部依赖和引用外部项目的代码即外部依赖)的时候去哪里查找。GOPATH可以随着项目的不同而重新设置。
GOPATH下会有3个目录:src、bin、pkg。
- src目录:go编译时查找代码的地方;按照golang默认约定,go run,go install等命令的当前工作路径(即在此路径下执行上述命令)。
- bin目录:go get这种bin工具的时候,二进制文件下载的目的地; golang编译可执行文件存放路径
- pkg目录:编译生成的lib文件存储的地方。golang编译包时,生成的.a文件存放路径
内部依赖管理
- 编译时会去
$GOPATH/src/
目录去查找需要的代码
GOPATH来管理外部依赖
go允许import不同代码库的代码,例如github.com, k8s.io, golang.org等等;对于需要import的代码,可以使用 go get 命令取下来放到GOPATH对应的目录中去。例如
go get github.com/globalsign/mgo
(下载和创建项目要保持目录一致,这样才能保证能够正确的引用外部导入和内部导入),会下载到$GOPATH/src/github.com/globalsign/mgo
中去,当其他项目在import github.com/globalsign/mgo
的时候也就能找到对应的代码了。- 对于go来说,其实并不在意你的代码是内部还是外部的,总之都在GOPATH里,任何import包的路径都是从GOPATH开始的。Go 语言原生包管理的缺陷:
- 依赖 列表/关系 无法持久化到本地,需要找出所有依赖包然后一个个 go get
- 只能依赖本地全局仓库(GOPATH/GOROOT),无法将库放置于局部仓库($PROJECT_HOME/vendor)
vendor
- vendor就是让go编译时,优先从项目源码树根目录下的vendor目录查找代码,如果vendor中有,则不再去GOPATH中去查找。
- 以kube-keepalived-vip为例。该项目会调用k8s.io/kubernetes的库(Client),但如果你用1.5版本的kubernetes代码来编译keepalived,会编译不过。1.5版本中代码有变化,已经没有这个Client了。这就是前面说的依赖GOPATH来解决go import所带来的问题,代码不对上了。
- 使用vendor目录可以把所有依赖的包都拷贝到了vendor目录下,对于需要编译该项目的人来说,只要把代码从github上clone到
$GOPATH/src
以后,就可以进去go build了(注意,必须将kube-keepalived-vip项目拷贝到$GOPATH/src
目录中,否则go会无视vendor目录,仍然去$GOPATH/src
中去找依赖包)。
govendor
该工具将项目依赖的外部包拷贝到项目下的 vendor 目录下,并通过 vendor.json 文件来记录依赖包的版本,方便用户使用相对稳定的依赖。
使用步骤
#安装 go get -u github.com/kardianos/govendor # 进入项目的根目录 # 创建 vendor 文件夹和 vendor.json 文件,此时文件中只有本项目的信息 govendor init # 拷贝GOPATH下的代码到vendor目录中,更新vendor.json govendor add +external # 列出已经存在的依赖包 govendor list # 找出使用的对应包 govendor list -v fmt # 拉取指定版本的包 govendor fetch golang.org/x/net/context@a4bbce9fcae005b22ae5443f6af064d80a6f5a55 govendor fetch golang.org/x/net/context@v1 # Get latest v1.*.* tag or branch. govendor fetch golang.org/x/net/context@=v1 # Get the tag or branch named "v1".
govendor还可以直接指定依赖包版本来获取包
Modules
go module 是go包的集合,是源代码交换和版本化控制的基本单元
- 「模块根目录」 ( Module root ) : 包含了名为
go.mod
文件的目录,可以存放于文件系统上的任何位置,而不用管GOPATH
路径到底是什么 - 「模块路径」 ( Module path ) : 与模块根目录对应的导入路径的前缀
- 「主模块」( Main module ) : 包行了运行 go 命令的所在目录的模块
GO111MODULE
要使用go module
,首先要设置GO111MODULE=on
。
- 如果设置为
on
,那么无论模块在于何种路径,都会启用模块支持,始终使用 module-aware mode,只根据 go.mod 下载 dependency 而完全忽略 GOPATH 以及 vendor 目录 - 如果设置为
off
,禁用 go module 功能,go compiler 会始终使用 GOPATH mode,即无论要构建的源码目录是否在 GOPATH 路径下,go compiler 都会在传统的 GOPATH 和 vendor 目录 (仅支持在 GOPATH 目录下的 package) 下搜索目标程序依赖的 go package; - 如果没有设置,或设置为
auto
,满足以下任一条件时才使用 module-aware mode:- 当前目录位于 GOPATH/src 之外并且包含 go.mod 文件
- 当前目录位于包含 go.mod 文件的目录下
既有项目
假设你已经有了一个go 项目, 比如在
$GOPATH/github.com/smallnest/rpcx
下, 你可以使用go mod init github.com/smallnest/rpcx
在这个文件夹下(即模块根目录)创建一个空的go.mod
(只有第一行module github.com/smallnest/rpcx
即模块导入名称)。下面是一个简化的go.mod的内容
module my/thing //模块名称 require (//要求的依赖项列表以及版本 one/thing v1.3.2 other/thing v2.5.0 // indirect ... ) exclude (//排除的依赖项,仅在当前模块为主模块时生效 bad/thing v0.7.3 ) replace (//替换的依赖项,仅在当前模块为主模块时生效 src/thing 1.0.2 => dst/thing v1.1.0 )
go ge