Go语言学习笔记-依赖管理

502 阅读6分钟

编程语言大多都有依赖管理方面的工具,比如 Java 的 Maven、Gradle ,Javascript 的 npm,Python 的pip。

Go 也有这方面的工具,不过由于历史原因,这方面挺乱的。

GOROOT

GOROOT 是用来告知 Go 当前的安装位置的,这个环境变量不是必须设置的,

Go 默认就是安装在 /usr/local/go 目录下。

当 Go进行编译的时候,SDK 的 system libariry 库就是在这个目录下寻找。

GOPATH

GOPATH 的目的是为了告知 Go,当需要代码的时候,去哪里查找。

这里的代码,其实就是 package ,包括本项目和引用外部项目的代码。

GOPATH可以随着项目的不同而重新设置。

这个环境变量必须设置。

一般会设置两个 GOPATH 。

第三方的 libairy 就下到第一个 GOPATH ,而自己的项目就放在第二个 GOPATH 。

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

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

vendor

GOPATH 有个问题,就是当项目导入的包,改了或者删了,那代码的编译自然就无法通过。

之所以会造成这样的情况,应该跟 Google 大部分代码就放在一个大仓库里有关,在 Google 的代码仓库里没有发生这种问题的环境。

为了解决这个问题,官方引入了 vendor属性

go在1.5版本引入了vendor属性 (默认关闭,需要设置go环境变量GO15VENDOREXPERIMENT=1), 并在1.6版本中默认开启了vendor属性。

这个 vendor 实际上就是项目根目录的一个 vendor 目录

在编译的时候优先在 vendor 下寻找依赖,找不到再去 GOPATH 下寻找依赖,

如果复制一份到这个目录下,这样以后编译就不怕 GOPATH 的依赖出现变动了 。

这个时候进行编译时寻找依赖的顺序就成了: vendor -> GOPATH -> GOROOT

vendor目录还有一些问题:

  • 没有版本管理
  • 项目依赖的包,需要手动复制到 vendor 目录

社区在 vendor 基础上开发了多个管理工具。

常用的如下:

  • godep
  • glide
  • govendor

官方也开发了一个管理工具:dep ,到现在(2019-08-31)都还没有 release 版本。。。

modules

modules 是 Go v1.11 引入的 依赖管理feature 。

目前该功能默认关闭,到下一个版本 v1.13 将默认开启。

别的不说,总算是有官方的版本管理了,只是苦了之前社区那些工具的开发者。

我是这两天开始才开始学习的 Go,现在是 Go v1.12.9 ,主要记录一下 modules 。

modules官方定义:

模块是相关Go包的集合。modules是源代码交换和版本控制的单元。 go命令直接支持使用modules,包括记录和解析对其他模块的依赖性。modules替换旧的基于GOPATH的方法来指定在给定构建中使用哪些源文件。

Go 为了保持兼容,目前一个项目想要使用 modules 需让项目存放在非 GOPATH/src 目录下。

使用

依赖包的存放位置变更为 $GOPATH/pkg ,多个项目可以共享 package,省硬盘!

设置 GO111MODULE

GO111MODULE 有三个值:off, onauto(默认值)

  • GO111MODULE=off,go 命令行将不会支持 module 功能,寻找依赖包的方式将会沿用旧版本那种通过 vendor 目录或者 GOPATH 模式来查找。

  • GO111MODULE=on,go命令行会使用 modules,而一点也不会去 GOPATH 目录下查找。

  • GO111MODULE=auto,默认值,go 命令行将会根据当前目录来决定是否启用 modules 功能。

GO111MODULE=auto 的判断可以分两种情况:

  • 当前目录在GOPATH/src之外且该目录包含go.mod文件

  • 当前文件在包含go.mod文件的目录下面。

go mod

Go 提供了 go mod 命令来管理包。

可以使用 go help mod 查看各种参数的作用。

初始化项目

想要使得一个项目变成 mod 项目 ,可以执行 go mod init

go mod init 本模块的路径 //初始化生成go.mod 文件

go.mod文件一旦创建后,它的内容将会被go toolchain全面掌控。go toolchain会在各类命令执行时,比如go get、go build、go mod等修改和维护go.mod文件。

go.mod 语法 :

  • module 本模块的路径,所有本模块下的包共享这个路径前缀
  • require 指定的项目需要的依赖模块,模块遵循语义化版本
  • replace 替换 import 模块的路径
  • exclude 排除某个模块,使之不能被 import

go.sum

当下载依赖包,并把依赖信息添加到 go.mod 文件中,同时把依赖版本哈希信息存到 go.sum 文件中:

//go.sum
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
github.com/Anderson-Lu/gofasion v0.0.0-20190530065914-6a05b679ee48 h1:Y0um3nHCQDleEpQzahJAkT8mvKTlLqvjoIqZYIAJgAw=
github.com/Anderson-Lu/gofasion v0.0.0-20190530065914-6a05b679ee48/go.mod h1:nJfnu9e1b/lczgULa3laeoUzeadR3ylEgYj8zpXO+Wc=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=

go.sum 作用:当编译的时候,校验引入的依赖和上一次引入的依赖是不是同一个依赖。

升级版本

假设当前一个依赖的版本为 v1.0.0,那我们升级依赖有两种方式: 1. 使用 go get, 运行 go get,如果有版本的更改,那么 go.mod 文件也会更改

  • 运行 go get -u 将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号)
  • 运行 go get -u=patch 将会升级到最新的修订版本
  • 运行 go get package@version 将会升级到指定的版本号

go mod 命令

go mod edit -require="package@version"

go mod tidy

go mod edit -require 可以主动修改 go.mod 文件中依赖的版本号,然后通过 go mod tidy 对版本进行更新。

go mod tidy: 它会自动清理掉不需要的依赖项,同时可以将依赖项更新到当前版本。

可能发生的问题

依赖无法下载

使用 go modgo get 的时候,可能会因为一些特殊原因,无法下载需要的一些依赖。

解决方法:

1.设置 GOPROXY 环境变量

set GOPROXY=“https://goproxy.io”

点击了解goproxy.io

2.给 git 配置代理

因为拉取 git 项目, go get 底层也是使用的 git 命令。

相应的,我们可以给当前项目配置一下 git config

  • http代理
git config --global https.proxy http://127.0.0.1:1080

git config --global https.proxy https://127.0.0.1:1080

git config --global --unset http.proxy

git config --global --unset https.proxy
  • socks代理
git config --global http.proxy 'socks5://127.0.0.1:1080'

git config --global https.proxy 'socks5://127.0.0.1:1080'

git config --global --unset http.proxy

git config --global --unset https.proxy