前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Go的包管理工具(三):Go Modules

Go的包管理工具(三):Go Modules

作者头像
aoho求索
发布于 2019-05-07 10:28:42
发布于 2019-05-07 10:28:42
1.5K00
代码可运行
举报
文章被收录于专栏:aoho求索aoho求索
运行总次数:0
代码可运行

在前面的文章,我们先是介绍了Go 的几种包管理方式,然后具体介绍了一种包管理的工具:glide。随着 Go 1.11 的发布,官方的包管理工具 Go Modules 变得流行起来。在发布不久的 Go 1.12 版本中,增强了对 Go Modules 的支持。本文将会介绍如何在项目中安装和使用 Go Modules

安装和激活 Modules 的支持

前置条件

如本文开头所说,从 Go 1.11 版本才支持 Go Modules。所以,默认 Go 的版本为 >= 1.11。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ go version
go version go1.12 darwin/amd64

笔者安装了最新的 1.12 版本。

激活使用

安装后,我们可以通过以下两种方式之一激活模块支持:

  • $GOPATH/src 之外的目录中调用 go 命令,且当前目录或其任何父目录中使用有效的 go.mod 文件,并且环境变量 GO111MODULE 未设置(或显式设置为auto)。
  • 在环境变量集上设置 GO111MODULE = on 后,调用go命令。

如何定义模块

为当前的项目创建一个 go.mod 文件。

当项目不在 GOPATH 中,直接执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
go mod init

否则,会出现如下的错误:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'

因此,我们需要手动激活 Modules:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ export GO111MODULE=on 

然后才能执行 go mod init。这会将任何现有的dep Gopkg.lock 文件或其他九种支持的依赖关系转换,添加 require 语句以匹配现有配置。

go mod init通常能够使用辅助数据(例如VCS元数据)来自动确定相应的模块路径,但是如果 go mod init 表明它不能自动确定模块路径,或者如果你需要以其他方式覆盖 path,你可以提供模块路径作为 go mod init 的可选参数,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ go mod init modtest

构建模块

从模块的根目录执行时,./... 模式匹配当前模块中的所有包。 go build 将根据需要自动添加缺失或未转换的依赖项,以满足此特定构建调用的导入:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ go build ./...

测试模块

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ go test ./...

按配置测试模块,以确保它适用于所选版本。还可以运行模块的测试以及所有直接和间接依赖项的测试以检查不兼容性:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ go test all

实战

创建项目

创建项目并进入根目录:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ mkdir src/hello
$ cd src/hello

初始化

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ go mod init github.com/keets2012/hello
go: creating new go.mod: module github.com/keets2012/hello

go mod 初始化,并命名包名为 github.com/keets2012/hello。可以看到,一起创建了 go.mod 文件。

实现一个简单的方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ cat <<EOF > hello.go
package main

import (
    "fmt"
    "rsc.io/quote"
)

func main() {
    fmt.Println(quote.Hello())
}
EOF

我们创建了一个 hello.go 的文件,并输出调用的方法结果。

构建执行

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ go build   # 构建可执行文件
$ ./hello  # 执行

Hello, world.  # 输出结果

执行构建之后,得到可执行文件,我们执行了得到结果。 go.mod 文件已更新为包含依赖项的显式版本,其中 v1.5.2semver 标记:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ cat go.mod

module github.com/keets2012/hello

require rsc.io/quote v1.5.2

升级和降级依赖

应该使用 go get 来完成日常升级和降级依赖项,这将自动更新 go.mod 文件。 或者可以直接编辑 go.mod

此外,像 go buildgo test 或甚至 go list 这样的命令会根据需要自动添加新的依赖项以满足导入。

要查看所有直接和间接依赖项的可用 minor 和 patch 程序升级:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
go list -u -m all

要升级到当前模块的所有直接和间接依赖关系的最新版本:

  • 运行 go get -u 以使用最新的次要版本或补丁版本
  • go -u = patch使用最新的补丁版本

