依赖管理
为什么需要依赖管理
早期,Go所依赖的三方库都在GOPATH
这个目录下面,这就导致同一个三方库职能保存一个版本,如果不同项目依赖不同版本的三方库,怎么解决?
godep
Go语言从v1.5开始引入vendor
模式,如果项目目录下面有vendor目录,那么go工具链回优先使用vendor
内的包进行编译、测试等,作用用途类似前端的npm包管理工具。
安装
执行下面的命令安装godep
工具:
go get github.com/tools/godep 复制代码
基本命令
安装完毕以后,在终端输入godep
查看支持的所有命令:
godep save 将依赖项输出并复制到Godeps.json文件中 godep go 使用保存的依赖项运行go工具 godep get 下载并安装具有指定依赖项的包 godep path 打印依赖的GOPATH路径 godep restore 在GOPATH中拉取依赖的版本 godep update 更新选定的包或go版本 godep diff 显示当前和以前保存的依赖项集之间的差异 godep version 查看版本信息 复制代码
使用godep
在项目目录下执行godep save
命令,我这里遇到了一个错误:
godep: [WARNING]: godep should only be used inside a valid go package directory and godep: [WARNING]: may not function correctly. You are probably outside of your $GOPATH. godep: [WARNING]: Current Directory: /Users/hometown/Desktop/golang-project/hello godep: [WARNING]: $GOPATH: /Users/hometown/stduy/go godep: Unable to find SrcRoot for package . 复制代码
错误原因大致是说:
godep只能在有效的go软件包目录中使用 可能无法正常工作。你可能在$GOPATH之外 复制代码
所以我得出了一个结论:当用godep
去管理项目依赖的时候,必须在GOPATH
的src目录下的项目中执行。
回到指定目录重新执行,生成了一个Godeps
和vender
两个文件夹。
Godeps
文件夹下有一个Godeps.json
的文件,记录项目依赖的包信息(类似package.josn
)。
vender
文件夹下是项目依赖的包的源代码文件(类似node_modules
)。
vender机制
控制Go语言程序编译时依赖包搜索路径的优先级。
例如查找项目的某个依赖包,首先会在项目根目录下的vender
文件夹下查找,如果没有找到就回去$GOPATH/src
目录下查找,类似(去项目中的node_modules
中找,如果没有找到,就去golbal node_modules
中找)。
godep开发流程
- 保证程序能够正常编译
- 执行
godep save
保存当前项目的所有第三方依赖版本信息和代码 - 提交Godeps目录和vender目录到代码库
- 如果要更新依赖的版本,可直接修改
Godeps.json
文件中的对应项
go module
go module
是Go1.11版本之后官方推出的版本管理工具,并且从GO1.13版本开始,go module
将是Go语言默认的依赖管理工具。
GO111MODULE
要启用go module
需要设置环境变量GO111MODULE
,有三个可选值off
、on
、auto
,默认是auto
。
- off --> 禁用模块支持,编译时从
GOPATH
&vender
文件夹中找包。 - on ---> 启用模块支持,编译时会忽略
GOPATH
&vender
文件夹,只根据go.mod
下载依赖。 - auto ---> 当项目在
$GOPATH/src
外且项目根目录有go.mod
文件时,开启模块支持
简单来说,设置GO111MODULE=on
之后就可以使用go module
了,以后就没有必要在GOPATH中创建项目了,并且还能够很好的管理项目依赖的第三方包信息。
go mod 命令
go mod download 下载依赖的module到本地cache(默认为$GOPATH/pkg/mod 目录) go mod edit 编辑go.mod文件 go mod graph 打印模块依赖图 go mod init 初始化当前文件夹,创建go.mod文件 go mod tidy 增加缺少的module,删除无用的module go mod vendor 将依赖复制到vendor下 go mod verify 校验依赖 go mod why 解释为什么需要依赖 复制代码
go mod
module hello go 1.17 require ( github.com/kr/fs v0.1.0 // indirect github.com/kr/pretty v0.3.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/tools/godep v0.0.0-20180126220526-ce0bfadeb516 // indirect golang.org/x/tools v0.1.9 // indirect ) 复制代码
- module 是包名
- require 用来定义依赖包及版本
- indirect 表示间接引用
go get
go get
下载依赖
go get -u
升级到最新的次要版本或者修订版本go get -u=patch
升级到最新的修订版本go get 包名@版本
升级到指定版本号
go mod tidy
删除依赖代码后,相关依赖库不会自动从go.mod
文件中删除,执行go mod tidy
更新go.mod
中的依赖关系(类似更新package.json
执行npm uninstall xxx
)
项目中使用go module
现有项目
- 在项目目录下执行
go mod init
生成 go.mod 文件 - 执行
go get
,查找并记录当前项目的依赖,同时生成go.sum
记录每个依赖库的版本和哈希值
新项目
- 执行
go mod init 项目名
- 手动编辑
go.mod
或中的require依赖项或者go get
自动发现。
使用go module导入本地包
导入本地包的时候碰到了一个问题,报错如下:
package xxx is not in GOROOT 复制代码
这是因为GOROOT
下面没有这个包,Go引入包的方式两种GOPATH
&go mod
,go mod
引入包,开头以项目根目录执行go mod init 项目名
的这个项目名开头(也是go.mod的module 名)。
解决了上面的问题以后就可以执行go run main.go
执行成功了。
我这写了一个demo:
/main.go
package main import ( "fmt" "moduledemo/mypackage" ) func main() { mypackage.DoSomething() fmt.Println("你好帅哥") } 复制代码
/mypackage/mypackage.go
package mypackage import "fmt" func DoSomething() { fmt.Println("做点啥啊?Do something??") } 复制代码
/hispackage/hispackage.go
package hispackage import "fmt" func DoSomething() { fmt.Println("他不做") } 复制代码
执行成功!
遇到了一个新的问题,就是虽然可以执行成功,但是Goland标红,是因为编辑器没有配置(很无语),打开这个设置即可:
过程中还手动开启了GO111MODULE