Go言語(Golang)がサーバーサイド開発やクラウドネイティブなツール開発において広く採用されている大きな理由の一つに、強力なクロスコンパイル機能が挙げられます。
開発環境と実行環境が異なる場合でも、追加のライブラリや複雑な設定を必要とせずに、ターゲットとなるOSやCPUアーキテクチャに合わせた実行ファイルを生成できる点は、他の言語にはない大きな強みです。
本記事では、Go言語におけるクロスコンパイルの基礎知識から、環境変数GOOSおよびGOARCHの設定方法、さらに難易度が高いとされるCGOを利用したプロジェクトでのビルド手法までを詳しく解説します。
Go言語のクロスコンパイルとは
クロスコンパイルとは、現在作業しているコンピュータ(ホスト環境)とは異なるOSやCPUアーキテクチャ(ターゲット環境)で動作するバイナリを作成することを指します。
通常、多くのコンパイル言語ではターゲット環境ごとにツールチェーンを用意する必要がありますが、Go言語は標準のツールチェーンのみでクロスコンパイルが可能な設計になっています。
例えば、macOS上で開発したプログラムをLinuxサーバーやWindowsクライアントで動作させたい場合、Goであればコマンド一つでそれぞれのOSに最適化されたシングルバイナリを出力できます。
これにより、デプロイ作業が劇的に簡略化され、実行環境にGoのランタイムをインストールする必要もなくなります。
基本的なクロスコンパイルの手順
Go言語でクロスコンパイルを行う際は、ビルドコマンドを実行する際に特定の環境変数を指定するだけで完了します。
最も重要な変数は、ターゲットOSを指定するGOOSと、ターゲットアーキテクチャを指定するGOARCHの2つです。
GOOSとGOARCHの設定
まずは、現在使用しているGoのバージョンでどのような組み合わせがサポートされているかを確認してみましょう。
以下のコマンドを実行することで、対応しているプラットフォームの一覧が表示されます。
# サポートされているOSとアーキテクチャの組み合わせを表示
go tool dist list
出力結果の一部を以下に示します。
android/386
android/amd64
darwin/amd64
darwin/arm64
linux/amd64
linux/arm64
windows/amd64
windows/arm64
ビルドコマンドの実装例
例えば、macOS(Intel/Apple Silicon共通)上でLinuxの64bit(x86_64)向けにビルドを行いたい場合は、次のように環境変数を付与してgo buildを実行します。
# Linux 64bit向けにビルド
GOOS=linux GOARCH=amd64 go build -o main-linux main.go
同様に、Windows 64bit向けにビルドする場合は以下のようになります。
# Windows 64bit向けにビルド(.exe拡張子が自動的に考慮されるわけではないため、出力名を指定するのが一般的)
GOOS=windows GOARCH=amd64 go build -o main-windows.exe main.go
このように、ビルド時に一時的に環境変数を上書きする手法が一般的です。
生成されたバイナリは、ターゲットとなる環境にコピーするだけでそのまま実行可能です。
主要なターゲット環境の組み合わせ
実務でよく利用される主要な組み合わせを以下の表にまとめました。
| ターゲットOS | ターゲットアーキテクチャ | GOOS設定値 | GOARCH設定値 |
|---|---|---|---|
| Linux (64bit) | Intel / AMD | linux | amd64 |
| Linux (ARM) | AWS Graviton / Raspberry Pi | linux | arm64 |
| Windows (64bit) | Intel / AMD | windows | amd64 |
| macOS (Intel) | Intel Mac | darwin | amd64 |
| macOS (Apple Silicon) | M1 / M2 / M3 Mac | darwin | arm64 |
注意点として、32bit環境(386)向けのビルドも可能ですが、近年のサーバー環境ではほとんどが64bitであるため、特別な理由がない限りamd64またはarm64を選択してください。
CGOを利用する場合のクロスコンパイル
Go言語の標準ライブラリのみを使用している場合、クロスコンパイルは非常に簡単です。
しかし、C言語のライブラリに依存している(CGOを使用している)場合、難易度が上がります。
CGOが抱える課題
CGOを利用しているコードをビルドする場合、Goのコンパイラだけでなく、ターゲット環境に対応したCコンパイラ(gccなど)が必要になります。
デフォルトの設定では、クロスコンパイル時にCGOは無効化(CGO_ENABLED=0)されるようになっています。
もしSQLiteや一部の暗号化ライブラリなど、CGOを必要とする依存関係が含まれている場合は、明示的にCGO_ENABLED=1を設定し、さらにターゲット環境用のクロスコンパイラを指定しなければなりません。
CGOを有効にしたビルド例
例えば、UbuntuなどのLinux環境からWindows向けにCGOを有効にしてビルドする場合、x86_64-w64-mingw32-gccなどのクロスコンパイラをインストールした上で、以下のようなコマンドを実行します。
# CGOを有効にし、ターゲット用のCコンパイラを指定してビルド
CGO_ENABLED=1 GOOS=windows GOARCH=amd64 CC=x86_64-w64-mingw32-gcc go build -o main.exe main.go
このように、CC環境変数で適切なCコンパイラを指し示す必要があります。
これにはターゲットOSのシステムヘッダーやライブラリの準備が必要となるため、ローカル環境で直接構築するのは手間がかかることが多いです。
解決策としてのZigコンパイラの活用
近年、CGOのクロスコンパイルを劇的に簡単にする方法として、Zig言語のコンパイラ(zig cc)を利用する手法が注目されています。
Zigは標準で多くのプラットフォームへのクロスコンパイルをサポートしており、GoのCCに指定するだけで複雑な設定なしにCGOビルドを通すことができます。
# ZigをCCとして利用する例(macOSからLinux amd64へ)
CGO_ENABLED=1 GOOS=linux GOARCH=amd64 CC="zig cc -target x86_64-linux" go build main.go
この手法は、Dockerコンテナ内でビルド環境を構築する際にも非常に有効です。
効率的なビルド管理と自動化
複数のプラットフォーム向けにバイナリを配布する場合、手動でコマンドを打つのは現実的ではありません。
そこで、ビルドプロセスの自動化が重要になります。
GoReleaserの活用
Goプロジェクトのリリース自動化ツールとしてデファクトスタンダードとなっているのがGoReleaserです。
YAML形式の設定ファイルを用意するだけで、GitHub ActionsなどのCI/CDパイプライン上で複数のOS・アーキテクチャ向けのビルド、アーカイブ作成(.tar.gzや.zip)、GitHub Releaseへのアップロードを一括で行うことができます。
以下は、簡単な.goreleaser.yamlの例です。
# GoReleaserの設定例
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
この設定ファイルがあるだけで、ツールが自動的に全ての組み合わせをビルドしてくれます。
ビルドタグの利用
プラットフォームごとに処理を切り分けたい場合は、ビルドタグ(Build Tags)を使用します。
ファイルの冒頭に特定の記述を追加することで、そのファイルがどのOSの時にコンパイル対象に含まれるかを制御できます。
// +build windows
package main
import "fmt"
func platformMessage() {
fmt.Println("This is a Windows specific message")
}
このように、ファイル名の末尾に_windows.goや_linux.goと付けることでも、Goのビルドシステムは自動的にプラットフォームを判別してくれます。
まとめ
Go言語のクロスコンパイルは、GOOSとGOARCHという2つの環境変数を理解するだけで、誰でも簡単に始めることができます。
依存関係がGoだけで完結していれば、追加のツールをインストールすることなく、世界中のあらゆるプラットフォームに向けたバイナリをその場で生成できるでしょう。
CGOを利用する場合や複雑なプラットフォーム固有の処理が必要な場合には、Zigコンパイラの併用やGoReleaserによる自動化を検討してください。
これらのツールを使いこなすことで、開発効率は飛躍的に向上します。
シングルバイナリでどこでも動くというGoの特性を最大限に活かし、迅速かつ安定したデプロイ環境を構築していきましょう。