要升级或降级到更具体的版本,go get 允许通过在 package 参数中添加@version 后缀或“模块查询”来覆盖版本选择,例如 go get foo@v1.6.2go get foo @ e3702bed2,或者 go foo @'<v1.6.2'

semver

在上一小节,我们提到了 semver。golang 官方推荐的最佳实践叫做 semver,这是一个简称,写全了就是Semantic Versioning,也就是语义化版本。

语义化的定义

通俗地说,就是一种清晰可读的,明确反应版本信息的版本格式,更具体的规范在这里。

如规范所言,形如 vX.Y.Z 的形式显然比一串 hash 更直观,所以 golang 的开发者才会把目光集中于此。

为何使用语义化版本

semver 简化版本指定的作用是显而易见的,然而仅此一条理由显然有点缺乏说服力,通过semver对版本进行严格的约束,可以最大程度地保证向后兼容以及避免 “breaking changes”,而这些都是 golang 所追求的。两者一拍即合,所以 go modules 提供了语义化版本的支持。

如果你使用和发布的包没有版本 tag 或者处于 1.x 版本,那么你可能体会不到什么区别,因为 go mod 所支持的格式从始至终是遵循 semver 的,主要的区别体现在 v2.0.0 以及更高版本的包上。

“如果旧软件包和新软件包具有相同的导入路径,则新软件包必须向后兼容旧软件包。” - go modules wiki

相同名字的对象应该向后兼容,然而按照语义化版本的约定,当出现 v2.0.0 的时候一定表示发生了重大变化,很可能无法保证向后兼容,这时候应该如何处理呢?

答案很简单,我们为包的导入路径的末尾附加版本信息即可,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
module my-module/v2

require (
  some/pkg/v2 v2.0.0
  some/pkg/v2/mod1 v2.0.0
  my/pkg/v3 v3.0.1
)

格式总结为 pkgpath/vN,其中 N 是大于 1 的主要版本号。在代码里导入时也需要附带上这个版本信息,如import "some/pkg/v2"。这样包的导入路径发生了变化,也不用担心名称相同的对象需要向后兼容的限制了,因为 golang 认为不同的导入路径意味着不同的包。当然还有意外的情况:

  • 当使用gopkg.in格式时可以使用等价的require gopkg.in/some/pkg.v2 v2.0.0
  • 在版本信息后加上 +incompatible 就可以不需要指定 /vN ,例如:require some/pkg v2.0.0+incompatible

除此以外的情况如果直接使用 v2+ 版本将会导致 go mod 报错。

v2+ 版本的包允许和其他不同大版本的包同时存在(前提是添加了/vN),它们将被当做不同的包来处理。

另外 /vN 并不会影响你的仓库,不需要创建一个v2对应的仓库,这只是 go modules 添加的一种附加信息而已。

当然如果你不想遵循这一规范或者需要兼容现有代码,那么指定 +incompatible 会是一个合理的选择。不过 go modules 不推荐这种行为。

使用 vendor 目录

如果你不喜欢 go mod 的缓存方式,你可以使用 go mod vendor 回到 godep 或 govendor 使用的 vendor 目录进行包管理的方式。

当然这个命令并不能让你从godep之类的工具迁移到 go modules,它只是单纯地把 go.sum 中的所有依赖下载到 vendor 目录里,如果你用它迁移 godep 你会发现 vendor 目录里的包会和 godep 指定的产生相当大的差异,所以请务必不要这样做。

使用 go build -mod=vendor 来构建项目,因为在 go modules 模式下 go build 是屏蔽 vendor 机制的,所以需要特定参数重新开启 vendor 机制:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
go build -mod=vendor
./hello
hello world!

构建成功。当发布时也只需要和使用 godep 一样将 vendor 目录带上即可。

总结

本文主要介绍了 go modules的一些特性和使用方法, go modules 是官方的包管理工具,Go 语言通过引入 module 的概念进而引入了 Go tool 的另外一种工作模式 module-aware mode 。在新的工作模式下,module 支持包依赖的版本化管理。

