Go的包管理工具(一)

栏目: Go · 发布时间: 5年前

内容简介:在前面转载了系列文章:每一门语言都有其依赖的生态,当我们使用Java语言的时候,使用Maven或者Gradle管理包依赖。早期的Go被很多开发者所诟病的一个问题就是依赖包的管理。Golang 1.5 release版本的发布之前,只能通过设置多个笔者是Mac系统,安装Go有多种方式,通过brew、下载源码安装go等方式可以安装go。

在前面转载了系列文章: Golang 需要避免踩的 50 个坑 ,总得来说阅读量都挺大。今天这篇文章,咱们一起聊聊 Go 的依赖包管理工具。

背景

每一门语言都有其依赖的生态,当我们使用 Java 语言的时候,使用Maven或者Gradle管理包依赖。早期的Go被很多开发者所诟病的一个问题就是依赖包的管理。Golang 1.5 release版本的发布之前,只能通过设置多个 GOPATH 的方式来解决这个问题,例如:我两个工程都依赖了Beego,但A工程依赖的是Beego 1.1,B工程依赖的是Beego 1.7,我必须设置两个 GOPATH 来区分,并且在切换工程的时候 GOPATH 也得切换,无比痛苦。在Golang 1.5 release 开始支持除了 GOROOTGOPATH 之外的依赖管理:vender,官方 wiki 推荐了多种支持这种特性的包管理工具,如:Godep、gv、gvt、glide、govendor和官方的dep等。

环境准备

安装Go

笔者是Mac系统,安装Go有多种方式,通过brew、下载源码安装go等方式可以安装go。

在bash_profile中自定义GOPATH和GOBIN位置:

GOROOT=/usr/local/go
export GOPATH=/Users/user/aoho/go-workspace
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOBIN:$GOROOT/bin

安装完成之后,查看go的环境变量: go env

GOARCH="amd64"
GOBIN="/usr/local/go/bin/go"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/user/aoho/go-workspace"
GORACE=""
GOROOT="/usr/local/go"
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/st/gkm45qzd2tv8mc32my38_n_00000gp/T/go-build646095787=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"

go的版本为: go version go1.9.3 darwin/amd64

GOPATH和GOROOT

GOROOT不是必须要设置的。默认go会安装在/usr/local/go下,但也允许自定义安装位置,GOROOT的目的就是告知go当前的安装位置,编译的时候从GOROOT去找SDK的system libariry。

如上面展示的结果,笔者使用的就是默认的安装地址,也可以通过 export GOROOT=$HOME/go1.9.3 指定。

GOPATH必须要设置,但并不是固定不变的。GOPATH的目的是为了告知go,需要代码的时候,去哪里查找。注意这里的代码,包括本项目和引用外部项目的代码。GOPATH可以随着项目的不同而重新设置。

GOPATH下会有3个目录:src、bin、pkg。

  • src目录:go编译时查找代码的地方;
  • bin目录:go get这种bin工具的时候,二进制文件下载的目的地;
  • pkg目录:编译生成的lib文件存储的地方。

包管理

上面小节提到,依赖的代码去 $GOPATH 指定的位置寻找,这部分代码可能是本项目或者外部引用的项目。下面依次介绍这两种情况。

内部依赖管理

如笔者示例route_auth.go的引入:

import (
	"gwp/Chapter_2_Go_ChitChat/chitchat/data"
	"net/http"
)

route_auth.go需要引用data/user.go,项目结构如下:

Go的包管理工具(一)

编译时会去 $GOPATH/src/ 目录去查找需要的代码,因此只要上面data/user.go在 $GOPATH/src/gwp/Chapter_2_Go_ChitChat/chitchat/data 里面,go编译的时候就能找到。

外部依赖管理

对于外部依赖的管理,在最开始go没有像java使用maven来管理依赖包、包版本,而是直接使用GOPATH来管理外部依赖。

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 get下来的。Go 语言原生包管理的缺陷:

  • 能拉取源码的平台很有限,绝大多数依赖的是 github.com
  • 不能区分版本,以至于令开发者以最后一项包名作为版本划分
  • 依赖 列表/关系 无法持久化到本地,需要找出所有依赖包然后一个个 go get
  • 只能依赖本地全局仓库(GOPATH/GOROOT),无法将库放置于局部仓库($PROJECT_HOME/vendor)

vendor

依赖GOPATH来解决go import存在的问题在上面小节已经列举。为了解决这个问题,go在1.5版本引入了vendor属性(默认关闭,需要设置go环境变量GO15VENDOREXPERIMENT=1),并在1.6版本中默认开启了vendor属性。

简单来说,vendor属性就是让go编译时,优先从项目源码树根目录下的vendor目录查找代码(可以理解为切了一次GOPATH),如果vendor中有,则不再去GOPATH中去查找。

以kube-keepalived-vip为例。该项目会调用k8s.io/kubernetes的库(Client),但如果你用1.5版本的kubernetes代码来编译keepalived,会编译不过。1.5版本中代码有变化,已经没有这个Client了。这就是前面说的依赖GOPATH来解决go import所带来的问题,代码不对上了。

