最近需要折腾kubernetes, 编译的时候提示需要升级到go 1.12. brew升级完golang版本后, 发现在emacs中无法通过go-mode自带的godef等工具进行跳转了. 怀疑是go-mode版本比较老, 于是继续升级go涉及的所有emacs插件. 然而全升级完了发现还是失败, 对一个明明应该能查询到定义的变量执行godef-descrition, 报”no description found for expression at point”.

此时猜想emacs的godef-descrition背后八成是调用了godef这个命令, 为了排查问题尝试手动执行. 然鹅粗略网上搜了下没找到godef的命令行用法…在go-mode 的emacs代码中找到如下几行代码调用godef:

(defun godef--call (point)
"Call godef, acquiring definition position and expression
description at POINT."
(if (not (buffer-file-name (go--coverage-origin-buffer)))
(error "Cannot use godef on a buffer without a file name")
(let ((outbuf (generate-new-buffer "*godef*"))
(coding-system-for-read 'utf-8)
(coding-system-for-write 'utf-8))
(prog2
(call-process-region (point-min)
(point-max)
godef-command
nil
outbuf
nil
"-i"
"-t"
"-f"
(file-truename (buffer-file-name (go--coverage-origin-buffer)))
"-o"
;; Emacs point and byte positions are 1-indexed.
(number-to-string (1- (position-bytes point))))
(with-current-buffer outbuf
(split-string (buffer-substring-no-properties (point-min) (point-max)) "\n"))
(kill-buffer outbuf)))))

其中call-process-region的语法格式, 查文档是:

start end program &optional delete destination display &rest args

翻译一下其实就是当在某个变量调用了godef-descrition后, go-mode会去执行”godef -i -t -f filename -o position 变量字符串”这样一条命令. 然鹅godef的帮助文档里说-i选项是从stdin中读, 照理来说和-f是互斥的. 实际执行也确实这样, 会卡在那等stdin输入. 不知道为啥go-mode能顺利调用这条命令.

一头雾水之际在go源代码的import的里的fmt调了一下godef-descrition, 发现有个报错说是找不到fmt这个包, 同时列出来搜索的路径, GOROOT的环境变量竟然是/usr/local/Cellar/go/1.8.1/libexec, 而这个目录随着升级golang版本已经被删除了, 现在应该是1.12.4. 于是继续找是不是哪个配置文件里写死了GOROOT的路径, 但是我这用的应该是默认的GOROOT, 没有任何配置文件包含GOROOT这个环境变量.

由于是升级golang出现的问题, 怀疑可能是系统中有两个go, 继续看go命令用的是哪个go:

kohn : ~
[0] % which go
/usr/local/bin/go

kohn : ~
[0] % ll /usr/local/bin | grep go
lrwxr-xr-x 1 kohn admin 26B 5 6 11:03 go -> ../Cellar/go/1.12.4/bin/go
-rwxr-xr-x 1 kohn admin 9.9M 4 10 2017 gocode
-rwxr-xr-x 1 kohn admin 5.2M 4 10 2017 godef
lrwxr-xr-x 1 kohn admin 29B 5 6 11:03 godoc -> ../Cellar/go/1.12.4/bin/godoc
lrwxr-xr-x 1 kohn admin 29B 5 6 11:03 gofmt -> ../Cellar/go/1.12.4/bin/gofmt

发现go, godoc, gofmt是一个软链, 只有godef是一个很老的二进制文件. 怀疑可能是godef没有升级导致的. 于是重新下载并编译了一个godef. 问题解决. 看样子可能是godef在编译的时候会把GOROOT写死带到二进制文件里去…

Leave a Reply

电子邮件地址不会被公开。 必填项已用*标注

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>