引言

如果想要在项目中使用第三方代码库,C/C++ 中一般会有两种方法,

1. 将第三方源码合并到自己的工程文件中直接编译;

2. 将第三方代码先编译生成静态链接库(.a、.lib)或动态链接库(.so 、.dll) 放到工程目录下,然后通过条件编译直接使用。

目前大多数主流语言都有一套标准的包管理解决方案,比如 Java 有 maven,Python 有 pip,Ruby 有 RubyGems,Rust 有 Cargo,Nodejs 有 npm,PHP 有 composer。包管理工具用于自动化构建代码,以及使用一致的方式下载、更新和删除项目依赖项。

omposer.json composer.json omposer.json/package.json omposer.json,composer.json,

那么,Go 的包依赖管理呢?

正文

在 Go 语言早期的版本,包依赖管理是缺失的,后面也经历了一些混乱的时代。

根据 Go 的历史发布版本,Go 的包管理大致分成以下几个时间点和阶段,

go 尚未正式发布,goinstall(2010.02)

go 1,go get(2011.12)

go 1.2.1,gopkg.in(2014.03)

go 1.5,vendor 目录(2015.06)

go 1.8.3,官方出品 golang/dep(2017.05)

go 1.11,go module(2018.08)

go 1.13,go module 的改进(2019.08)

Golang 的包管理有两个特点,一个是去中心化,包的仓库可以是任意的代码仓库;一个是三方代码库跟项目代码本身耦合在一起,这个也是 Golang 推荐的工作方式。

在安装好 Go 后,配置环境变量时,可以选择性配置 GO111MODULE。比如

export GO111MODULE=auto

注意,这个变量是 Go 1.11 推出的,之后 Go 的不同版本,这个环境变量有不同的值含义。

如果 go mod 状态没有打开,可以使用 go env 找到自己的 GOPATH,在 GOPATH 下建立 src 目录,在 src 下建立自己的项目。这时记住一句话就行了,Go 找包都是去 GOPATH 下的 src 目录下找的,项目一定放在 GOPATH 的 src 目录下。一般 bin 和 pkg 目录可以不创建,go命令会自动创建(如 go install),只需要创建src目录即可,不过最好创建一下。

高版本的 Go 一般自带 go mod,go mod 是比 GOPATH 更新的一种 Go 包管理方式,使用了 go mod 后,就不需要把项目放在 GOPATH 下,Go 也能找到了。

当然,GOPATH 和 go mod 可以共存。

当 modules 功能启用时,依赖包的存放位置变更为 $GOPATH/pkg,允许同一个 package 多个版本并存,且多个项目可以共享缓存的 module。

使用 go mod 管理包

go mod 命令

go mod init 初始化一个项目

go mod download 下载依赖包,依赖包会自动下载到 $GOPATH/pkg/mod,多个项目可以共享缓存的mod

go mod tidy 拉取缺少的模块,移除不用的模块

go mod verify 验证依赖是否正确

go mod vendor 从mod中拷贝到项目的vendor目录下,这样IDE就可以识别了

go mod why 解释为什么需要依赖

go mod 为项目引入依赖

执行 go mod init 命令,初始化一个项目,会在项目根目录下生成 go.mod 文件。

go mod init github.com/project

go.mod 提供了 module、require、replace 和 exclude 四个命令。

modulerequirereplaceexclude
假如需要引入 protobuf,添加 require,可以手动修改 go.mod 文件require,可以手动修改 go.mod 文件最好使用 go get 命令(不同的 Go 版本,go get的行为会有不同,一般最好使用 go get 命令(不同的 Go 版本,go get的行为会有不同,一般)。)。
// 手动修改 eg.
go mod init .
go mod edit -require github.com/golang/protobuf@1.5.0` 
go get -v -t ./...   
go build
go install 
注意,如果在后续模块代码编写时 import 了该模块,但没有在 go.mod 中引用它,在执行 go build 时就会报错,但注意,如果在后续模块代码编写时 import 了该模块,但没有在 go.mod 中引用它,在执行 go build 时就会报错,但
go get github.com/golang/protobuf
或
go get github.com/golang/protobuf@v1.5.0

这条命令执行完之后,在 go.mod 中会添加如下语句,同时生成 go.sum 文件,依赖包被下载到 $GOPATH/pkg/mod 中。这时就可以在项目中使用了。go get 指定版本_29. 系统学习 Go语言命令_weixin_39611043的博客-CSDN博客

go.mod(通过这个文件管理包)

go.sum 文件(一般不需要手工维护)

包含特定模块版本内容的预期加密哈希,Go 命令使用 go.sum 文件确保这些模块的未来下载检索与第一次下载相同的位,以确保项目所依赖的模块不会出现意外更改,无论是出于恶意、意外还是其他原因。 go.mod 和 go.sum 都应检入版本控制。 

注意:子目录里是不需要 init 的,所有的子目录里的依赖都会组织在根目录的 go.mod 文件里。

如果要在 IDE 中查看,还需执行 go mod vendor

go mod vendor

go mod vendor 还有一个作用,一般第三方依赖库(包括公司内网 GitLab 上的依赖库),其源码都不被包含在我们的项目内部,而是在编译的时候 Go 连接公网、内网下载到本地 GOPATH,然后编译。问题是,有时候需在无公网、无内网(无法连接内网 GitLab)的情况下编译 go 项目,或者由于种种原因,比如

  1. 防止依赖库因为某种原因被删除、移动,导致找不到依赖并编译失败;
  2. 对新手来说,下载一些墙外的依赖可能略有困难;

该如何做呢?在此时,需使用 go mod vendor 将项目的依赖库下载到项目内部,作为项目的一部分来编译。

Have Fun