golang包管理解决之道——go modules初探
golang的包管理是一直是为人诟病之处,从golang1.5引入的vendor机制,到准官方工具dep,目前为止还没一个简便的解决方案。
不过现在go modules随着golang1.11的发布而和我们见面了,这是官方提倡的新的包管理,乃至项目管理机制,可以不再需要GOPATH的存在。
go module的初始化
现在modules机制仍在早期阶段,所以golang提供了一个环境变量“GO111MODULE”,默认值为auto,如果当前目录里有go.mod文件,就使用go modules,否则使用旧的GOPATH和vendor机制,因为在modules机制下go get只会下载go modules,这一行为会在以后版本中成为默认值,这里我们保持auto即可,如果你想直接使用modules而不需要从GOPATH过度,那么把“GO111MODULE”设置为on。
modules和传统的GOPATH不同,不需要包含例如src,bin这样的子目录,一个源代码目录甚至是空目录都可以作为module,只要其中包含有go.mod文件。
我们就用一个空目录来创建我们的第一个module:
要初始化modules,需要使用如下命令(假设已经安装配置好golang1.11):
go mod init [module name]
我们的module叫test,所以就是:
go mod init test
初始完成后会在目录下生成一个go.mod文件,里面的内容只有一行“module test”。
包管理
那么我们怎么进行包管理呢?别担心,当我们使用go build,go test以及go list时,go会自动得更新go.mod文件,将依赖关系写入其中。
如果你想手动处理依赖关系,那么使用如下的命令:
go mod tidy
这条命令会自动更新依赖关系,并且将包下载放入cache。
下面我们使用chromedp的一个简单example作为实验代码main.go,看下go modules是如何处理包的依赖关系的。
我们手动运行go mod tidy:

查找并下载包

我们发现多了一个go.sum,我们看看它里面是什么内容:

没错,你已经猜到了,这是我们直接引用的package和它自身需要的以来的版本记录,go modules就是根据这些去找到需要的packages的。
顺带一提,如果我们不做任何修改,默认会使用最新的包版本,如果包打过tag,那么就会使用最新的那个tag对应的版本。
下面我们使用go build来编译我们的代码:
go build
值得注意的是,新增了一个编译选项“-mod”,它有如下的可选值:
go build -mod=readonly
在这个模式下任何会导致依赖关系变动的情况都将导致build失败,前面提到过build能查找并更新依赖关系,使用这个选项可以检查依赖关系的变动。
go build -mod=vendor
意思是忽略cache里的包,只使用vendor目录里的版本。
构建完成后目录结构如下:

我们的代码成功构建了,包管理都由go modules替我们完成了。
包的版本控制
包管理的另外一项重要功能就是包的版本控制。modules同样可以做到。
在介绍版本控制之前,我们要先明确一点,如果上层目录和下层目录的go.mod里有相同的package规则,那么上层目录的无条件覆盖下层目录,目的是为了main module的构建不会被依赖的package所影响。
那么我们看看go.mod长什么样:
module test require github.com/chromedp/chromedp v0.1.2
如果有多个依赖,可以是这样的:
module github.com/chromedp/chromedp require (
github.com/chromedp/cdproto v0.0.0-20180713053126-e314dc107013
github.com/disintegration/imaging v1.4.2
github.com/gorilla/websocket v1.2.0
github.com/knq/sysutil v0.0.0-20180306023629-0218e141a794
github.com/mailru/easyjson v0.0.0-20180606163543-3fdea8d05856
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81
)
前面部分是包的名字,也就是import时需要写的部分,而空格之后的是版本号,版本号遵循如下规律:
vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef
vX.0.0-yyyymmddhhmmss-abcdefabcdef
vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef
vX.Y.Z
也就是版本号+时间戳+hash,我们自己指定版本时只需要制定版本号即可,没有版本tag的则需要找到对应commit的时间和hash值。
默认使用最新版本的package。
现在我们要修改依赖关系了,我们想使用chromedp 的v0.1.0版本,怎么办呢?
只需要如下命令:
go mod edit -require="github.com/chromedp/chromedp@v0.1.0"
@后面加上你需要的版本号。go.mod已经修改了:
module test require github.com/chromedp/chromedp v0.1.0
我们还需要让go modules更新依赖关系,这里我们手动go mod tidy之后:

