过了个年回到工作岗位,发现之前好好的 Go
环境无法进行调试了,于是又重新配置了一次,弄好之后的新参数与原来有一些不一样的地方,甚至还有一些矛盾的地方,真搞不清楚原来的配置参数怎么能成功调试的,也是奇了怪了。配置过程中还遇到了一些问题,特别记录一下,防止今后遇到类似问题还要苦苦寻找。
说起环境变量,写 Java
的时候倒是配置了不少,一般都需要配置 JAVA_HOME
和 CLASSPATH
,后来 C/C++ 写的比较多,完全不需要这个东西,直接使用 include
把绝对路径或者相对路径引用进来就可以,或者使用VS的项目属性界面配置包含路径,也可以将包含路径写在 CMakeLists.txt
中。但是为了能找到和使用各种工具和软件,它们所在的路径一般会加到环境变量Path
中。
Go
中也有两个环境变量非常重要,它们分别是 GOROOT
和 GOPATH
,其中 GOROOT
比较好理解,就是 Go
软件安装的目录,可以类比一下 JAVA_HOME/bin
,而 GOPATH
就是一个神奇的存在,在go1.12版本之前,Go
语言编写的项目代码和下载的包都必须在 GOPATH
目录下,想像一下,在一个 GOPATH
目录下无数个项目go文件,那感觉真是酸爽。
GOPATH
设计的出发点是好的,将代码包统一存储到一个目录下,直接引用包名就可以了,可是这样设计也缺少了自由,下载的第三方包和自己的项目文件混在一起虽然可以方便查看代码,但是结构看起来确实很乱。
什么?你说 GOPATH
可以指定多个目录,确实很多资料说 GOPATH
支持多个目录,下载的包会默认放在 GOPATH
指定的第一个目录下,需要注意的一个点是在windows下指定多个目录需要用分号分隔,而Linux下指定多个目录需要用冒号分隔,并且指定的目录需要是用绝对路径,如果指定的目录中包含相对路径,会报一个 go: GOPATH entry is relative; must be absolute path: "...
错误,记得 GOPATH
变量末尾不要加 :
或者 ;
。
春节前我就是配置的多个目录,本来调试用的好好的,结果过完年现在不让用了,一调试就会报错 unexpected directory layout:
,具体的报错内容结构如下:
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
设计所有包下载到指定的目录,并且没有版本号,如果多个项目引用的同一个包的不同版本那就歇菜了,所以说这时的 Go
管理仅仅处于能用的状态,也就相当于一个下载器,达不到软件包管理器的及格水平,后来出现了一些例如 dep
、Godep
的包管理工具,均属于官方推荐的第三方管理工具,都非 Go
语言自带。
Go
的包管理工具并不像 Python 的 pip,或者 JS 的 npm 那样统一,本质上还是设计不同导致的,Go
想做的包管理是一种分布式的,没有Python 或者 JS 那种中心仓库,这样又带来了一个弊端,如果包的提供者频繁提交新版本怎么办,所以在包管理的工作中,版本号是必须要存在的。
关于之前GO项目为什么非要放在 GOPATH
下,以及 GO的包管理发展历程可以参考下面文章:
直到 go mod
出现以后,在Go
中引入第三方模块算是方便了不少,参考《拜拜了,GOPATH君!新版本Golang的包管理入门教程》
Go
作为一种语言,同时也代表了一系列工具和生态环境,它的命令有不少,下面列举一些常见的:
其中 go help
不仅仅打印了这些命令的基本信息,还可以打印出一些概念的帮助信息, 例如 go help gopath
,内容比较多,下面只列举一小部分:
...
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
展示一下当前使用的环境,方便以后做个对照:
$ 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"
这个问题也是在这次配置 Go
调试环境时遇到的,我是在 ~/.profile
文件中修改的 GOPATH
的内容,但是在VSCode中调试时就是报错,其表现就跟修改的变量未生效一致,后来查资料发现,原来出现这种情况和配置文件的加载顺序有关,具体参考下列文章:
其实在linux中的shell有 interactive shell
、 non-interactive shell
、 login shell
、 non-login shell
的区分,每种情况下调用的初始化脚本不同,涉及到 /etc/profile
、~/.bash_profile
~/.bash_login /
~/.profile
等等,而在VSCode远程连接Linux时还会继承之前的环境,多次尝试之后还是不起效果,此时不得不高呼“重启大法好”,重启能解决80%的问题,剩下的20%只能靠重做系统来解决了。
在我这修改脚本内容不生效,脚本间调用还搞出了死循环的问题,不知道是不是因为我使用 zsh
这个 shell
作为默认环境出的问题,但重启大法依然奏效,电脑重启后环境变量成功修改了。
捣鼓这么久 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
就可以了。
GOPATH
路径中了,灵活度大大提高go get
是安装依赖包常常要用到的 Go 命令, go help
会提供 Go 相关的许多知识有时正确的选择比刻苦努力更加重要,用战术上的勤奋来掩盖战略上的懒惰,其结果只是感动了自己,而不会带我们达到目标。将者,智信仁勇严也~