Go环境配置时遇到的GOPATH路径以及包管理问题

前言

过了个年回到工作岗位,发现之前好好的 Go 环境无法进行调试了,于是又重新配置了一次,弄好之后的新参数与原来有一些不一样的地方,甚至还有一些矛盾的地方,真搞不清楚原来的配置参数怎么能成功调试的,也是奇了怪了。配置过程中还遇到了一些问题,特别记录一下,防止今后遇到类似问题还要苦苦寻找。

Go 的环境变量

说起环境变量,写 Java 的时候倒是配置了不少,一般都需要配置 JAVA_HOMECLASSPATH,后来 C/C++ 写的比较多,完全不需要这个东西,直接使用 include 把绝对路径或者相对路径引用进来就可以,或者使用VS的项目属性界面配置包含路径,也可以将包含路径写在 CMakeLists.txt 中。但是为了能找到和使用各种工具和软件,它们所在的路径一般会加到环境变量Path中。

Go 中也有两个环境变量非常重要,它们分别是 GOROOTGOPATH,其中 GOROOT 比较好理解,就是 Go 软件安装的目录,可以类比一下 JAVA_HOME/bin,而 GOPATH 就是一个神奇的存在,在go1.12版本之前,Go 语言编写的项目代码和下载的包都必须在 GOPATH 目录下,想像一下,在一个 GOPATH 目录下无数个项目go文件,那感觉真是酸爽。

GOPATH 的设计

GOPATH设计的出发点是好的,将代码包统一存储到一个目录下,直接引用包名就可以了,可是这样设计也缺少了自由,下载的第三方包和自己的项目文件混在一起虽然可以方便查看代码,但是结构看起来确实很乱。

什么?你说 GOPATH 可以指定多个目录,确实很多资料说 GOPATH 支持多个目录,下载的包会默认放在 GOPATH 指定的第一个目录下,需要注意的一个点是在windows下指定多个目录需要用分号分隔,而Linux下指定多个目录需要用冒号分隔,并且指定的目录需要是用绝对路径,如果指定的目录中包含相对路径,会报一个 go: GOPATH entry is relative; must be absolute path: "... 错误,记得 GOPATH 变量末尾不要加 : 或者 ;

春节前我就是配置的多个目录,本来调试用的好好的,结果过完年现在不让用了,一调试就会报错 unexpected directory layout:,具体的报错内容结构如下:

1
2
3
4
5
6
7
unexpected directory layout:
import path: _/go/src/firstgo
root: /go/src
dir: /go/src/firstgo
expand root: /go
expand dir: /go/src/firstgo
separator: /

后来参考了下面两篇文章,把 GOPATH 改成单一目录就好了。

也就是在linux下的 ~/.profile 文件中把 export GOPATH=/home/albert/go:/home/albert/WorkSpace/go 改成 export GOPATH=/home/albert/go 就可以了。

GOPATH 的发展

早期版本的 GOPATH 设计所有包下载到指定的目录,并且没有版本号,如果多个项目引用的同一个包的不同版本那就歇菜了,所以说这时的 Go 管理仅仅处于能用的状态,也就相当于一个下载器,达不到软件包管理器的及格水平,后来出现了一些例如 depGodep 的包管理工具,均属于官方推荐的第三方管理工具,都非 Go 语言自带。

Go 的包管理工具并不像 Python 的 pip,或者 JS 的 npm 那样统一,本质上还是设计不同导致的,Go 想做的包管理是一种分布式的,没有Python 或者 JS 那种中心仓库,这样又带来了一个弊端,如果包的提供者频繁提交新版本怎么办,所以在包管理的工作中,版本号是必须要存在的。

关于之前GO项目为什么非要放在 GOPATH 下,以及 GO的包管理发展历程可以参考下面文章:

直到 go mod 出现以后,在Go 中引入第三方模块算是方便了不少,参考《拜拜了,GOPATH君!新版本Golang的包管理入门教程》

