概述
golang 官方的包管理從 1.11 版本就開始支持了, 之前嘗試了幾次, 效果都不理想, 就一直用 dep 來管理 package.
最近 1.13 版本發布了, 使用 go module 的官方管理方式越來越多, dep 也早就不在繼續開發了. 鑒於此, 是時候把 golang 的包管理方式遷移到 go module 上來了.
我一直是用 spacemacs 來開發各種應用, 所以本文也是介紹如何在 spacemacs 中配置 golang module 的開發環境.
配置方法
go module 其實本身是不需要什么配置, 這里的配置其實為了更方便的編碼而做的 spacemacs 配置. 能夠讓它支持自動補全, 代碼調轉等等開發時常用的操作.
需要的軟件
使用 go module, golang 的工程不用在放在 GOPATH 下, 所有傳統的 gocode 不能再用來做代碼補全這些了. 我們這里采用 gopls 來代替 gocode.
出來 golang 1.13, 額外需要的軟件就是 gopls
安裝好 golang 1.13, 安裝 gopls 非常簡單:
$ GO111MODULE=on go get golang.org/x/tools/gopls@latest
spacemacs 的配置
go layer
spacemacs 的 develop 分支默認繼承了 lsp 的功能. LSP 是什么 所以配置起來很簡單, 在 dotspacemacs-configuration-layers 下配置:
dotspacemacs-configuration-layers
'(
... ...
lsp
;; ----------------------------------------------------------------
;; Example of useful layers you may want to use right away.
;; Uncomment some layer names and press `SPC f e R' (Vim style) or
;; `M-m f e R' (Emacs style) to install them.
;; ----------------------------------------------------------------
(go :variables
go-backend 'lsp
go-tab-width 8
godoc-at-point-function 'godoc-gogetdoc)
... ...
)
lsp-mode
lsp-mode 是 emacs 對 lsp 的封裝, 參考其中 golang 的部分, 在 dotspacemacs/user-config 中配置:
;; lsp
(use-package lsp-mode
:hook (go-mode . lsp-deferred)
:commands (lsp lsp-deferred))
(setq lsp-auto-guess-root nil)
(setq lsp-ui-doc-enable nil)
(setq lsp-ui-sideline-enable nil)
(setq lsp-prefer-flymake :none)
project root 設置
使用 go module 之后, golang 項目的目錄不一定在 GOPATH 下, 所以定義了個配置 project root 的函數. 當然, 如果不設置, 默認值是 emacs 的 projectile-project-root
;; project path settings
(setq current-project-path (projectile-project-root))
(defun set-project-path (relative-path)
(interactive
(list (read-string "relative path: " "." nil nil nil)))
(setq current-project-path (file-truename relative-path)))
(defun get-project-path ()
(interactive)
(message current-project-path))
build/install 快捷鍵
增加 2 個快捷鍵, 用來執行 go build 和 go install
;; go build/install
(setq default-go-package "")
(defun go-build (&optional pkg)
(interactive
(list (read-string (format "Package Name[%s]: " default-go-package) nil nil "")))
(if (not (string= pkg ""))
(setq default-go-package pkg))
(if (string= current-project-path "")
(message "You MUST set current-project-path FIRST!")
(projectile-with-default-dir current-project-path
(projectile-run-compilation (concat "go build " default-go-package))))
)
(defun go-install (&optional pkg)
(interactive
(list (read-string (format "Package Name[%s]: " default-go-package) nil nil "")))
(if (not (string= pkg ""))
(setq default-go-package pkg))
(if (string= current-project-path "")
(message "You MUST set current-project-path FIRST!")
(projectile-with-default-dir current-project-path
(projectile-run-compilation (concat "go install " default-go-package))))
)
;; set shortcuts
(spacemacs/set-leader-keys-for-major-mode 'go-mode
"xi" 'go-install)
(spacemacs/set-leader-keys-for-major-mode 'go-mode
"xb" 'go-build)
go build 和 go install 的快捷鍵分別是: SPC m x b 和 SPC m x i
使用中遇到的坑
在嘗試使用的過程中, 遇到 2 個坑, 耗費了大半天的時間… 😦
錯誤內容: LSP : main.go not in project or it is blacklisted
在 spacemacs 的 Message buffer 中, 提示 LSP : main.go not in project or it is blacklisted 幾近波折, 才發現不知道什么時候, 當前的項目被加入到 blacklist 中了…
解決方法:
- M-X lsp-workspace-blacklist-remove
- 找到項目所在的文件夾, 然后選擇它, 將它從 blacklist 中移除即可
錯誤內容: no AST for <file:///..../foo.go>
如果項目本身就是 golang 工程的話, 一般不會出現這個問題, 我有個項目, golang 工程是其中的一部分, 工程結構大致如下:
.
├── backend
│ └── this-is-golang-project-root
├── deploy
│ ├── builder
│ └── docker-compose.yml
├── frontend
│ └── ui
└── README.md
golang 工程不在項目的根目錄, 使用時在 spacemacs 的 Message buffer 中, 提示: no AST for <file:///..../foo.go>
解決方式:
- 設置 (setq lsp-auto-guess-root nil)
- M-x set-project-path
- 設置 golang project path, 設置這個的目的是為了使用 SPC m x b 和 SPC m x i 來隨時執行 go build 和 go install
