• Golang依赖管理(GOPATH->vendor->Go Module)


    参考 https://docs.kilvn.com/GoExpertProgramming/chapter12/

    Go依赖管理历程

    Go依赖管理经历了三个重要的阶段:

    • GOPATH;
    • vendor;
    • Go Module;

    下面依次介绍这三个方法

    GOPATH

    环境变量GOROOT&GOPATH

    安装完golang1.13后,有两个路径GOROOT和GOPATH。

    使用命令 go env 查看这两个路径:

    GOROOT="/usr/local/go"
    GOPATH="/home/zhanhzhong/go"
    
    • 1
    • 2

    实际上Go语言项目是由一个或多个package组成的,这些package按照来源分为以下几种:

    • 标准库
    • 第三方库
    • 项目私有库

    其中标准库的package全部位于GOROOT环境变量指示的目录中,而第三方库和项目私有库都位于GOPATH环境变量所指示的目录中。

    第三方库和自己写的项目都需要放在GOPATH的src目录下,而且需要使用go get命令来逐个下载第三方库(go get命令自动把第三方库下载到GOPATH/src目录)。

    依赖查找

    当某个package需要引用其他包时,编译器就会依次在下面的目录查找

    • GOROOT/src/
    • GOPATH/src/

    如果某个包从GOROOT下找到的话,就不再到GOPATH目录下查找,所以如果项目中开发的包名与标准库相同的话,将会被自动忽略。

    GOPATH的缺点

    GOPATH的优点是足够简单,但由于不同项目的第三方库都存放在同一个目录下,而且同一个依赖库只能存放某一个版本,不能同时存放多个版本,因此不能很好的满足实际项目的工程需求。

    比如,你有两个项目A和B,他们都引用某个第三方库T,但这两个项目使用了不同的T版本,即:

    • 项目A 使用T v1.0
    • 项目B 使用T v2.0

    由于编译器依赖查找固定从GOPATH/src下查找GOPATH/src/T,所以,无法在同一个GOPATH目录下保存第三方库T的两个版本。当某一个项目的一个依赖库无法使用特定的版本时,就有可能会出错,导致出现”在我的开发机上明明没问题,为什么到你开发机上就出问题了“的情况。

    针对GOPATH的缺点,GO语言社区提供了Vendor机制,从此依赖管理进入第二个阶段:将项目的依赖包私有化。

    vendor

    自Go 1.6版本起,vendor机制正式启用,它允许把项目的依赖全部放到一个位于本项目的vendor目录中,这个vendor目录可以简单理解成私有的GOPATH目录。(但是vendor放进项目目录也会导致它随着git上传到远端,比较臃肿)

    依赖查找

    编译时,优先从vendor中寻找依赖包,如果vendor中找不到再到GOPATH中寻找。顺序如下

    • Main.go所在目录下的vendor目录
    • 再上一个层级的目录下的vendor目录
    • GOROOT/src/
    • GOPATH/src/

    可见一个项目里可以有多个vendor目录,但是一般建议只集中维护一个vendor目录。

    vendor的缺点

    vendor很好的解决了多项目间的隔离问题,但是位于vendor中的依赖包无法指定版本,某个依赖包,在把它放入vendor的那刻起,它就固定在当时版本,项目的其他开发者很难识别出你所使用的依赖版本。

    比起这个,更严重的问题是二进制急剧扩大问题,比如你依赖某个开源包A和B,但A中也有一个vendor目录,其中也放了B,那么你的项目中将会出现两个开源包B。再进一步,如果这两个开源包B版本不一致呢?如果二者不兼容,那后果将是灾难性的。

    一直到Go 1.11版本,官方社区推出了Modules机制,从此Go的版本管理走进第三个时代。

    Go Module

    Go Module 相比GOPATH和vendor而言功能强大得多,它基本上完全解决了GOPATH和vendor时代遗留的问题。 我们知道,GOPATH时代最大的困扰是无法让多个项目共享同一个pakage的不同版本,在vendor时代,通过把每个项目依赖的package放到vendor 中可以解决这个困扰,但是使用vendor的问题是无法很好的管理依赖的package。

    Go Module是一种全新的依赖管理方案,它涉及一系列的特性,但究其核心,它主要解决两个重要的问题:

    • 准确的记录项目依赖;(依赖哪些package、以及package的版本)
    • 可重复的构建;(一旦项目的依赖被准确记录了,就很容易做到重复构建)

    准确的记录项目依赖,比如你的项目依赖github.com/prometheus/client_golang, 且必须是v1.0.0版本,那么你可以通过Go Module指定(具体指定方法后面会介绍),任何人在任何环境下编译你的项目, 都必须要使用github.com/prometheus/client_golangv1.0.0版本。

    可重复的构建是指,项目无论在谁的环境中(同平台)构建,其产物都是相同的。回想一下GOPATH时代,虽然大家拥有同一个项目的代码,但由于各自 的GOPATH中github.com/prometheus/client_golang版本不一样,虽然项目可以构建,但构建出的可执行文件很可能是不同的。 可重复构建至关重要,避免出现“我这运行没问题,肯定是你环境问题”等类似问题出现。

    mod使用方法

    有了go modules功能后,建议使用go modules的方法,项目目录也不需要再放到GOPATH/src目录下了。

    首先要设定环境变量GO111MODULE,它有三个取值:

    • auto:go判断当前目录是否满足以下两种情况,都满足的话就会开启modules功能
      1. 该项目目录不在GOPATH/src下
      2. 当前目录or上一层目录存在go.mod文件
    • on:启用modules功能。
    • off:不启用modules功能。

    接下来的步骤是

    1. 运行命令 go mod init 生成一个go.mod文件,文件里module默认使用项目目录名,此外还包含了go的版本、用到的第三方库等信息行。
    2. 运行命令go mod tidy 检测依赖:(1)引用项目需要的依赖增加到go.mod文件;(2)去掉go.mod文件中项目不需要的依赖。
    3. 运行命令 go mod download 下载第三方库,也可以直接运行go build或者go install,也会自动安装第三方库。此时第三方库不再被安装在GOPATH/src下,而是下载到GOPATH/pkg/mod中

    依赖包存储

    GOMODULE模式下,go get命令会将依赖包下载到$GOPATH/pkg/mod目录下,并且按照依赖包的版本分别存放。例子:

    ${GOPATH}/pkg/mod/github.com/google
    ├── uuid@v1.0.0
    ├── uuid@v1.1.0
    ├── uuid@v1.1.1
    
    • 1
    • 2
    • 3
    • 4

    相较于GOPATH模式,GOMODULE有两处不同点:

    • 一是依赖包的目录中包含了版本号,每个版本占用一个目录;
    • 二是依赖包的特定版本目录中只包含依赖包文件,不包含.git目录;(由于依赖包的每个版本都有唯一的目录,也表示该目录内容不会发生改变,也就不必再存储其位于版本管理系统(如git)中的信息)
  • 相关阅读:
    MacOS原版镜像下载,详细下载步骤
    答辩步骤及相关准备1
    【我的渲染技术进阶之旅】你知道数字图像处理的标准图上的女孩子是谁吗?背后的故事你了解吗?为啥这张名为Lenna的图会成为数字图像处理的标准图呢?
    数据结构: unordered_map与unordered_set
    【希赛网】软考高级系统架构每日一题总结
    Express写接口—接口的跨域问题-CORS中间件
    W5100S-EVB-PICO主动PING主机IP检测连通性(十)
    dreamweaver网页设计作业制作 学生NBA篮球网页 WEB静态网页作业模板 大学生校园篮球网页代码 dw个人网页作业成品
    CMSC5707-高级人工智能之神经网络
    CentOS7 硬盘扩容
  • 原文地址:https://blog.csdn.net/weixin_41519463/article/details/126613809