在 Go 语言中,我们可以使用go get命令安装远程仓库中托管的代码,不同于 Ruby Gem、pypi 等集中式的包管理机制, Go 语言的包管理系统是去中心化的。简单来讲,go get命令支持任何一个位置托管的 Git 或 Mercurial 的仓库,无论是 Github 还是 Google Code 上的包,都可以通过这个命令安装。

我们知道,在 Go 语言中的import语句对于已经使用go get安装到本地的包,依然要使用其去绝对路径引入。 比如对于从 Github 上安装的 goji,其在 Github 上的路径 URL 是 https://github.com/zenazn/goji,因此在import它的时候需要使用下面的代码:

1
import "github.com/zenazn/goji"

正因为如此,Go 语言可以通过直接分析代码中的import语句来查询依赖关系。 go get命令在执行时,就会自动解析import来安装所有的依赖。

除了go get,Go 语言还提供了一个 Workspace 的机制,这个机制也是很容易让人困惑的设计。简单来说就是通过设定 GOPATH环境变量,指定除了GOROOT所指定的目录之外,Go 代码所在的位置 (也就是 Workspace 的位置)。 一般来说,GOPATH目录下会包含pkgsrcbin三个子目录,这三个目录各有用处。

  • bin 目录用来放置编译好的可执行文件,为了使得这里的可执行文件可以方便的运行, 在 shell 中设置PATH变量。
  • src 目录用来放置代码源文件,在进行import时,是使用这个位置作为根目录的。自己编写的代码也应该放在这下面。
  • pkg 用来放置安装的包的链接对象 (Object) 的。这个概念有点类似于链接库,Go 会将编译出的可连接库放在这里, 方便编译时链接。不同的系统和处理器架构的对象会在pkg存放在不同的文件夹中。

我的GOPATH目录树如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
├── bin
├── pkg
│   └── darwin_amd64
│       └── github.com
│           └── zenazn
│               └── goji
└── src├── code.google.com│   └── p│       └── go.crypto└── github.com└── zenazn└── goji

一般来说,你自己的代码不应该直接放置在src目录下,而应该为其建立对应的项目文件夹。 go get也会把第三方包的源代码放到这个目录下,因此一般推荐设置两个GOPATH,比如:

1
export GOPATH="/usr/local/share/go:$HOME/codes/go"

这样第三方包就会默认放置在第一个路径中,而你可以在第二个路径下编写自己的代码。 虽然 Go 语言本身已经提供了相当强大的包管理方式了,但是仍然有一些不足:

  1. 不能很方便地隔离不同项目的环境
  2. 不能很方便地控制某个依赖包的版本
  3. 不能管理 Go 本身的版本

因此我们还需要一些第三方的工具来弥补这些缺陷。

第三方的管理工具

GOPATH 管理和包管理

由于存在GOPATH的机制,我们可以使用多个GOPATH来实现项目隔离的方法。 譬如,对于每个项目,都分配一个不同的路径作为GOPATH。 可以实现这样的目的的工具有gvp等。

对于 gvp 来说,想要针对当前目录建立一个GOPATH,只需要执行gvp init即可。 gvp 会在当前项目的目录下新建一个隐藏的文件夹作为GOPATH指向的位置。 切换环境时使用下面两个命令来修改环境变量。这种做法跟 Python 中的virtualenv比较类似。

1
2
source gvp in   # 进入当前目录对应的 GOPATH 环境
source gvp out  # 登出当前目录对应的 GOPATH 环境

至于对依赖包更版本更细致的管理,可以配合的工具还有 gpm。 gpm有点类似于 Python 中的pip工具。他可以生成一个名为 Godeps 的文件, 其中记录了每个依赖包的 URL 以及使用的版本 (hash tag)。 之前的一篇文章提到 gpm只能管理来自 Github 的依赖,不过当前的版本已经支持了非 Git 方式托管的依赖包了。

基于同样原理管理依赖包版本的工具还有Godep。 这个工具在 Github 上具有相当高的关注度。它所生成的Godeps文件采用 JSON 格式储存, 是一个跟 Node.js 中 NPM 相仿的工具。

