みつきんのメモ

組み込みエンジニアです。Interface誌で「My オリジナルLinuxの作り方」連載中

Ubuntu 18.04にtinygoをインストールする(2019/04編)(4/7追記)

はじめに

Ubuntu18.04でtinygoをインストールしようとしたらハマったのでメモっておく。

基本はここの手順。

Requirement

  • Go 1.11+
  • LLVM 7 (for example, from apt.llvm.org

あとは、ターゲットのツールチェイン。

  • ARM Cortex-M
  • AVR(Arduino)
  • WebAssembly

詳細は先述のリンク元を参照。

筆者環境はarm-none-eabiがインストール済み。

goのインストール

いろいろ手段があるが、インストーラによるインストールが一番便利だった。

$ sudo apt install wget git
$ wget -q https://storage.googleapis.com/golang/getgo/installer_linux
$ chmod +x installer_linux
$ ./installer_linux -version 1.11.7

GOPATHの設定は.bash_profileに自動的に作成される。

このインストーラ意外と優秀で-version 1.11.7とかやると、特定のバージョンをインストールしてくれる。

引数なしの場合は最新バージョン。今回は1.12がインストールされた。

(4/7 追記)

ここで1.11系のgoをインストールしておく必要がある。現時点では1.11.7が最新。

そうしないと、tinygoの実行時に次のエラーが発生する。

$ tinygo flash -target=bluepill examples/blinky1
.go/src/syscall/js/func.go:74:3: todo: unknown expression: select blocking []

既にインストールしてしまった場合はgoを入れ直す必要がある。 このインストーラでインストールした場合は~/.goを削除すれば良い。

$ rm -rf ~/.go
$ ./installer_linux -version 1.11.7

GOPATHの設定

UbuntuGUI環境では、.bash_profileはログイン時にしか読み込まれないので、 一度ログインし直すか、新しく開いた端末で次のコマンドを実行する。

$ source ${HOME}/.bash_profile

.bash_profileに追加された内容を.bashrcに移動してしまうというのも手。

export PATH=$PATH:/home/mickey/.go/bin

export GOPATH=/home/mickey/go

export PATH=$PATH:/home/mickey/go/bin

llvm-7のインストール

ここを参考にした。

sources.listの追加

llvm 7.0.1をインストールするために、/etc/apt/sources.list.d/llvm.listを次の内容で作成する。

# i386 not available
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic main
# 7
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main
# 8
deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main
deb-src http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main

これがないと、7.0.0がインストールされる。

$ wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
$ sudo apt update

これも忘れずに。

パッケージのインストール

Install (stable branch)に書いてあったものすべて入れた。

$ sudo apt install clang-7 lldb-7 lld-7
$ sudo apt install libllvm-7-ocaml-dev libllvm7 llvm-7 llvm-7-dev llvm-7-doc llvm-7-examples llvm-7-runtime
$ sudo apt install clang-7 clang-tools-7 clang-7-doc libclang-common-7-dev libclang-7-dev libclang1-7 clang-format-7 python-clang-7
$ sudo apt install lldb-7 lld-7 libc++-7-dev libc++abi-7-dev 

tinygoのインストール

まずはgo getを実行する。が、これは必ず失敗する(した)。

$ go get -u github.com/tinygo-org/tinygo

エラー発生(その1)

次のようなエラーが発生した。

$ go get -u github.com/tinygo-org/tinygo
# tinygo.org/x/go-llvm
../../go/src/tinygo.org/x/go-llvm/analysis.go:17:10: fatal error: llvm-c/Analysis.h: No such file or directory
 #include "llvm-c/Analysis.h" // If you are getting an error here read bindings/go/README.txt
          ^~~~~~~~~~~~~~~~~~~
compilation terminated.

ここによると、次のように説明されている。

If you get an error like this::

/usr/local/go/pkg/tool/linux_amd64/link: running g++ failed: exit status 1
/usr/bin/ld: error: cannot find -lLLVM-7
cgo-gcc-prolog:58: error: undefined reference to 'LLVMVerifyFunction'
cgo-gcc-prolog:80: error: undefined reference to 'LLVMVerifyModule'
[...etc...]
Or like this::

../go-llvm/analysis.go:17:93: fatal error: llvm-c/Analysis.h: No such file or directory
 #include "llvm-c/Analysis.h" // If you are getting an error here read bindings/go/README.txt

It means something is wrong with your LLVM installation. Make sure LLVM 7 is installed (Debian package llvm-7-dev). If it still doesn’t work, you can try running:

cd $GOPATH/src/github.com/tinygo-org/go-llvm
make config
And retry:

go install github.com/tinygo-org/tinygo

llvm-7-devはインストールしてあるので、make configを実行する。

go-llvmのソースの場所が実際は異なっているので次のようにする。

$ cd $GOPATH/src/tinygo.org/x/go-llvm/
$ make config

アドバイス通りに次を実行する。

$ go install github.com/tinygo-org/tinygo

エラー発生(その2)

今度は次のようなエラーが発生した。

# tinygo.org/x/go-llvm
panic: overlapping edits: [8156,8319)->"func() _Ctype_LLVMMetadataRef{ _cgo0 := /*line :297:3*/d.ref; var _cgo1 *_Ctype_char = /*line :298:3*/name; var _cgo2 _Ctype_size_t = _Ctype_size_t(len(t.Name)); var _cgo3 _Ctype_uint64_t = _Ctype_uint64_t(t.SizeInBits); var _cgo4 _Ctype_LLVMDWARFTypeEncoding = _Ctype_LLVMDWARFTypeEncoding(t.Encoding); _cgoCheckPointer(_cgo0); return _Cfunc_LLVMDIBuilderCreateBasicType(_cgo0, _cgo1, _cgo2, _cgo3, _cgo4); }()", [8299,8312)->" /*line :302:3*/_Ctype_LLVMDIFlags /*line :302:16*/"

goroutine 1 [running]:
cmd/internal/edit.(*Buffer).Bytes(0xc0000e1650, 0xc0001b20e0, 0x5f171f, 0xe)
    /usr/local/go/src/cmd/internal/edit/edit.go:79 +0x5a4
main.(*Package).writeOutput(0xc0000b4000, 0xc0000a63c0, 0x7ffe1ab7ad12, 0x35)
    /usr/local/go/src/cmd/cgo/out.go:562 +0x38e
main.main()
    /usr/local/go/src/cmd/cgo/main.go:356 +0xceb

これは解決方法も示されていなかったので、こまった。

どうやらgo-llvmでエラーが発生しているらしい。

解決方法

go-llvmのソースはgitリポジトリなので、コミットログを調べてみた。

commit 7707ae5d1261a8929edea7336c8087ca8b520d8d (HEAD -> master, origin/master, origin/llvm8, origin/HEAD)
Author: Ayke van Laethem <aykevanlaethem@gmail.com>
Date:   Thu Feb 14 11:10:53 2019 +0100

    Switch to LLVM 8

なんと、(現時点の)最新のコミットで LLVM 8に移行した と。

気を取り直してブランチを確認してみる。

$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/llvm7
  remotes/origin/llvm8
  remotes/origin/make-release
  remotes/origin/master
  remotes/origin/windows

llvm7系のブランチはあるみたい。

tinygoのgo getでリポジトリが汚れているようなので一度きれいにする。

$ git reset --hard HEAD

llvm7ブランチに切り替える

$ git checkout -b llvm7 origin/llvm7

ビルドしてみる。

$ go build -v  github.com/tinygo-org/tinygo
tinygo.org/x/go-llvm
github.com/tinygo-org/tinygo/ir
github.com/tinygo-org/tinygo/interp
github.com/tinygo-org/tinygo/compiler
github.com/tinygo-org/tinygo

通った。

インストール

$ go install github.com/tinygo-org/tinygo

成功した!

まとめ

go-llvmLLVM 8に移行していた。 回避するには手でブランチを切り替える必要がある。

go getでは依存するリポジトリのコミットかブランチを指定できればよいのに。。

(4/7 追記) goのバージョンは1.11系(現時点の最新は1.11.7)をインストールする必要がある。

参考