LoginSignup
1
0

WSL2でGo 1.20のAPIをARM64向けにコンパイルした

Posted at

はじめに

最近、Go言語でAPIを開発しています。このAPIのバイナリを ARM64/AMD64向けに 自動でコンパイル&リリースするGitlab CIアクションを作りたくなったので、まずは ローカルのWSL2(Linux)でARM64向けのバイナリをコンパイルする方法を調べました。

前提

  • Windows10 (AMD64)
  • WSL2 (Ubuntu 20.04)
  • Go 1.20.4

やりたいこと

  • Goで書いたAPIを Linux(WSL2) AMD64Linux ARM64向けにコンパイルする。
  • CGO_ENABLED=1 でコンパイルする。 (github.com/mattn/go-sqlite3 を利用しているため)

手順

1. まずGoの実行環境を WSL2側に用意する

GoがそもそもWindowsにしか入っておらず、WSL2側に無かったので Go 1.20.4 をインストールします

WSL2シェル
# 前提として: パッケージを更新
sudo apt-get update 
sudo apt-get -y upgrade

# 公式サイト上に書いてあるリンク先からバイナリをダウンロードする
wget https://go.dev/dl/go1.20.4.linux-amd64.tar.gz
# 展開する
sudo tar -xvf go1.20.4.linux-amd64.tar.gz
# ローカルユーザーのアプリ保存場所に移動
sudo mv go /usr/local
# (任意のエディタでユーザー設定ファイルを開く)
nano ~/.profile

# 下記コマンドを 末尾に追加する
# 作業ファイルの保存先
export GOPATH=$HOME/go-projects
# Go実行ファイルの位置
export GOROOT=/usr/local/go
# PATHを通す
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH 

※ Windows領域(/mnt配下)で実行すると時間がかかるので WSL領域(/home配下)で実行がおすすめです。
※ インストール前に 単にgoを実行しようとすると もしかして: apt-get install golang と出ますが そのコマンドだと古いバージョンがインストールされるため注意

ターミナルを開き直して、下記コマンドで Goのバージョンが確認できたらOK。

$ go version
go version go1.20.4 linux/amd64

2. APIをコンパイルしてみる。

普通にコンパイル

Goで マルチアーキテクチャビルドするのは(通常)かなり簡単になっています。
とてもシンプルにビルドターゲットを指定するだけでビルドできます。

# 環境変数で 対象OSと 対象アーキテクチャを指定し ビルドするだけ
GOOS=linux   GOARCH=arm64 go build -o api_linux_arm64 main.go
GOOS=linux   GOARCH=amd64 go build -o api_linux_amd64 main.go

CGO_ENABLED=1でコンパイル

が、今回はCGO_ENABLED=1でビルドする必要があったため 下記のように ビルドしてみる。

$ CGO_ENABLED=1 GOOS=linux GOARCH=arm64 go build -o server-linux-arm64 main.go
# runtime/cgo
gcc_arm64.S: Assembler messages:
gcc_arm64.S:30: Error: no such instruction: `stp x29,x30,[sp,'
gcc_arm64.S:34: Error: too many memory references for `mov'
gcc_arm64.S:36: Error: no such instruction: `stp x19,x20,[sp,'
gcc_arm64.S:39: Error: no such instruction: `stp x21,x22,[sp,'
gcc_arm64.S:42: Error: no such instruction: `stp x23,x24,[sp,'
gcc_arm64.S:45: Error: no such instruction: `stp x25,x26,[sp,'
gcc_arm64.S:48: Error: no such instruction: `stp x27,x28,[sp,'
gcc_arm64.S:52: Error: too many memory references for `mov'
gcc_arm64.S:53: Error: too many memory references for `mov'
gcc_arm64.S:54: Error: too many memory references for `mov'
gcc_arm64.S:56: Error: no such instruction: `blr x20'
gcc_arm64.S:57: Error: no such instruction: `blr x19'
gcc_arm64.S:59: Error: no such instruction: `ldp x27,x28,[sp,'
gcc_arm64.S:62: Error: no such instruction: `ldp x25,x26,[sp,'
gcc_arm64.S:65: Error: no such instruction: `ldp x23,x24,[sp,'
gcc_arm64.S:68: Error: no such instruction: `ldp x21,x22,[sp,'
gcc_arm64.S:71: Error: no such instruction: `ldp x19,x20,[sp,'
gcc_arm64.S:74: Error: no such instruction: `ldp x29,x30,[sp],'

うーん、謎のエラーが... 検索したところ このIssue がヒットするも、Goの問題ではない? ようで、クローズされてしまっていた。

更に調べるとこのページがヒットし、どうやらCCという環境変数でクロスコンパイラを指定する必要があることがわかった。

CCを指定してコンパイル

$ CGO_ENABLED=1 GOOS=linux GOARCH=arm64 CC=aarch64-linux-gnu-gcc go build -o s
erver-linux-arm64 main.go
# runtime/cgo
cgo: C compiler "aarch64-linux-gnu-gcc" not found: exec: "aarch64-linux-gnu-gcc": executable file not found in $PATH

エラーが変わり、別途コンパイラの実行ファイルが必要ということがわかったため 更に検索した。

すると aarch64-linux-gnu-gccには g++-aarch64-linux-gnu というコンパイラをインストールすると良いことがわかった。

必要なコンパイラをインストールした上でコンパイル

$ CGO_ENABLED=1 GOOS=linux GOARCH=arm64 CC=aarch64-linux-gnu-gcc go build -o server-linux-arm64 main.go

若干待ったあと、エラーなく 実行したフォルダ内にバイナリが生成された!

image.png

感想

やっぱり環境整えるのは コード書くより大変! 書いている途中で調べたところ、今使っているSQLiteがCGO必須なだけで、CGO不要なGoにポートしたSQLiteライブラリもあったみたいです。(後で試してみます)

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0