总体来说以上几个工具已经可以解决隔离项目环境和控制依赖包版本的问题了。但是使用上还不算方便, 为了能在我们 cd 到某个目录时自动的切换环境变量,我们可能还需要在 shell 做一些配置使其在cd到项目目录下时自动切换环境变量。

这方面做的比较好的一个选择是 Go Manager(gom), 它生成的Gomfile格式上几乎跟 Ruby Gem 一样。gom 可能是这些工具当中使用最方便的一个, 只要使用gom build命令代替原来的go build命令进行编译,你基本不需要配置 Shell 或者和环境变量打交道。

Go 语言版本管理

对于 Go 语言,一般来说并没有使多个语言版本并存的需求。Go 语言现在还没有经历过类似 Python 2.x 到 3.x 或者 Ruby 1.x 到 2.x 这样破坏性的版本升级。旧的代码在新的语言版本当中一般是能够正确运行的。 不过若遇到非要并存多个版本的时候,gvm就是一个不错的选择。

gvm 的使用跟 rvm 比较类似。

1
2
gvm install go1 # 安装 go1 版本
gvm use go1     # 修改环境变量使用 go1 版本的 Go

总结

是否有必要使用多个 Workspace 仍然具有争议,譬如这个 StackOverflow 上的相关问答中, 就有人提出只使用一个 Workspace 就可以应付大多数情况了。

在研究相关问题的时候,我发现很多 Go 语言的用户都还带着原来编程语言的思维, 这点从上面介绍的多个工具的特点当中就可以很容易看出来:gvpgpm就是典型的 Python 的包管理模式, gvp对应着virtualenvgpm对应着pip;如果你之前是 Node.js 和 NPM 的用户, 那么GoDeps肯定会让你有种熟悉的感觉;更不用说最后介绍的gom了,它从名称到文件格式都在模仿 Ruby Gem。

不同编程背景的开发者来到 Go 语言之后各自带来了自己的依赖包管理方式,而且形成了各自的社区。 这种现象虽然使得各自圈子的开发者免去了选择恐惧症,但是造成的解决方案分裂和互不兼容的情况也需要正视。 这时我们不禁要问,Go 自己的解决方式应该是什么样的?Go 语言为何没有一个官方标准的解决方案呢?

从Go FAQ的一段文字当中我们可以得到部分答案:

Versioning is a source of significant complexity, especially in large code bases, and we are unaware of any approach that works well at scale in a large enough variety of situations to be appropriate to force on all Go users. (依赖包的版本管理是一个非常复杂的问题,特别是在代码量比较大的时候。 我们一直没有找到任何一种方式能够在各种情形下都能良好工作, 因此也没有一种方式足够好到应该强迫所有的 Go 用户使用它)

因此现阶段来看,对于 Go 语言的包管理解决方案,我们也就只能“仁者见仁,智者见智”了。

最后,对于想要了解 Go 语言的包管理以及更多可用的工具的读者,这里再推荐两篇相关的文章: Go Package Management 和 A Journey in Golang Package Manager

转载于:https://www.cnblogs.com/dasn/articles/4848968.html