kube-keepalived-vip项目用vendor目录解决了这个问题:该项目把所有依赖的包都拷贝到了vendor目录下,对于需要编译该项目的人来说,只要把代码从github上clone到 $GOPATH/src 以后,就可以进去go build了(注意,必须将kube-keepalived-vip项目拷贝到 $GOPATH/src 目录中,否则go会无视vendor目录,仍然去 $GOPATH/src 中去找依赖包)。

通过如上vendor解决了部分问题,然而又引起了新的问题:

  • vendor目录中依赖包没有版本信息。这样依赖包脱离了版本管理,对于升级、问题追溯,会有点困难。
  • 如何方便的得到本项目依赖了哪些包,并方便的将其拷贝到vendor目录下?依靠人工实在不现实。

为了解决这些问题,开源社区在vendor基础上开发了多个管理工具,比较常用的有godep、govendor glide等,go官方发布了dep。

godep

godep是解决包依赖的管理工具,原理是扫描记录版本控制的信息,并在go命令前加壳来做到依赖管理。godep早期版本并不依赖vendor,所以对go的版本要求很松,go 1.5之前的版本也可以用,只是行为上有所不同。在vendor推出以后,godep也改为使用vendor了。godep 建议在 golang 1.6 以后使用,且godep 依赖 vendor 。

godep的使用者众多,如docker,kubernetes, coreos等go项目很多都是使用godep来管理其依赖,当然原因可能是早期也没的 工具 可选。

go get -u -v github.com/tools/godep

通过如上的命令安装,成功安装后,在 $GOPATH 的bin目录下会有一个godep可执行的二进制文件,后面执行的命令都是用这个,建议这个目录加入到全局环境变量中。

编译运行

因为go命令是直接到GOPATH目录下去找第三方库,且在1.6以后支持vendor方式编译,而使用godep下载的依赖库放到Godeps/workspace目录下的,但是不影响继续使用依赖GOPATH目录,所以与三方工具本身不冲突。因此使用:

godep go build main.go

godep中的go命令,就是将原先的go命令加了一层壳,执行 godep go 的时候,会将当前项目的workspace目录加入GOPATH变量中。

检出依赖

如果要增加新的依赖包:

go get github.com/globalsign/mgo
import github.com/globalsign/mgo

项目编写好了,使用 GOPATH 的依赖包测试ok了的时候,执行:

godep save

如上的命令将会自动扫描当前目录所属包中import的所有外部依赖库(非系统库),并将所有的依赖库下来下来到当前工程中,产生文件 Godeps/Godeps.json 文件。

godep save 时godep把所有依赖包代码从GOPATH路径拷贝到Godeps目录下,并去除代码管理目录。这个用处主要是为了支撑godep go tool的一系列操作,尤其是git clone了代码库下来后,通常直接用godep go install xxx即可完成编译,一定程度上能够缓解golang比较严格的代码路径和包管理带来的烦恼。在没有 Godeps 文件的情况下,生成模组依赖目录vendor文件夹。如果是开发依赖使用三方库,需要固定使用某个版本,请完全提交Godeps和vendor文件夹。

依赖包会有更新,如何更新依赖包?可以通过如下的命令实现。

go get -u github.com/globalsign/mgo
godep update github.com/globalsign/mgo

拉取依赖 restore

通过命令 godep restore 同步依赖库,如果下载的项目中只有Godeps.json文件,而没有包含第三库则可以使用godep restore这个命令将所有的依赖库下来到 $GOPATH\src 中用于开发。

godep restore执行时,godep会按照Godeps/Godeps.json内列表,依次执行go get -d -v来下载对应依赖包到GOPATH路径下。

govendor

govendor是在vendor之后出来的,功能相对godep多一点,不过就核心问题的解决来说基本是一样的。该工具将项目依赖的外部包拷贝到项目下的 vendor 目录下,并通过 vendor.json 文件来记录依赖包的版本,方便用户使用相对稳定的依赖。

go get -u github.com/kardianos/govendor

如上的命令即可安装govendor,govendor生成vendor目录的时候需要2条命令:

  • govendor init生成vendor/vendor.json,此时文件中只有本项目的信息
  • govendor add +external更新vendor/vendor.json,并拷贝GOPATH下的代码到vendor目录中。
    govendor还可以直接指定依赖包版本来获取包。

govendor的依赖包主要有以下多种类型:

Go的包管理工具(一)

使用步骤

进入项目的根目录。

# 创建 vendor 文件夹和 vendor.json 文件
govendor init

# 从 $GOPATH 中添加依赖包,会加到 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功能更加丰富。

总结

本文主要介绍了几种go依赖包管理工具,首先介绍了go的环境安装,配置对应的环境变量;其次讲到包管理的两种类型:内部依赖和外部依赖的管理。内部依赖包的管理很简单,go原生的外部依赖包管理存在很多缺陷,随后介绍了开源社区推出的godep和govendor,在vendor基础上进行了功能的完善。还有目前常用的包依赖管理工具glide和官方的dep,将会在后面的文章介绍,尽请期待。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Trading and Exchanges

Trading and Exchanges

Larry Harris / Oxford University Press, USA / 2002-10-24 / USD 95.00

This book is about trading, the people who trade securities and contracts, the marketplaces where they trade, and the rules that govern it. Readers will learn about investors, brokers, dealers, arbit......一起来看看 《Trading and Exchanges》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换