我的vim开发环境搭建(3): Go开发配置

1. Go的安装

嗯因为Go的官网被墙了所以需要自行准备梯子。Linux安装Go很简单,即使是CentOS 6,直接去golang下载页下载二进制文件解压即可,比如我写这篇博客时的最新版本是1.12.6,下载解压即可:

1
2
3
4
wget https://dl.google.com/go/go1.12.6.linux-amd64.tar.gz
tar zxvf go1.12.6.linux-amd64.tar.gz -C ~/local/
cd ~/local/go
mkdir gopath

我这里依旧是解压到~/local目录,另外新建了gopath目录。然后在~/.bashrc中添加环境变量:

1
2
3
4
export PATH=$LOCAL/go/bin:$PATH
export GOROOT=$LOCAL/go
export GOPATH=$GOROOT/gopath
export GOBIN=$GOPATH/bin

GOROOT指的是Go的安装目录,而GOPATH则是自定义路径,不一定要在GOROOT下,而且可以有多个路径,每个路径代表Go的一个工作区,一般的工作区由srcpkgbin三个目录组成,比如go get远程下载的项目,而GOBIN则是安装的二进制文件的路径。

2. 重新编译YCM

之前安装的YCM能够对C/C++进行补全,要对Go进行补全需要加上--go-completer选项重新编译,不过由于已经存放过编译的中间文件了,所以这次编译会很快。

1
2
CC="$LOCAL/gcc-5.4.0/bin/gcc" CXX="$LOCAL/gcc-5.4.0/bin/g++" ./install.py  \
--clang-completer --system-libclang --go-completer

编译完毕后基本的补全功能已经有了,如下图所示:

YCM对Go的补全

Go的编码规范建议使用TAB而非空格表示缩进,因此之前的vim配置中set expandtab最好注释掉,防止把TAB扩展成空格。

YCM对Go的补全无需像C++一样通过.ycm_extra.conf.py脚本来指定头文件包含目录的,它是通过直接分析处于$GOROOT/pkgGOPATH/pkg下的静态库.a文件来获取补全信息的。

由于Go标准库的静态库已经编译好,位于$GOROOT/pkg/$GOOS_$GOARCH目录下,环境变量可通过go env命令来查询。而对于go get或者$GOPATH/src下的项目,如果没有编译成静态库,YCM是无法补全的,因此要用到某些包时需要首先进入包所在目录go install

如果使用了本地包比如import "./local",那么需要把local.a文件拷贝到和当前.go文件同一目录。

3. vim-go

1
Plug 'fatih/vim-go', { 'do': ':GoUpdateBinaries' }

安装、使用可参考vim-go的README,某些二进制文件地址被墙了,所以需要去镜像站下载。

然而打开.go文件时会提示

1
vim-go: could not find 'gopls'. Run :GoInstallBinaries to fix it

然而用:GoInstallBinaries会失败,因为某些二进制文件被墙了,打开vim-go项目目录下的plugin/go.vim可以找到:

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
" these packages are used by vim-go and can be automatically installed if
" needed by the user with GoInstallBinaries.
let s:packages = {
\ 'asmfmt': ['github.com/klauspost/asmfmt/cmd/asmfmt'],
\ 'dlv': ['github.com/go-delve/delve/cmd/dlv'],
\ 'errcheck': ['github.com/kisielk/errcheck'],
\ 'fillstruct': ['github.com/davidrjenni/reftools/cmd/fillstruct'],
\ 'gocode': ['github.com/mdempsky/gocode', {'windows': ['-ldflags', '-H=windowsgui']}],
\ 'gocode-gomod': ['github.com/stamblerre/gocode'],
\ 'godef': ['github.com/rogpeppe/godef'],
\ 'gogetdoc': ['github.com/zmb3/gogetdoc'],
\ 'goimports': ['golang.org/x/tools/cmd/goimports'],
\ 'golint': ['golang.org/x/lint/golint'],
\ 'gopls': ['golang.org/x/tools/cmd/gopls'],
\ 'gometalinter': ['github.com/alecthomas/gometalinter'],
\ 'golangci-lint': ['github.com/golangci/golangci-lint/cmd/golangci-lint'],
\ 'gomodifytags': ['github.com/fatih/gomodifytags'],
\ 'gorename': ['golang.org/x/tools/cmd/gorename'],
\ 'gotags': ['github.com/jstemmer/gotags'],
\ 'guru': ['golang.org/x/tools/cmd/guru'],
\ 'impl': ['github.com/josharian/impl'],
\ 'keyify': ['honnef.co/go/tools/cmd/keyify'],
\ 'motion': ['github.com/fatih/motion'],
\ 'iferr': ['github.com/koron/iferr'],
\ }

