配置 1.13+ 的 golang 环境

以前写过《配置 Golang 开发环境》(go < 1.13, win64)。然后 1.13 是一个重大变更,大到需要原有的依赖管理要做迁移的程度(《golang 1.13 - 依赖管理从 dep 到 mod 踩坑》)。

1.13 让原来的配置方式有了变化,撇开语言特性不谈,仅说和配置相关的,最大的变化,是 go module 的转正,和 GOPATH 和 vendor 的边缘化(1.13 仍然给你选择的余地,但是推荐选择 module,停用 GOPATH 和 vendor)。

那么如果你从 1.13 之后才刚刚开始接触 go, 那么前面两篇文章对你来说并不友好。

所以我找到了理由又水一篇。

配置

之前的文章讲的 Win64 环境的配置,正好新版本重写,这次写 Linux 环境下。

0x00 下载解压

1
2
# 为免你无脑复制黏贴,强迫你走一趟流程,也确保你下载最新版本,这不是有效的下载链接,请自行到官网找最新版本,替换掉版本号 x.y.z
~ wget https://dl.google.com/go/gox.y.z.linux-amd64.tar.gz

找下载链接请到官网 golang.org/dl ,如果国内不能访问,请到官方镜像站 golang.google.cn/dl 。

然后解压

1
2
3
# 记得改文件名里的 x.y.z
~ tar -zxvf gox.y.z.linux-amd64.tar.gz
mv -t /opt/ go

个人习惯放到 /opt/ 下。

0x01 系统环境变量

然后将可执行文件加入系统路径。

/etc/profile 末尾加上,保存之后记得 source 一下:

1
2
3
# manually added
GOROOT=/opt/go
export PATH=$PATH:$GOROOT/bin:$HOME/go/bin

我是想全局生效所以丢这里,如果你只是想当前账户生效,可以加在 ~/.bashrc

惯例地检查一下是否配置正确

1
2
~ go version
go version go1.13.6 linux/amd64

如果不能正确执行 go version ,把当前版本输出,请回头检查哪里出错。

跟老版本不同的是,只要把 go 本身的可执行路径 和 go bin 的安装路径加入 PATH 就可以了,剩下的 go env 自行管理了。

0x02 go env

执行 go env,就会看到 go 内置的环境变量,以及部分默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/jaycechant/.cache/go-build"
GOENV="/home/jaycechant/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/jaycechant/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build089244508=/tmp/go-build -gno-record-gcc-switches"

必改

1
2
~ go env -w GO111MODULE=on
~ go env -w GOPROXY=https://goproxy.cn,direct

GO111MODULE :

  • auto : 自 1.11 实验性加入之后就是默认值。auto 意味着由工具链自动判断是否启用 go modules。在 1.13 以前的启用条件是『项目根目录有 go.mod 且项目不在 GOPATH 内』,1.13+ 去掉了 『不在 GOPATH 内的限制』,也就是只要有 go.mod 就会启用。
  • on : 如果你觉得上面这段话太长懒得看,或者害怕以后启用条件还会变,那么 1.13 已经准备好全面启用 go modules,直接设为 on 就好了。设为 on 之后无条件启用 go modules。
  • off : 关闭 go modules,回到 GOPATH 时代。

GOPROXY :

国内环境必备,原因你懂的。甚至可以说这是新版本为中国开发者做出的最大改进之一也不为过。在 dep 的时代是靠自建的代理熬过来的,那么不会代理的朋友就很麻烦了。改用镜像就友好太多了。

目前国内最早最好的代理是 七牛云提供的 https://goproxy.cn 。如果团队内部还有搭建私有代理,可以用 , 隔开,go 会依次尝试。最后记得加上 direct ,让镜像上找不到的依赖回源查找。(包括但不限于 镜像还没同步,私有仓库 等情况)

目前自建代理的开源方案貌似有以下几个。由于我暂时没有自建代理的需要,没有实测,请自行对比选择。

推荐改

1
~ go env -w GOBIN=$HOME/go/bin

GOBIN 如果没有设置,默认值为 $GOPATH/bin ,是通过 go getgo install 安装的可执行文件的存放目录。不设并不影响使用,但考虑到 GOPATH 正在被边缘化,未来不知道哪个版本就取消了,所以建议还是单独设置一下比较好。我为了保持使用习惯,设置了跟默认相同的目录(因为 GOPATH 默认值是 $HOME/go),区别只是这个值不依赖 GOPATH 的值。

值得 提醒 的是,这个目录也需要加入系统 PATH ,并且我已经在 系统环境变量 里加入(最后一个),如果你根据自己的习惯修改了 GOBIN 的位置,那么 0x01 里的配置也得相应修改。

更多的变量,推荐参考 《干货满满的 Go Modules 和 goproxy.cn》。

0x03 cgo 和 build tool

go 语言的 cgo 特性允许 C 语言 和 go 语言互调,达到 复用已有的 C/C++ 庞大代码资源 的目的;又或者用 C 编写程序的一部分以达到某些 底层语言才能达到的目标。而要使用 cgo 特性,就需要有 C/C++ 的构建工具链 gcc