Go 的常用命令

Go 作为一种语言,同时也代表了一系列工具和生态环境,它的命令有不少,下面列举一些常见的:

  • go env: 打印go的环境信息
  • go fmt: 运行gofmt对go代码进行格式化
  • go build: 编译包和依赖
  • go run: 编译并运行go程序
  • go version: 显示go程序的版本
  • go help: 打印命令的帮助信息
  • go get: 下载并安装包和依赖(-v 显示操作流程的日志及信息;-u 下载丢失的包,但不会更新已经存在的包)

其中 go help 不仅仅打印了这些命令的基本信息,还可以打印出一些概念的帮助信息, 例如 go help gopath,内容比较多,下面只列举一小部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
Here's an example directory layout:

GOPATH=/home/user/go

/home/user/go/
src/
foo/
bar/ (go code in package bar)
x.go
quux/ (go code in package main)
y.go
bin/
quux (installed command)
pkg/
linux_amd64/
foo/
bar.a (installed package object)
...
...

运行 go env 展示一下当前使用的环境,方便以后做个对照:

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
34
35
36
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/albert/.cache/go-build"
GOENV="/home/albert/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/albert/WorkSpace/go1/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/albert/WorkSpace/go1"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/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-build602227063=/tmp/go-build -gno-record-gcc-switches"

VSCode Remote 时修改的环境变量不生效

这个问题也是在这次配置 Go 调试环境时遇到的,我是在 ~/.profile 文件中修改的 GOPATH的内容,但是在VSCode中调试时就是报错,其表现就跟修改的变量未生效一致,后来查资料发现,原来出现这种情况和配置文件的加载顺序有关,具体参考下列文章:

其实在linux中的shell有 interactive shellnon-interactive shelllogin shellnon-login shell 的区分,每种情况下调用的初始化脚本不同,涉及到 /etc/profile~/.bash_profile ~/.bash_login / ~/.profile等等,而在VSCode远程连接Linux时还会继承之前的环境,多次尝试之后还是不起效果,此时不得不高呼“重启大法好”,重启能解决80%的问题,剩下的20%只能靠重做系统来解决了。

在我这修改脚本内容不生效,脚本间调用还搞出了死循环的问题,不知道是不是因为我使用 zsh 这个 shell作为默认环境出的问题,但重启大法依然奏效,电脑重启后环境变量成功修改了。

C++ 的包管理器

捣鼓这么久 Go,突然想到一个问题,C++ 有没有包管理器呢?答案是有的,并且有很多,但是都存在着这样或那样的问题,可以重点看一下 conan,具体使用可以搜索官网,或者看看下面这些总结。

conan 是一款使用 python 开发的包管理工具,所以需要依赖 Python 环境,CentOS 平台上安装 Python 环境可以参考 Centos安装python3.6和pip步骤记录,虽然CentOS即将被放弃,但是目前在各种云服务器上依旧是主流系统,安装 Python 环境时需要注意一步步跟着做,最好不要投机取巧,我就是因为少安装了一个依赖,导致我使用 pip install conan命令安装 conan 是报错 ModuleNotFoundError: No module named '_ctypes',此时可以安装依赖,重新编译安装 ·conan· 就可以了,也就是运行 yum install libffi-devel -y,重新 make clean && make && make install 就可以了。

总结

  • Go 的项目在 1.12 版本之后不必放到 GOPATH 路径中了,灵活度大大提高
  • C++ 也是有包管理器的,其中 conan 排名比较靠前,它是由 Python 语言编写的
  • go get 是安装依赖包常常要用到的 Go 命令, go help 会提供 Go 相关的许多知识

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

有时正确的选择比刻苦努力更加重要,用战术上的勤奋来掩盖战略上的懒惰,其结果只是感动了自己,而不会带我们达到目标。将者,智信仁勇严也~

2021-2-21 01:19:01

Albert Shi wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客