如注释所言,:GoInstallBinaries实际上是把这些二进制文件安装到本地,由于golang.org被墙了,所以相关工具无法下载。即使是github上的项目,克隆速度也慢得感人,所以还是手动下载安装。

3.1 手动安装二进制文件

fillstruct为例:

1
2
3
4
5
mkdir -p $GOPATH/src/github.com/davidrjenni
cd $GOPATH/src/github.com/davidrjenni
git clone https://github.com/davidrjenni/reftools.git
cd reftools/cmd/fillstruct
go install

注意go.vim中的cmd/fillstruct后缀指的是克隆的项目的子目录,因此流程是先克隆项目本身,再进入相应子目录安装。go install安装完后会发现$GOPATH/bin下多了二进制文件fillstruct

实际上上述流程是手动进行了go get的流程,但是能够判断出错到底是git clone还是go install,前者出错可能就是访问太慢甚至无法访问,后者则是可能项目里引用了未安装的包。

3.2 安装依赖包

并非所有项目都像fillstruct那么顺利,比如在安装errcheck时就提示:

1
2
3
4
$ go install
internal/errcheck/errcheck.go:19:2: cannot find package "golang.org/x/tools/go/packages" in any of:
/home/xyz/local/go/src/golang.org/x/tools/go/packages (from $GOROOT)
/home/xyz/local/go/gopath/src/golang.org/x/tools/go/packages (from $GOPATH)

其中/home/xyz是我的HOME目录,出现这个错误就是因为"golang.org/x/tools/go/packages"包没有安装,而由于golang.org被墙了,go get安装会失败,不过好在可以从golang的github镜像站去找到对应的项目,然后下载安装,以此为例:

1
2
3
4
cd $GOPATH
mkdir -p src/golang.org/x
cd src/golang.org/x
git clone https://github.com/golang/tools.git

然后再重新在errcheck目录下go install即可。

3.3 特别操作

  1. stamblerre/gocode,由于生成的是gocode-gomod而非默认的gocode,因此需要指定二进制名称(似乎go install无法做到):
1
2
go build -o gocode-gomod
mv gocode-gomod $GOPATH/bin
  1. honnef.co/go/tools/cmd/keyify,在github上有镜像
1
2
3
4
5
cd $GOPATH/src
mkdir -p honnef.co/go
git clone https://github.com/dominikh/go-tools.git honnef.co/go/tools
cd honnef.co/go/tools/cmd/keyify
go install

3.4 最终安装结果

安装的二进制文件如下:

1
2
3
4
$ ls $GOBIN
asmfmt fillstruct godef golangci-lint gomodifytags gotags impl
dlv gocode gogetdoc golint gopls guru keyify
errcheck gocode-gomod goimports gometalinter gorename iferr motion

从golang的github镜像上分别克隆了3个项目:

1
2
$ ls $GOPATH/src/golang.org/x
lint sync tools

3.5 其他说明

vim-go的具体使用方式,参考vim-go Tutorial

打开go文件时会出现下列错误

1
vim-go: Features that rely on gopls will not work correctly in a null module.

解决方法参考#2301,在.vimrc中添加下列代码即可:

1
let g:go_null_module_warning = 0

此外GoRename命令只有在项目目录在$GOPATH/src下时才能使用,否则会出现can't find package containing错误。

4. 总结

由于是在之前的基础上进行,所以Go开发环境的搭建较为简单,安装Go、重新编译YCM,Ultisnip已经有了,剩下的就是vim-go的安装了。其实最重要的还是YCM的补全功能。

虽然我vim-go用得也不多,主要就是用了下将gofmt集成进vim的:GoFmt命令,毕竟上手Go的时间也不长。话说才发现现在保存文件时就会自动格式化了,无需手动输入:GoFmt命令。

安装vim-go的主要难点在于各种远程包,在我的电脑上几乎是全程开代理下载,有时候git代理不太好使就直接在VPS上克隆完毕后,打包、FTP下载、FTP上传、解压。

之前实习时安装vim-go去解决各种go get的问题了,go get虽然方便,但是出错的话难以及时发现错误在哪,感觉在国内这个网络环境下,还不如手动克隆、安装。