zoukankan      html  css  js  c++  java
  • 浅谈GoPath和Go Modules包管理

    1、概述

    大多数语言都有“依赖”、“包”等概念,Go语言的依赖处理经历了几次变革

    最早的时候,Go所依赖的所有的第三方库都放在GOPATH这个目录下面

    v1.5开始开始引入vendor模式,如果项目目录下有vendor目录,那么go工具链会优先使用vendor内的包进行编译、测试等

    v1.11开始,引入了Go Module 作为依赖解决方案,到v1.14宣布Go Module已经可以用于生产环境,到v1.16版本开始Go Module默认开启

    2、GOPATH介绍

    2.1 GOPATH目录

    GOPATH是什么,输入如下命令查看

    # go env GOPATH
    GOPATH="/Users/ssgeek/go"
    

    进入到该目录下,目录结构如下

    # cd `go env GOPATH`
    # tree -L 2 .
    .
    ├── bin
    │   ├── dlv
    │   ├── go-outline
    │   ├── gomodifytags
    │   ├── gopkgs
    │   ├── goplay
    │   ├── gopls
    │   ├── gotests
    │   ├── impl
    │   └── staticcheck
    ├── pkg
    │   ├── mod
    │   └── sumdb
    └── src
        └── github.com
        ...
    

    三个目录中存放的文件说明如下

    bin //用来存放编译后的可执行文件
    pkg //用于存放编译后生成的归档文件
    src //用来存放go源码文件
    

    2.2 GOPATH的缺点

    在使用GOPATH的模式下,我们需要将应用代码存放在固定的$GOPATH/src目录下,并且如果执行go get来拉取外部依赖会自动下载并安装到$GOPATH目录下

    第三方套件只要不是官方库,都需要放置在GOPATH/src的路径下才可以使用

    go get最常用在当我们想用别人公开在GitHub上的套件,可以帮我们从网络cloneGOPATH/src里面。虽然这样很方便,但是会发现GOPATH/src下会很复杂,除了有你自己开发的代码目录,同时也包含其他第三方库的专属目录

    我们给不同的项目设置不同的GoPath,优点非常明显:

    便于管理项目,每个项目都是不同的GoPath,这对于我们管理多个Golang项目而言,能够非常清晰的处理项目结构。如果我们把所有项目都放在同一个GoPathsrc包下,那么项目的结构就会变得非常混乱,难以管理

    但是当我们需要依赖第三方的包的时候,不同的项目设置不同的GoPath的缺点也非常明显:

    1. 第三方依赖的包和我们自己的Golang包混在一起,会给我们的项目文件管理带来一定的麻烦
    2. 不同的GoPath都需要下载依赖,那么磁盘中重复的依赖就会非常多,会占用我们大量的磁盘空间

    3、GO Module介绍

    为了解决GOPATH的问题,因此官方在1.11开始推出了Go Modules的功能。Go Modules解决方式很像是Java看到Maven的做法,将第三方库储存在本地的空间,并且给项目代码去引用

    3.1 设定GO111MODULE环境变量

    总共可以设置三种不同的值

    • auto

    默认值,go命令会根据当前目录来决定是否启用modules功能。需要满足两种情形:
    该目录不在GOPATH/src/
    当前或上一层目录存在go.mod文件

    • on

    go命令会使用modules,而不会去GOPATH目录下查找。

    • off

    go命令将不会支持module功能,寻找依赖按照以前GOPATH的做法去寻找

    目前1.16版本默认将这个参数设置成on,而且可能之后的版本会弃用掉GO111MODULE,因此建议要开发Go项目时就不再使用GOPATH了,而是采用Go Modules的做法,因此建议都设定为on

    采用Go Modules,下载下来的第三方依赖就位于GOPATH/pkg/mod目录下

    3.2 初始化mod

    go mod init <module name>
    

    <module name>可填可不填,不填的话预设就是默认的文件名称go.mod

    在此文件中可以写以下几个关键字:

    • module

    定义模组路径

    • go

    定义go语言version

    • require

    指定依赖,预设是最新版,可以指定版本号

    • exclude

    排除该依赖和其版本

    • replace

    使用不同的依赖版本并替换原有的依赖版本注解
    indirect代表被间接导入的依赖包

    假设现在我要引入GitHub上的gin-gonic/gin的依赖,如下定义:

    module myProject
    go 1.16
    require github.com/gin-gonic/gin v1.6.3
    

    再执行以下指令:

    go mod xxx
    

    会将需要的依赖安装在GOPATH/pkg/mod目录里面

    gin@v1.4.0 gin@v1.6.3 gin@v1.7.1
    

    除了go.mod之外,go命令还维护一个名为go.sum的文件,其中包含特定模块版本内容的预期加密哈希
    go命令使用go.sum文件确保这些模块的未来下载检索与第一次下载相同,以确保项目所依赖的模块不会出现意外更改,无论是出于恶意、意外还是其他原因。 go.modgo.sum都应检入版本控制。
    go.sum不需要手工维护,所以可以不用太关注

    只要有开启go modules功能,go get 就不会像以前一样在GOPATH/src下放置依赖,而是会放在GOPATH/pkg/mod里面,并且go.mod会写好引入

    3.3 go mod命令

    常用

    go mod init:初始化go mod, 生成go.mod文件,后可接参数指定 module 名,上面已经演示过。
    go mod download:手动触发下载依赖包到本地cache(默认为$GOPATH/pkg/mod目录)
    go list -m -json all:以 json 的方式打印依赖详情
    

    其他

    go mod graph: 打印项目的模块依赖结构
    go mod tidy :添加缺少的包,且删除无用的包
    go mod verify :校验模块是否被篡改过
    go mod why: 查看为什么需要依赖
    go mod vendor :导出项目所有依赖到vendor下
    go mod edit :编辑go.mod文件
    

    4、总结

    GoPath所引出的问题,就是因为第三方类库的包所导致的,所以在有了GoModule之后,GoPathGoModule就分别负责不同的职责,共同为Golang项目服务

    GoPath用来存放我们从网上拉取的第三方依赖包
    GoModule用来存放我们自己的Golang项目文件,当自己的项目需要依赖第三方的包的时候,我们通过GoModule目录下的一个go.mod文件来引用GoPath目录pkg包下的mod文件夹下的第三方依赖即可

    这样以来,既解决了原来只能局限在GoPath目录src包下进行编程的问题,也解决了第三方依赖包难以管理和重复依赖占用磁盘空间的问题

  • 相关阅读:
    freeswitch对媒体的处理的三种方式
    Windows如何在cmd命令行中查看、修改、删除与添加、设置环境变量
    freeswitch电话代接
    freeswitch三方通话配置
    认识拨号计划
    洛谷P4049 [JSOI2007]合金 题解
    2020-9杂题选做
    LOJ#6497. 「雅礼集训 2018 Day1」图 题解
    LOJ#6496. 「雅礼集训 2018 Day1」仙人掌 题解
    LOJ#6495. 「雅礼集训 2018 Day1」树 题解
  • 原文地址:https://www.cnblogs.com/ssgeek/p/14843476.html
Copyright © 2011-2022 走看看