新的工作模式也带来了一些问题,在大陆地区我们无法直接通过 go get 命令获取到一些第三方包,这其中最常见的就是 golang.org/x 下面的各种优秀的包。一旦工作在模块下,go build 将不再关心 GOPATH 或是 vendor 下的包,而是到 GOPATH/pkg/mod 查询是否有cache,如果没有,则会去下载某个版本的 module,而对于某些包的 module,在大陆地区往往会失败。我们将在下篇文章介绍 go module 的 proxy 配置实现。

推荐阅读

Go的包管理工具

订阅最新文章,欢迎关注我的公众号

微信公众号

参考
  1. Modules docs:https://github.com/golang/go/wiki/Modules
  2. https://www.cnblogs.com/apocelipes/p/10295096.html
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-03-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 aoho求索 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Go mod包依赖管理工具使用详解
对比上面几点: 目前做的最好的也就 maven了,gradle没有使用过,不知道。
OwenZhang
2021/12/08
9880
Go mod包依赖管理工具使用详解
Go Modules 详解
Go 1.11 和 Go 1.12 包含了初步的 Go Modules 支持,且计划在 2019 年 8 月发布的 Go 1.13 会在所有开发过程中默认使用 Go Modules。
码农编程进阶笔记
2021/07/20
8650
Go Modules 详解
go mod 命令详解
一个模块是 Go packages 的集合,定义在项目根目录下的 go.mod 文件。go.mod 文件定义了模块的路径,这也是使用当前项目中包的导入路径。go.mod 文件还定义了模块的依赖项,这些是项目成功构建所需的其他模块。每个依赖项都被编写为模块路径和特定的语义版本。
恋喵大鲤鱼
2023/12/30
2.1K0
跳出Go module的泥潭
Go 1.11 前天已经正式发布了,这个版本包含了两个最重要的feature就是 module和web assembly。虽然也有一些简单的教程介绍了go module的特性,但是基本上都是hello world的例子,在实践的过程中, 很多人都在“拼命的挣扎”,包括我自己, 从一些qq群、github的issue, twitter上都可以看到大家茫然或者抱怨的语句。
李海彬
2018/09/29
1.7K0
跳出Go module的泥潭
Go编程之相关命令工具记录
该命令可以借助代码管理工具通过远程拉取或更新代码包及其依赖包,并自动完成编译和安装,整个过程类似安装App一样;
全栈工程师修炼指南
2022/09/29
6240
Go包管理工具
想想Java的Maven, Nodejs的NPM,还有我们赞颂一万遍也不过分的Python包管理,为什么生命总要浪费在这些事情上面呢? 陷入了深深的沉思~~
happy123.me
2019/12/30
6890
石桥码农:如何在本地基于 nideshop 架设一个微信小程序商城?
本文主要基于 nideshop 和 moshopserver 构建,在本地构建,mysql可以用本地的,也可以用云上的。这个项目的意义,主要在于自己学习和研究小程序商城项目的开发。
LIYI
2020/02/13
2.4K0
石桥码农:如何在本地基于 nideshop 架设一个微信小程序商城?
Go的包管理工具(三):Go Modules
在前面的文章,我们先是介绍了Go 的几种包管理方式,然后具体介绍了一种包管理的工具:glide。随着 Go 1.11 的发布,官方的包管理工具 Go Modules 变得流行起来。在发布不久的 Go 1.12 版本中,增强了对 Go Modules 的支持。本文将会介绍如何在项目中安装和使用 Go Modules 。
aoho求索
2019/05/07
1.5K0
使用 Go Modules 管理依赖
Go Modules 是 Go 语言的一种依赖管理方式,该 feature 是在 Go 1.11 版本中出现的,由于最近在做的项目中,团队都开始使用 go module 来替代以前的 Godep,Kubernetes 也从 v1.15 开始采用 go module 来进行包管理,所以有必要了解一下 go module。go module 相比于原来的 Godep,go module 在打包、编译等多个环节上有着明显的速度优势,并且能够在任意操作系统上方便的复现依赖包,更重要的是 go module 本身的设计使得自身被其他项目引用变得更加容易,这也是 Kubernetes 项目向框架化演进的又一个重要体现。
田飞雨
2019/12/20
1K0
Go的包管理工具(四):Go Module Proxy
在前面的文章,我们介绍了Go Modules。Go module支持了Versioned Go,并初步解决了包依赖管理的问题。
aoho求索
2019/05/07
2.1K0
Go的包管理工具(四):Go Module Proxy
Go Module详细使用教程,包管理不在难
go modules是 golang 1.11引入的新特性。模块是相关Go包的集合。modules是源代码交换和版本控制的单元。go命令直接支持使用modules,包括记录和解析对其他模块的依赖性。modules替换旧的基于GOPATH的方法来指定在给定构建中使用哪些源文件。
公号:咻咻ing
2020/03/04
20.5K0
Go 编程 | 连载 21 - Go Modules 和 Package
GOPATH 是 Go 语言中使用的一个环境变量,它使用绝对路径提供项目的共工作目录,GOPATH 适合处理大量 Go 语言源码、多个包组合而成的复杂工程。
RiemannHypothesis
2022/09/28
5200
Go——依赖管理
在Go1.5 release的版本的发布vendor目录被添加到除了GOPATH和GOROOT之外的依赖目录查找的解决方法。 查找依赖包路径的解决 当前包下的vendor目录 先上级的目录查找,直到找到scr的vendor目录 在GOPATH下面查找依赖包 在GOROOT目录下查找
羊羽shine
2019/05/29
1.4K0
Go依赖管理——Go Mod
module简介 在 go1.12,go发布了官方的包管理工具 Go Module 使用module 生成go.mod 新建一个文件夹作为项目目录,执行 go mod init 模块名称 使用mod初始化项目,生成项目依赖管理文件go.mod 这个文件也可以手动创建,无伤大雅 初始化后的go.mod文件内容如下 module test go 1.14 添加依赖 通过在go.mod中,添加require语句,导入依赖,如 require golang.org/x/text v0.3.0 require g
歪歪梯
2020/10/26
2.1K0
Go Modules:Go语言依赖管理的新篇章
自从Go 1.11版本引入以来,Go Modules 已经成为了Go语言依赖管理的标准。接下来,我将用简单易懂的语言,带你一步步了解Go Modules的安装、使用和最佳实践。
南山竹
2024/06/06
4110
Go Modules:Go语言依赖管理的新篇章
Golang Module的使用 顶
注意:go mod 还有一些其他比较有意思的工具,比如可以打印依赖树,比如可以查看哪些模块在哪些包引用了
BGBiao
2019/09/09
1.3K0
Go | 浅谈包管理模式
go的编译器会在 $GOPATH/src 下面寻找对应的模块,src 下的每一个目录都可以对应一个模块,目录中的目录也可以是一个模块
甜点cc
2022/11/16
5310
Go | 浅谈包管理模式
Go Modules 终极入门
Go modules 是 Go 语言中正式官宣的项目依赖解决方案,Go modules(前身为vgo)于 Go1.11 正式发布,在 Go1.14 已经准备好,并且可以用在生产上(ready for production)了,Go 官方也鼓励所有用户从其他依赖项管理工具迁移到 Go modules。
madneal
2020/03/10
1.9K0
Go Modules 终极入门
Golang学习笔记,从入门到精通,持续记录
Golang官网:https://go.dev/、Golang下载:https://go.dev/、Golang学习文档:https://go.dev/doc/
房东的狗丶
2023/02/17
1.3K0
GO 依赖管理工具go Modules(官方推荐)
以前写过一篇关于go管理依赖包工具 dep的文章,当时认为dep将会成为官方依赖工具,现在看来是自己图样图斯内幕破了,正如官方一直提到dep是“official experiment”官方实验项目的那样,随着go modules 在go1.11版推出,go1.12版功能不断改进,再到go1.13版完善优化,正式扶正。预计dep将来也只能定格在“official experiment”了。
孤烟
2020/09/27
1.8K1
相关推荐
Go mod包依赖管理工具使用详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验