CLOVER🍀

That was when it all began.

Ubuntu Linux 20.04 LTSに、Goをインストールする(+Emacs lsp-mode)

これは、なにをしたくて書いたもの?

そろそろ、少しずつGoを扱ってみようかなぁと思いまして。

The Go Programming Language

触ったことがないので、今回はとりあえず簡単にインストーとエディタの設定くらいをやります。

環境

今回の環境は、こちらです。Ubuntu Linux 20.04 LTSです。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.1 LTS
Release:    20.04
Codename:   focal


$ uname -srvmpio
Linux 5.4.0-58-generic #64-Ubuntu SMP Wed Dec 9 08:16:25 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

Goをインストールする

では、Goをインストールしましょう。

Goのオフィシャルサイトを見ると、Linux環境だとtar.gzバイナリをダウンロードしてインストールという感じになっています。

Download and install - The Go Programming Language

ですが、GitHubリポジトリにいくともう少し他の手段があるようです。

GitHub - golang/go: The Go programming language

Platform Specific Information

Ubuntu LinuxだとPPAが提供されているようなので、こちらを使うことにします。

Ubuntu · golang/go Wiki · GitHub

まず、なにもしない状態でgolangパッケージを見てみましょう。

$ apt info golang
Package: golang
Version: 2:1.13~1ubuntu2
Priority: optional
Section: devel
Source: golang-defaults
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Go Compiler Team <team+go-compiler@tracker.debian.org>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 12.3 kB
Depends: golang-1.13, golang-doc (>= 2:1.13~1ubuntu2), golang-go (>= 2:1.13~1ubuntu2), golang-src (>= 2:1.13~1ubuntu2)
Homepage: https://golang.org
Download-Size: 2,900 B
APT-Sources: http://jp.archive.ubuntu.com/ubuntu focal/main amd64 Packages
Description: Go programming language compiler - metapackage
 The Go programming language is an open source project to make
 programmers more productive. Go is expressive, concise, clean, and
 efficient. Its concurrency mechanisms make it easy to write programs
 that get the most out of multicore and networked machines, while its
 novel type system enables flexible and modular program construction.
 Go compiles quickly to machine code yet has the convenience of
 garbage collection and the power of run-time reflection. It's a
 fast, statically typed, compiled language that feels like a
 dynamically typed, interpreted language.
 .
 This package is a metapackage that, when installed, guarantees
 that (most of) a full Go development environment is installed.

このエントリを書いている時点で、最新のGoは1.15なので少し古いです。

こちらの手順に沿って、PPAを追加します。

Ubuntu · golang/go Wiki · GitHub

$ sudo add-apt-repository ppa:longsleep/golang-backports
$ sudo apt update

もう1度パッケージの情報を見てみましょう。

$ apt info golang
Package: golang
Version: 2:1.15-1longsleep1+bionic
Priority: optional
Section: devel
Source: golang-defaults
Maintainer: Go Compiler Team <team+go-compiler@tracker.debian.org>
Installed-Size: 10.2 kB
Depends: golang-1.15, golang-doc (>= 2:1.15-1longsleep1+bionic), golang-go (>= 2:1.15-1longsleep1+bionic), golang-src (>= 2:1.15-1longsleep1+bionic)
Download-Size: 3,912 B
APT-Sources: http://ppa.launchpad.net/longsleep/golang-backports/ubuntu focal/main amd64 Packages
Description: Go programming language compiler - metapackage
 The Go programming language is an open source project to make
 programmers more productive. Go is expressive, concise, clean, and
 efficient. Its concurrency mechanisms make it easy to write programs
 that get the most out of multicore and networked machines, while its
 novel type system enables flexible and modular program construction.
 Go compiles quickly to machine code yet has the convenience of
 garbage collection and the power of run-time reflection. It's a
 fast, statically typed, compiled language that feels like a
 dynamically typed, interpreted language.
 .
 This package is a metapackage that, when installed, guarantees
 that (most of) a full Go development environment is installed.

Go 1.15が表示されました。

インストールします。

$ sudo apt install golang

確認。

$ go version
go version go1.15.6 linux/amd64

試してみる

では、ちょっと動かしてみましょう。Getting Startedに沿ってみます。

Tutorial: Get started with Go - The Go Programming Language

ソースコードを作成。
hello.go

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!!")
}

ソースコードのフォーマット。

$ go fmt hello.go

go mod initで、カレントディレクトリをモジュールルートとして設定します。モジュール名は、Getting Startedのままhelloと
します。

$ go mod init hello
go: creating new go.mod: module hello

go.modというファイルが作成されます。 go.mod

module hello

go 1.15

go runで実行。

$ go run hello.go 
Hello, World!!

go buildで実行可能ファイルが作成されます。

$ go build hello.go

helloというファイルができました。

$ ll
合計 2000
drwxrwxr-x 2 xxxxx xxxxx    4096 12月 18 00:05 ./
drwxrwxr-x 4 xxxxx xxxxx    4096 12月 18 00:01 ../
-rwxrwxr-x 1 xxxxx xxxxx 2034781 12月 18 00:05 hello*
-rw-rw-r-- 1 xxxxx xxxxx      75 12月 18 00:04 hello.go

実行。

$ ./hello 
Hello, World!!