另一方面,随着项目规模变大,你会逐渐需要一个 构建工具 (build tools)帮你管理构建细节,就像 ant / maven / gradle 之于 Java。由于 go 本身的构建比较简单(或者说 go 的构建规则比较清晰,自带的 build 命令够用),又有了现成的依赖管理(之前的 vgo / glide / dep,现在官方的 go modules),官方并没有一个专用的构建工具。这部分,因为依赖管理已有,管理额外的构建细节, Makefile (make) 足矣

gcc 和 make 在多数 Linux 发行版是自带的,你可以通过 gcc -vmake -v 来确认安装的版本。即使没有,视乎不同的包管理器,也就是一两句命令的事。Windows 下稍微麻烦一些,但仍然有解决方案,我在《配置 Golang 开发环境》#2. gcc 和 make 部分有提及,go 的重大升级不影响这部分内容依然有效。

0x04 安装 VCS

在使用 go get 命令之前,需要安装依赖托管服务对应的 VCS (Version Control System)。go get 会根据依赖所托管的网站反馈的信息,调用对应的工具 (git / hg / svn)拉取依赖。

就我的个人实践而言,绝大多数的第三方依赖都是基于 git 发布的(或者说直接就是放在 github 上),所以 直接安装 git 就好 ,后面遇到基于其他工具的依赖,再安装不迟。

由于 git 本身就是一个大话题,基本的安装使用教程不难搜到,有时间时会另起文章讨论,这里只是提醒安装,不再展开。

0x05 开始一个项目

终于把环境都配置好了,然后就可以开始第一个 go 的项目了。由于 go modules 不再依赖 GOPATH,所以项目可以放在任何地方——这个 『任何』,是指可以不是 GOPATH ,但是要是习惯了,继续放在 $GOPATH/src 也没问题。

好了,不管放在哪,现在新建一个项目的根目录

1
2
~ mkdir testproj
~ cd testproj

然后执行 go mod init <module_path> ,生成 go.mod ,这个项目就算初始化完了,接下来就该敲代码了。随着开发的进行,还会自动生成 go.sum 文件,记录依赖的校验信息。注意 go.sum 不是 lock 文件 ,重现构建的信息已经包含在 go.mod 里,go.sum 属于 checksum 文件 ,用来 确保下载的依赖没有被篡改 。 go.mod 和 go.sum 需要一起提交参与版本控制 。关于 go mod 的详细用法,可以直接 go help mod 获取帮助信息,不展开。

关于 module path 的内容,以及 module 与 package 之间的关系,原本是在这篇文章里接着继续写;结果发现这部分内容让字数足足翻了一番。为了避免让本文又臭又长,就另起了一篇文章,请看《golang 1.13 - module VS package》。

go 语言开发不是(篇幅上也不可能是)本文的话题,另起系列展开。

题外话

在写这篇文章时,留意到 gradle 的一个插件 gogradle,可以为 gradle 添加对 go 的支持。由于我没有使用过这个插件,所以不好评价;不过基于以下理由,我认为除非有什么困难只有它能解决,不然 make 足以完成绝大多数的任务,不推荐尝试:

  • go 除了某些特性(如 cgo)编译时依赖某些二进制工具(如 gcc,二进制是区别于基于虚拟机的工具),基本是一个完全自给自足的语言,环境配置简单且基本一劳永逸,编译结果可以单执行文件零依赖部署,在某些情况下简直是杀手级的特性。(想想 C/C++ 以外多少语言能做到)而 gradle 是基于 groovy (一种 JVM 上的脚本语言),等于 给 go 的开发环境引入了 JVM 依赖 。即使我作为一个长期写 Java 的人,环境里一定有 JVM,仍然觉得这种依赖是别扭的。
  • gogradle 官方文档自荐的理由,是 make 学习曲线陡峭,和 make 基于 bash 的跨平台性不好。make 和 gradle 的学习曲线见仁见智,但是由于 go 自带的 build 已经完成了构建的大多数工作(包括依赖推导和文件新旧比较),也不需要处理依赖管理,make 的 工作任务非常轻 , 不会涉及太复杂的规则编写。至于跨平台,引入 MinGW-w64 已经可以解决大多数的问题。
  • go 1.13 自带 go modules 作为依赖管理,大方向是 淡化 GOPATH 和 vendor;而 gogradle 受 glide 启发,自带依赖管理,自称相当于 glide + make,依然使用 GOPATH 和 vendor,这 跟官方的发展方向冲突 。这可能是最关键的一点,如果你习惯了 gradle 的工作方式,有一天这种工作方式可能跟官方的最新版本不兼容。

知识共享 “署名-非商业性使用-相同方式共享” 4.0 (CC BY-NC-SA 4.0)”许可协议
本文为本人原创,采用知识共享 “署名-非商业性使用-相同方式共享” 4.0 (CC BY-NC-SA 4.0)”许可协议进行许可。
本作品可自由复制、传播及基于本作品进行演绎创作。如有以上需要,请留言告知,在文章开头明显位置加上署名(Jayce Chant)、原链接及许可协议信息,并明确指出修改(如有),不得用于商业用途。谢谢合作。
请点击查看协议的中文摘要。