golangでクロスコンパイルを試してみる

# はじめに
Go（Golang）は、Googleによって開発されたオープンソースのプログラミング言語です。本記事では、WindowsにGoをインストールし、簡単な「Hello, World!」プログラムをWindowsとUbuntu(amd64)向けにビルドする手順を紹介します。

# 1. Goのダウンロード
まず、Goの公式サイトからインストーラーをダウンロードします。

1. Goのダウンロードページにアクセスします。 https://go.dev/
2. 「Download Go」ボタンをクリックし、Windows用のインストーラー（`go<version>.windows-amd64.msi`）をダウンロードします。

# 2. Goのインストール
ダウンロードしたインストーラーを実行し、画面の指示に従ってインストールを完了させます。

1. ダウンロードした`go<version>.windows-amd64.msi`ファイルをダブルクリックして実行します。
2. インストールウィザードに従い、インストール先を指定して「Next」をクリックします。
3. インストールが完了したら、「Finish」をクリックします。

# 3. 環境変数の設定の確認
Goを正しく動作させるために、GOPATHの環境変数を設定します。インストーラーが自動で設定するのですが、念のため確認します。
「スタート」メニューを開き、「環境変数」と入力して「システム環境変数の編集」を選択して確認してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32580/98358e55-2b01-82ca-c077-8d7bb9d81ef8.png)

# 4. Goの動作確認
Goが正しくインストールされているか確認します。

1. 「スタート」メニューを開き、「powershell」と入力してPowerShellを開きます。
2. 以下のコマンドを入力し、Goのバージョン情報が表示されることを確認します。

```powershell
> go version
go version go1.23.2 windows/amd64
```

# 5. 「Hello, World!」プログラムの作成
次に、簡単な「Hello, World!」プログラムを作成して実行します。

1. 任意のディレクトリに移動し、以下の hello.go ファイルを作成します。

```go:hello.go
package main

import "fmt"

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

2. modファイルを作成します。

```powershell
> go mod init hello
```

# 6. 現在の環境（Windows）で動作するプログラムをビルドする
現在の環境を確認した後に、作成したプログラムをビルドします。

1. Goの環境を確認する

```powershell
> go env GOOS
windows
> go env GOARCH
amd64
```

2. PowerShellで以下のコマンドを入力してプログラムをビルドします。

```powershell
> go build
```

3. ビルドして、hello.exeが作成されました。プログラムのサイズは、2,172KBぐらいです。

```powershell
> dir
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2024/11/03     15:09             24 go.mod
-a----        2024/11/03     15:10        2224128 hello.exe
-a----        2024/11/03     15:10             81 hello.go
```

## 7. Ubuntu(amd64)で動作するプログラムをビルドする

1. Powershellで以下のコマンドを入力してプログラムをビルドします。

```powershell
> $env:GOOS="linux"; $env:GOARCH="amd64"; go build
```

2. ビルドして、hello が作成されました。プログラムのサイズは、2,080KBぐらいです。

```powershell
> dir
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2024/11/03     15:09             24 go.mod
-a----        2024/11/03     15:17        2128949 hello
-a----        2024/11/03     15:10        2224128 hello.exe
-a----        2024/11/03     15:10             81 hello.go
```

3. Ubuntuにscpなどでコピーして確認してみます。

```sh
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=xxxxx, with debug_info, not stripped
```

## リリース用にビルドする
先ほどのビルドにはデバック用の情報が入っていましたので、以下のコマンドで再度ビルドします。

```powershell
> $env:GOOS="linux"; $env:GOARCH="amd64"; go build -ldflags="-s -w"
```

-s で、シンボルテーブルを削除します。シンボルテーブルはデバッグやプロファイリングに使用される情報を含んでいますが、リリースビルドでは不要です。
-w で、デバッグ情報を削除します。これにはソースファイルのパスや行番号などが含まれます。

これらのフラグを使用することで、実行ファイルのサイズを削減し、配布や起動時間を改善することもできます。1,357KBぐらいになりました。

```powershell
> dir
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2024/11/03     15:09             24 go.mod
-a----        2024/11/03     15:46        1388696 hello
-a----        2024/11/03     15:10        2224128 hello.exe
-a----        2024/11/03     15:10             81 hello.go
```

Ubuntuにscpなどでコピーして確認してみます。

```sh
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=xxxxx, stripped
```

# 8. 補足：Ubuntu 24.04でGoを実行する
Ubuntu 24.04でGoを実行してみます。

Goのインストールは以下のコマンドです。

```sh
sudo apt install golang-go
```

UbuntuでWindows向けのビルドする場合は、以下のコマンドになります。

```sh
GOOS=windows GOARCH=amd64 go build -ldflags="-s -w"
```

# おわりに
Cで同様のプログラムを作成し、Ubuntuで静的リンク（statically linked）したところ、実行ファイルのサイズは約766KBになりました。Cの方が実行ファイルのサイズが小さいですが、Cでポータビリティがあるプログラムを作るのは大変です。ファイルのサイズが少し大きくなりますが、Goは使いやすさと利便性が非常に魅力的だと感じました。