コンテンツにスキップ

Go/クロスコンパイル

出典: フリー教科書『ウィキブックス(Wikibooks)』
< Go


Goにおけるクロスコンパイル

[編集]

はじめに

[編集]

クロスコンパイルとは、開発しているマシンとは異なるターゲット環境(オペレーティングシステムやCPUアーキテクチャ)向けに実行ファイルを生成するプロセスです。Goは強力なクロスコンパイル機能を持ち、複数のプラットフォーム向けのバイナリを簡単に作成できます。

Goのクロスコンパイルの利点

[編集]
  • 開発環境に依存せず:WindowsマシンでLinux向けのバイナリを作成できる
  • シンプルな設定:環境変数の設定だけで異なるターゲット向けにビルド可能
  • ネイティブバイナリの生成:依存関係のないスタンドアロンの実行ファイルを生成

クロスコンパイルの基本

[編集]

Goでクロスコンパイルを行うには、GOOSGOARCHの2つの環境変数を設定します。

  • GOOS: ターゲットのオペレーティングシステム
  • GOARCH: ターゲットのCPUアーキテクチャ
GOOSで有効な値一覧
GOOS 解説
aix IBMが開発した商用UNIX。同社のPower Systemsサーバで動作し、高い堅牢性が特徴。
android Google主導で開発されているLinuxベースのモバイルOS。スマホやタブレットで世界シェア1位。
darwin Apple製品(macOS, iOS等)の核となるオープンソースのOS。BSD系をベースに開発。
dragonfly FreeBSD 4.8から派生したOS。軽量なカーネルスレッドと、高性能なストレージ機能が特徴。
freebsd 高いパフォーマンスと信頼性を誇るオープンソースのBSD系OS。サーバやネットワーク機器で多用。
illumos OpenSolarisから派生したオープンソースOS。ZFSやDTraceなどの高度な機能を継承。
ios iPhoneやiPad(旧)専用のOS。Darwinをベースに、モバイル向けに高度に最適化されている。
js JavaScript実行環境(主にWebブラウザ内)。OSではないが、Go等のコンパイル対象として扱われる。
linux 世界で最も普及しているオープンソースカーネル。サーバ、スパコン、組み込み等、用途は多岐にわたる。
netbsd 「どんなハードウェアでも動かす」ことを目標とするBSD系OS。移植性が極めて高い。
openbsd セキュリティを最優先に設計されたBSD系OS。デフォルト設定での安全性を追求している。
plan9 ベル研究所で開発された分散型OS。全ての資源をファイルとして扱う設計思想がGo言語にも影響。
solaris 旧サン・マイクロシステムズ(現オラクル)が開発したUNIX OS。商用システムで広く利用されていた。
wasip1 WebAssembly System Interface (WASI) の初期版。ブラウザ外でWasmを動作させるための規格。
windows Microsoftが開発する世界標準のPC用OS。デスクトップからサーバ(Windows Server)まで広く普及。
GOARCHで有効な値一覧
GOARCH 解説
386 Intelの32ビットx86アーキテクチャ。古いPCやレガシーな32ビットOS環境向け。
amd64 Intel/AMDの64ビットアーキテクチャ(x86_64)。現在のデスクトップやサーバの主流。
arm 32ビットのARMアーキテクチャ。古いスマートフォンやRaspberry Pi(初期〜3)などで利用。
arm64 64ビットのARMアーキテクチャ(AArch64)。最新スマホ、Appleシリコン、AWS Graviton等で主流。
loong64 中国のLoongson(龍芯)が開発した独自の64ビットRISCアーキテクチャ。
mips 32ビットのMIPSアーキテクチャ(ビッグエンディアン)。ルータ等の組み込み機器で古くから利用。
mips64 64ビットのMIPSアーキテクチャ(ビッグエンディアン)。高速なネットワーク機器等で使用。
mips64le 64ビットMIPSのリトルエンディアン版。一部の特定用途向けサーバ等で利用。
mipsle 32ビットMIPSのリトルエンディアン版。安価なネットワークデバイス等で利用。
ppc64 64ビットのPowerPCアーキテクチャ(ビッグエンディアン)。IBMのメインフレームや古いサーバ向け。
ppc64le 64ビットPowerPCのリトルエンディアン版。モダンなLinux OSやHPC、AIサーバ等で利用。
riscv64 オープンソースの命令セットRISC-Vの64ビット版。次世代の標準として急速に普及中。
s390x IBMのメインフレーム(z/Architecture)用64ビットアーキテクチャ。エンタープライズ用途。
wasm WebAssembly。ブラウザ上で動作する仮想バイナリ形式。プラットフォームに依存せず実行可能。

クロスコンパイルの実行方法

[編集]

コマンドラインでの実行例

[編集]
# Linux 64-bit (amd64) 向けにビルド
env GOOS=linux GOARCH=amd64 go build -o myapp-linux-amd64 main.go

# Windows 64-bit 向けにビルド
GOOS=windows GOARCH=amd64 go build -o myapp-windows-amd64.exe main.go