そのままドキュメントに沿って、外部パッケージを使ってみます。rsc.io/quoteというパッケージですね。 hello_quote.go

package main

import (
    "fmt"
    "rsc.io/quote"
)

func main() {
    fmt.Println(quote.Go())
}

go runで実行すると、初回はパッケージのダウンロードが行われます。

$ go run hello_quote.go 
go: finding module for package rsc.io/quote
go: downloading rsc.io/quote v1.5.2
go: found rsc.io/quote in rsc.io/quote v1.5.2
go: downloading rsc.io/sampler v1.3.0
go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
Don't communicate by sharing memory, share memory by communicating.

2回目の実行時は、ダウンロードはスキップされます。

$ go run hello_quote.go 
Don't communicate by sharing memory, share memory by communicating.

この時、go.modに外部パッケージの依存が追記されるようです。 go.mod

module hello

go 1.15

require rsc.io/quote v1.5.2 // indirect

また、go.sumというファイルもできていました。
go.sum

golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y=
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

ダウンロードしたファイルは、デフォルトでは$HOME/go配下に置かれるようですね。$GOPATHという話らしいですが、
このあたりはそのうち調べましょう…。

$ find $HOME/go -maxdepth 6 -type f
$HOME/go/pkg/mod/cache/lock
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/LICENSE
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/README.md
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/AUTHORS
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/gen.go
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/.gitattributes
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/CONTRIBUTORS
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/PATENTS
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/doc.go
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/.gitignore
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/CONTRIBUTING.md
$HOME/go/pkg/mod/golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c/codereview.cfg
$HOME/go/pkg/mod/rsc.io/sampler@v1.3.0/sampler.go
$HOME/go/pkg/mod/rsc.io/sampler@v1.3.0/LICENSE
$HOME/go/pkg/mod/rsc.io/sampler@v1.3.0/go.mod
$HOME/go/pkg/mod/rsc.io/sampler@v1.3.0/hello.go
$HOME/go/pkg/mod/rsc.io/sampler@v1.3.0/glass.go
$HOME/go/pkg/mod/rsc.io/sampler@v1.3.0/glass_test.go
$HOME/go/pkg/mod/rsc.io/sampler@v1.3.0/hello_test.go
$HOME/go/pkg/mod/rsc.io/quote@v1.5.2/LICENSE
$HOME/go/pkg/mod/rsc.io/quote@v1.5.2/README.md
$HOME/go/pkg/mod/rsc.io/quote@v1.5.2/go.mod
$HOME/go/pkg/mod/rsc.io/quote@v1.5.2/quote_test.go
$HOME/go/pkg/mod/rsc.io/quote@v1.5.2/buggy/buggy_test.go
$HOME/go/pkg/mod/rsc.io/quote@v1.5.2/quote.go
$HOME/go/pkg/sumdb/sum.golang.org/latest

Goでlsp-mode

最後に、エディタの設定をしましょう。自分はEmacsを使うのと、lsp-modeでなんとかしたいところ。

エディタやIDEに関する情報は、Wikiにまとまっていました。

IDEsAndTextEditorPlugins · golang/go Wiki · GitHub

まずは、go-modeをインストール。

GitHub - dominikh/go-mode.el: Emacs mode for the Go programming language

Goでlsp-modeを使うには、goplsというものが必要そうです。

Go (gopls) - LSP Mode - LSP support for Emacs

https://github.com/golang/tools/blob/master/gopls/doc/emacs.md

というわけで、goplsをインストール。go.modファイルがないディレクトリで実行する場合は、$GO111MODULEをonに
しないと動きませんでしたが…。

$ GO111MODULE=on go get golang.org/x/tools/gopls@latest

$PATHを通せ、ということらしいので

You first must install gopls and put it somewhere in your PATH.

https://github.com/golang/tools/blob/master/gopls/doc/emacs.md

$HOME/go/binに通しておきます。

$ PATH=$HOME/go/bin:$PATH

確認。

$ gopls version
golang.org/x/tools/gopls v0.6.0
    golang.org/x/tools/gopls@v0.6.1 h1:vD171EDBkyUVyp9B45IYXklV/VEfbHgX0FKw0Q0dO30=

あとは、.init.elを設定して完了です。lsp-mode、company、go-mode+lsp-mode、ですね。

;; lsp-mode
(require 'lsp-mode)
(setq gc-cons-threshold 100000000)
(setq read-process-output-max (* 1024 1024))
(setq lsp-completion-provider :capf)
(setq lsp-idle-delay 0.500)
(require 'lsp-ui)
(setq lsp-ui-imenu-enable t)
(setq lsp-headerline-breadcrumb-enable t)

;; company
(require 'company)
(global-company-mode t)
(setq company-idle-delay 0)
(setq company-minimum-prefix-length 1)
(setq company-selection-wrap-around t)
(setq completion-ignore-case t)
(define-key company-active-map (kbd "C-n") 'company-select-next)
(define-key company-active-map (kbd "C-p") 'company-select-previous)
(define-key company-active-map (kbd "C-s") 'company-filter-candidates)

;; go
(use-package lsp-mode
  :ensure t
  :commands (lsp lsp-deferred)
  :hook (go-mode . lsp-deferred))