注意颜色较深的那两行,我们已经切换到了v0.1.0版本了。
go modules是一个很大的主题,以后我还将进一步介绍它。
如果想进一步深入go modules的使用,可以阅读我的这篇文章:再探go modules:使用与细节
因为go1.11刚发布不久,这篇文件作为探路,必定会有错误和疏漏,欢迎大家指正!
golang包管理解决之道——go modules初探的更多相关文章
- golang包管理工具
软件开发中,不可避免的会使用到第三方库,因此包管理工具可以极大的方便开发者管理第三方依赖,避免掉入"依赖地狱". 作为google强大背书的golang语言,golang官方包管理 ...
- Golang 包管理机制
Golang 包管理机制 1. 历史 在go1.11之前, 并没有官方的包管理机制(Godep算个半官方), 主流的包管理机制有: GoVendor Glide Godep 在go1.11之后, 官方 ...
- golang包管理的古往今来
https://golang.org/ before GO1.5-GOPATH 在GO1.5之前用GOPATH以及GOROOT这两个环境变量来决定包的位置. GOROOT就是告知当前go的安装位置,编 ...
- Golang 包管理简介
Golang 包管理 在一个项目里,如果想引用本地包,经常会把新手搞的莫名其妙.这里通俗记录一下. 首先先要知道几个默认的规则 必须定义环境变量GOPATH,GOPATH可以定义多个目录 所有项目代码 ...
- Golang包管理工具glide简介
Golang包管理工具glide简介 前言 Golang是一个十分有趣,简洁而有力的开发语言,用来开发并发/并行程序是一件很愉快的事情.在这里我感受到了其中一些好处: 没有少了许多代码格式风格的争论, ...
- golang包管理的取巧
常见的golang的包管理工具 glide 使用yaml做配置,语义化版本管理,可以设置镜像,下载x系列库,但是x系列库被第三方库依赖时会出现下载失败. dep 亲儿子,语义化版本管理,无法解决墙 v ...
- window下golang包管理glide使用说明
golang是一门简洁高效的开发 语言,但是包管理一直是一个痛点,如图 : 很多开源项目特别是github.com中的大量应用golang.org和google.golang.org中的源码,且由于被 ...
- Glide Golang包管理
Golang的包管理乱得不行,各种工具横空出世,各显神通啊.用了几个下来,发现 Glide 是比较好用的,使用了 vender 来进行管理,多个开发环境的版本不冲突,功能强大,配置文件也足够简单. 初 ...
- golang包管理工具及环境管理工具;如何下载外网的依赖包
简介: golang的包管理工具类似于java的maven.python的pip.js的npm,可以实现依赖包的统一管理:有很多:govendor.godep.glide,挑一个自己喜欢的用吧.mac ...
随机推荐
- python_flask项目(BBS)_01
项目文件用途说明: config.py , 此文件主要存储一些配置信息,如数据库连接串.debug模式串等. exts.py , 此文件装载第三方库实例对象,如sqlalchemy ...
- android:动态申请权限(一)
环境: android版本6.0 对应SDK版本23 动态申请权限说明:所有动态申请的权限,必须在AndroidManifest.xml中进行声明 步骤 1.新建一个android工程 默认创建即可 ...
- mysql5.6版本的优化
1. 目标 l 了解什么是优化 l 掌握优化查询的方法 l 掌握优化数据库结构的方法 l 掌握优化MySQL服务器的方法 2. 什么是优化? l 合理安排资源.调整系统参数使MySQL运行更快.更节省 ...
- Spark Programming--- Shuffle operations
*:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...
- Akka-CQRS(0)- 基于akka-cluster的读写分离框架,构建gRPC移动应用后端架构
上一篇我们讨论了akka-cluster的分片(sharding)技术.在提供的例子中感觉到akka这样的分布式系统工具特别适合支持大量的带有内置状态的,相对独立完整的程序在集群节点上分布运算.这里重 ...
- 吴恩达机器学习笔记45-使用支持向量机(Using A SVM)
本篇我们讨论如何运行或者运用SVM. 在高斯核函数之外我们还有其他一些选择,如:多项式核函数(Polynomial Kernel)字符串核函数(String kernel)卡方核函数( chi-squ ...
- 吴恩达机器学习笔记18-多类别分类:一对多(Multiclass Classification_ One-vs-all)
对于之前的一个,二元分类问题,我们的数据看起来可能是像这样: 对于一个多类分类问题,我们的数据集或许看起来像这样: 我用3 种不同的符号来代表3 个类别,问题就是给出3 个类型的数据集,我们如何得到一 ...
- 聊一聊PHP的global
众所周知,在PHP的函数中,如果想使用全局变量,一种是使用超全局变量$GLOBALS,另一种是在函数中使用global关键字声明,使用超全局变量$GLOBALS的方式大家都知道了,今天来好好聊一聊使用 ...
- #Java学习之路——基础阶段(第一篇)
我的学习阶段是跟着CZBK黑马的双源课程,学习目标以及博客是为了审查自己的学习情况,毕竟看一遍,敲一遍,和自己归纳总结一遍有着很大的区别,在此期间我会参杂Java疯狂讲义(第四版)里面的内容. 前言: ...
- python(leetcode)-344反转字符串
编写一个函数,其作用是将输入的字符串反转过来.输入字符串以字符数组 char[] 的形式给出. 不要给另外的数组分配额外的空间,你必须原地修改输入数组.使用 O(1) 的额外空间解决这一问题. 你可以 ...