# macOS 64-bit 向けにビルド
GOOS=darwin GOARCH=amd64 go build -o myapp-darwin-amd64 main.go

# Raspberry Pi (ARM) 向けにビルド
env GOOS=linux GOARCH=arm go build -o myapp-linux-arm main.go

Windows環境での実行例

[編集]

Windows環境では、コマンドの記述方法が少し異なります:

# CMD
set GOOS=linux
set GOARCH=amd64
go build -o myapp-linux-amd64 main.go

# PowerShell
$env:GOOS="linux"
$env:GOARCH="amd64"
go build -o myapp-linux-amd64 main.go

高度なクロスコンパイル設定

[編集]

ARM向けのビルドでARMバージョンを指定

[編集]

ARMアーキテクチャには様々なバージョンがあります。GOARM環境変数を使ってバージョンを指定できます:

env GOOS=linux GOARCH=arm GOARM=7 go build -o myapp-armv7 main.go

CGOと依存関係

[編集]

デフォルトでは、クロスコンパイル時にCGO_ENABLED=0が設定され、Cライブラリへの依存を避けるよう構成されます。特定の場合にはCGOを有効化する必要があります:

env CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build main.go

ただし、CGOを有効にする場合は、ターゲットプラットフォーム向けのCコンパイラが必要になります。

マルチプラットフォームビルドの自動化

[編集]

シェルスクリプトを使用した例

[編集]
#!/bin/bash
BINARY_NAME=myapp
PLATFORMS=("windows/amd64" "linux/amd64" "darwin/amd64")

for platform in "${PLATFORMS[@]}"
do
    platform_split=(${platform//\// })
    GOOS=${platform_split[0]}
    GOARCH=${platform_split[1]}
    
    output_name=$BINARY_NAME'-'$GOOS'-'$GOARCH
    if [ $GOOS = "windows" ]; then
        output_name+='.exe'
    fi
    
    echo "Building for $GOOS/$GOARCH..."
    env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name
    
    if [ $? -ne 0 ]; then
        echo "Error building for $GOOS/$GOARCH"
    fi
done

Makefileを使った例

[編集]
.PHONY: build-all

BINARY_NAME=myapp
PLATFORMS=linux/amd64 linux/arm windows/amd64 darwin/amd64

build-all:
	$(foreach platform,$(PLATFORMS), \
		$(eval GOOS = $(word 1,$(subst /, ,$(platform)))) \
		$(eval GOARCH = $(word 2,$(subst /, ,$(platform)))) \
		$(eval EXTENSION = $(if $(filter windows,$(GOOS)),.exe,)) \
		$(shell GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $(BINARY_NAME)-$(GOOS)-$(GOARCH)$(EXTENSION) main.go) \
	)

goreleaser を使用する方法

[編集]

大規模なプロジェクトでは goreleaser ツールを使うとクロスコンパイルとリリースプロセスが簡単になります:

# .goreleaser.yml
builds:
  - env:
      - CGO_ENABLED=0
    goos:
      - linux
      - windows
      - darwin
    goarch:
      - amd64
      - arm64
      - arm
    goarm:
      - 6
      - 7

よくある問題と解決策

[編集]

CGO依存の問題

[編集]

エラー: cgo: C compiler "gcc" not found: exec: "gcc": executable file not found in %PATH%

解決策: CGOを無効にする

env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go

ビルド時のネイティブライブラリ依存

[編集]

問題: プログラムがOS固有のライブラリに依存している場合

解決策:

  • 可能な限りGoのネイティブライブラリを使用する
  • 条件付きコンパイルでOS別の実装を分ける
// +build windows

package main

import "syscall"

// Windowsでのみ使用される関数

実行権限のエラー

[編集]

問題: Linuxバイナリがパーミッションエラーで実行できない

解決策: バイナリに実行権限を与える

chmod +x ./myapp-linux-amd64

実用的なクロスコンパイル事例

[編集]

Webサーバーの例

[編集]
package main

import (
    "fmt"
    "net/http"
    "os"
    "runtime"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello from Go! Running on %s/%s\n", runtime.GOOS, runtime.GOARCH)
    })
    
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    
    fmt.Printf("Server starting on port %s...\n", port)
    err := http.ListenAndServe(":"+port, nil)
    if err != nil {
        fmt.Printf("Error starting server: %s\n", err)
    }
}

このサーバーをさまざまなプラットフォームでビルドし、それぞれで同じ機能を提供できます。

まとめ

[編集]

Goのクロスコンパイル機能は、さまざまなプラットフォーム向けのアプリケーション開発を非常に簡単にします。主な利点は:

  1. 開発環境に依存せず、あらゆるプラットフォーム向けのバイナリを生成できる
  2. 環境変数の設定だけで簡単にクロスコンパイルができる
  3. 依存関係のないスタンドアロンバイナリの生成が可能

この機能を活用することで、アプリケーションの配布と展開が大幅に簡素化され、Goプログラムの移植性が向上します。