Go 语言本身提供的包管理机制相关推荐

  1. python包管理机制_Go 1.5之前的多种包管理机制简介(

    在 Go 语言中,我们可以使用go get命令安装远程仓库中托管的代码,不同于 Ruby Gem.pypi 等集中式的包管理机制, Go 语言的包管理系统是去中心化的.简单来讲,go get命令支持任 ...

  2. import java.io 包下载_Go 包管理机制深入分析

    前言 随着 Go 语言的深入使用,其依赖管理机制也一直是各位 Gopher 热衷于探讨的话题.Go 语言的源码依赖可通过 go get 命令来获取,但自动化程度不高,于是官方提供了 Dep 这样的自动 ...

  3. npm包管理机制引质疑:又一安装程序中发现恶意代码,开发者账户频遭劫持

    铜灵 发自 凹非寺 量子位 出品 | 公众号 QbitAI npm行不行,包管理机制行不行? 最新的一次npm包被篡改事件,让开发者的这两个疑问更加强烈了. 最新中枪的是纯函数式编程语言Purescr ...

  4. js读取外部json指定字段值完整代码_前端工程化 剖析npm的包管理机制(完整版)...

    导读 现如今,前端开发的同学已经离不开 npm 这个包管理工具,其优秀的包版本管理机制承载了整个繁荣发展的NodeJS社区,理解其内部机制非常有利于加深我们对模块开发的理解.各项前端工程化的配置以加快 ...

  5. Android 系统(203)---Android包管理机制(一)PackageInstaller的初始化

    Android包管理机制(一)PackageInstaller的初始化 转自:https://blog.csdn.net/itachi85/article/details/81024903 前言 包管 ...

  6. 前端工程化 - 剖析npm的包管理机制

    导读 现如今,前端开发的同学已经离不开 npm 这个包管理工具,其优秀的包版本管理机制承载了整个繁荣发展的NodeJS社区,理解其内部机制非常有利于加深我们对模块开发的理解.各项前端工程化的配置以加快 ...

  7. Android包管理机制(三)PMS处理APK的安装

    本文首发于微信公众号「刘望舒」 关联系列 Android包管理机制系列 前言 在上一篇文章Android包管理机制(二)PackageInstaller安装APK中,我们学习了PackageInsta ...

  8. Android包管理机制5 APK是如何被解析的

    一 概述 在本系列的前面文章中,我们介绍了 PackageInstaller 的初始化和安装 APK 过程.PMS 处理 APK 的安装和 PMS 的创建过程,这些文章中经常会涉及到一个类,那就是 P ...

  9. com.android.packageinstaller,Android包管理机制(二)PackageInstaller安装APK

    前言 在本系列上一篇文章Android包管理机制(一)PackageInstaller的初始化中我们学习了PackageInstaller是如何初始化的,这一篇文章我们接着学习PackageInsta ...

最新文章

  1. hbase 0.96 java api_HBase(九) HBase JAVA API - 运维API
  2. 2006,来晚了~哈哈
  3. DOM渲染的详细过程 1
  4. .net EF监控 MiniProfiler
  5. python从零开始系列连载_技术 | Python从零开始系列连载(一)
  6. java正则替换数字_Java 正则表达式,替换图片名称,替换数字,和谐用语,复制文件...
  7. Python爬取全站妹子图片,差点硬盘走火了!
  8. matlab 最优资产组合,基于MATLAB的最优投资组合问题.pdf
  9. Python语言程序设计课程论文
  10. 密码学与加密算法详解
  11. WPF Effect (一)
  12. 杂记(关于域名、网名以及一些常用图像格式、像素)
  13. 2016跨境电商五大物流模式
  14. 基于mahout的动漫推荐系统
  15. CSS 清除浮动的方法
  16. Oracle命名规范
  17. 湘湘学习之旅 越努力 越幸运
  18. 此文胜过你听三年的培训课----海尔集团CEO/张瑞敏•演讲语录!
  19. Android开发免费短信验证码SDK。
  20. 关于人工智能训练师职业认证通知

热门文章

  1. 为什么只看重结果_买家下单最看重的三项服务,做好这三点,让你的销量涨涨涨...
  2. Jmeter数据库及接口测试
  3. mysql 一对多 根据多条数据排序_优化的道路永无止境——Mysql的ICP及MRR
  4. 在定时器中返回给视图的值_JavaScript二进制数组(2)TypedArray视图
  5. 96KB存储器的怎么算地址范围_STM32入门系列-存储器与寄存器介绍
  6. python交互式方式、代码文件方式_涨见识了,在终端执行 Python 代码的 6 种方式
  7. 24点游戏java代码 中国开源社区_编程之美 1.16 24点游戏
  8. 类加载器 java委托机制_解析Java虚拟机中类的初始化及加载器的父委托机制
  9. linux mysql 实战_Linux平台MySQL多实例项目实施_MySQL数据库基础与项目实战06
  10. 了区块链开放平台baas_区块链开放平台 BaaS 系统开发,区块链智能合约撰写服务...