Ubuntu 16.04で複数のプラットフォーム用のGo実行可能ファイルをビルドする方法

前書き

Go programming languageには、パッケージの取得と実行可能ファイルの構築を非常に簡単にする豊富なツールチェーンが付属しています。 Goの最も強力な機能の1つは、Goでサポートされている任意の外部プラットフォームの実行可能ファイルをクロスビルドできることです。 これにより、パッケージを配布するために特定のプラットフォームにアクセスする必要がないため、テストとパッケージの配布がはるかに簡単になります。

このチュートリアルでは、Goのツールを使用してバージョン管理からパッケージを取得し、その実行可能ファイルを自動的にインストールします。 次に、実行可能ファイルを手動でビルドしてインストールし、プロセスに精通できるようにします。 次に、異なるアーキテクチャ用の実行可能ファイルをビルドし、ビルドプロセスを自動化して複数のプラットフォーム用の実行可能ファイルを作成します。 完了したら、WindowsとmacOS、およびサポートする他のプラットフォーム用の実行可能ファイルを作成する方法がわかります。

前提条件

このチュートリアルを実行するには、次のものが必要です。

[[step-1 -—- installing-go-programs-from-version-control]] ==ステップ1—バージョン管理からのGoプログラムのインストール

Goパッケージから実行可能ファイルを作成する前に、そのソースコードを取得する必要があります。 go getツールは、GitHubなどのバージョン管理システムからパッケージをフェッチできます。 内部的には、go getはパッケージを$GOPATH/src/ディレクトリのサブディレクトリに複製します。 次に、該当する場合は、実行可能ファイルをビルドして$GOPATH/binディレクトリに配置することでパッケージをインストールします。 前提条件のチュートリアルで説明されているようにGoを構成した場合、$GOPATH/binディレクトリは$PATH環境変数に含まれ、システムのどこからでもインストール済みパッケージを使用できるようになります。

go getコマンドの構文はgo get package-import-pathです。 package-import-pathは、パッケージを一意に識別する文字列です。 多くの場合、Githubなどのリモートリポジトリ内のパッケージの場所、またはマシンの$GOPATH/src/ディレクトリ内のディレクトリです。

go get-uフラグとともに使用するのが一般的です。これは、go getにパッケージとその依存関係を取得するか、それらの依存関係がすでにマシンに存在する場合はそれらを更新するように指示します。

このチュートリアルでは、Goで記述されたWebサーバーであるCaddyをインストールします。 Caddy’s instructionsxごとに、パッケージのインポートパスにgithub.com/mholt/caddy/caddyを使用します。 go getを使用して、Caddyをフェッチしてインストールします。

go get -u github.com/mholt/caddy/caddy

コマンドの完了には時間がかかりますが、パッケージを取得してインストールしている間、進行状況は表示されません。 実際には、コマンドが正常に実行されたことを示す出力はありません。

コマンドが完了すると、Caddyのソースコードが$GOPATH/src/github.com/mholt/caddyで利用可能になります。 さらに、Caddyには実行可能ファイルがあるため、自動的に作成され、$GOPATH/binディレクトリに保存されます。 whichを使用して実行可能ファイルの場所を出力することにより、これを確認します。

which caddy

次の出力が表示されます。

Output/home/sammy/work/bin/caddy

[。注意]##

Notego getコマンドは、Gitリポジトリのデフォルトブランチ(多くの場合、masterまたは開発中のブランチ)からパッケージをインストールします。 go getを使用する前に、通常はリポジトリのREADMEファイルにある手順を確認してください。

git checkoutなどのGitコマンドを使用して、go getコマンドを使用して取得したソースで別のブランチを選択できます。 ブランチを切り替える方法の詳細については、チュートリアルHow to Use Git Branchesを確認してください。

Goパッケージのインストールプロセスを詳しく見てみましょう。まず、既に入手したパッケージから実行可能ファイルを作成します。

[[step-2 -—- building-an-executable]] ==ステップ2—実行可能ファイルの構築

go getコマンドは、ソースをダウンロードし、Caddyの実行可能ファイルを1つのコマンドでインストールしました。 ただし、実行可能ファイルを自分で再構築するか、独自のコードから実行可能ファイルをビルドすることができます。 go buildコマンドは実行可能ファイルをビルドします。

Caddyは既にインストールされていますが、プロセスに慣れるために手動で再構築します。 go buildを実行し、パッケージのインポートパスを指定します。

go build github.com/mholt/caddy/caddy

前と同じように、操作の成功を示す出力はありません。 実行可能ファイルは、パッケージを含むディレクトリと同じ名前で、現在のディレクトリに生成されます。 この場合、実行可能ファイルの名前はcaddyになります。

パッケージディレクトリにいる場合は、パッケージへのパスを省略して、go buildを実行するだけです。

実行可能ファイルに別の名前または場所を指定するには、-oフラグを使用します。 caddy-serverという実行可能ファイルを作成し、現在の作業ディレクトリ内のbuildディレクトリに配置しましょう。

go build -o build/caddy-server github.com/mholt/caddy/caddy

このコマンドは実行可能ファイルを作成し、存在しない場合は./buildディレクトリも作成します。

では、実行可能ファイルのインストールを見てみましょう。

[[step-3 -—- installing-an-executable]] ==ステップ3—実行可能ファイルのインストール

実行可能ファイルをビルドすると、現在のディレクトリまたは選択したディレクトリに実行可能ファイルが作成されます。 実行可能ファイルのインストールは、実行可能ファイルを作成して$GOPATH/binに保存するプロセスです。 go installコマンドはgo buildと同じように機能しますが、go installが出力ファイルを適切な場所に配置します。

実行可能ファイルをインストールするには、go installを使用し、その後にパッケージのインポートパスを続けます。 もう一度、Caddyを使用してこれを試してください。

go install github.com/mholt/caddy/caddy

go buildの場合と同様に、コマンドが成功した場合、出力は表示されません。 前と同様に、実行可能ファイルは、パッケージを含むディレクトリと同じ名前で作成されます。 ただし、今回は実行可能ファイルは$GOPATH/binに格納されます。 $GOPATH/bin$PATH環境変数の一部である場合、実行可能ファイルはオペレーティングシステムのどこからでも利用できます。 whichコマンドを使用してその場所を確認できます。

which caddy

次の出力が表示されます。

Output of which/home/sammy/work/bin/caddy

go getgo build、およびgo installがどのように機能し、それらがどのように関連しているかを理解したところで、最も人気のあるGo機能の1つである他のターゲットプラットフォーム用の実行可能ファイルの作成について見ていきましょう。

[[step-4 -—- building-executables-for-different-architectures]] ==ステップ4—さまざまなアーキテクチャの実行可能ファイルを構築する

go buildコマンドを使用すると、Goでサポートされているターゲットプラットフォームon your platformの実行可能ファイルを作成できます。 つまり、使用するターゲットプラットフォームで実行可能ファイルをビルドすることなく、アプリケーションをテスト、リリース、および配布できます。

クロスコンパイルは、ターゲットオペレーティングシステムとアーキテクチャを指定する必要な環境変数を設定することにより機能します。 ターゲットオペレーティングシステムには変数GOOSを使用し、ターゲットアーキテクチャにはGOARCHを使用します。 実行可能ファイルをビルドするには、コマンドは次の形式を取ります。

env GOOS=target-OS GOARCH=target-architecture go build package-import-path

envコマンドは、変更された環境でプログラムを実行します。 これにより、現在のコマンド実行にのみ環境変数を使用できます。 変数は、コマンドの実行後に設定解除またはリセットされます。

次の表に、使用できるGOOSGOARCHの可能な組み合わせを示します。

GOOS-ターゲットオペレーティングシステム GOARCH-ターゲットプラットフォーム

android

arm

darwin

386

darwin

amd64

darwin

arm

darwin

arm64

dragonfly

amd64

freebsd

386

freebsd

amd64

freebsd

arm

linux

386

linux

amd64

linux

arm

linux

arm64

linux

ppc64

linux

ppc64le

linux

mips

linux

mipsle

linux

mips64

linux

mips64le

netbsd

386

netbsd

amd64

netbsd

arm

openbsd

386

openbsd

amd64

openbsd

arm

plan9

386

plan9

amd64

solaris

amd64

windows

386

windows

amd64

[。警告]##

Warning: Android用の実行可能ファイルのクロスコンパイルには、Android NDKと、このチュートリアルの範囲を超える追加のセットアップが必要です。

表の値を使用して、次のようにWindows 64ビット用のCaddyを構築できます。

env GOOS=windows GOARCH=amd64 go build github.com/mholt/caddy/caddy

この場合も、操作が成功したことを示す出力はありません。 パッケージ名を名前として使用して、実行可能ファイルが現在のディレクトリに作成されます。 ただし、この実行可能ファイルをWindows用にビルドしたため、名前は接尾辞.exeで終わります。

現在のディレクトリにcaddy.exeファイルがあります。これは、lsコマンドで確認できます。

ls caddy.exe

出力にcaddy.exeファイルが表示されます。

Outputcaddy.exe

[.note]#Note-oフラグを使用して、実行可能ファイルの名前を変更したり、別の場所に配置したりできます。 ただし、Windows用の実行可能ファイルを作成して別の名前を指定する場合は、実行可能ファイルの名前を設定するときに必ず `.exe`サフィックスを明示的に指定してください。

このプロセスをスクリプト化して、複数のターゲット環境向けにソフトウェアを簡単にリリースできるようにします。

[[step-5 --- creating-a-script-to-automate-cross-compilation]] ==ステップ5—クロスコンパイルを自動化するスクリプトの作成

多くのプラットフォームで実行可能ファイルを作成するプロセスは少し面倒ですが、スクリプトを作成して物事を簡単にすることができます。

スクリプトは、パッケージインポートパスを引数として受け取り、オペレーティングシステムとプラットフォームのペアの定義済みリストを反復処理し、各ペアの実行可能ファイルを生成して、出力を現在のディレクトリに配置します。 各実行可能ファイルには、パッケージ名に続いて、ターゲットプラットフォームとアーキテクチャがpackage-OS-architectureの形式で名前が付けられます。 これは、任意のプロジェクトで使用できるユニバーサルスクリプトになります。

ホームディレクトリに切り替えて、テキストエディタでgo-executable-build.bashという名前の新しいファイルを作成します。

cd ~
nano go-executable-build.bash

スクリプトはshebang行から開始します。 この行は、実行可能ファイルとして実行されるときにこのスクリプトを解析するインタープリターを定義します。 次の行を追加して、bashがこのスクリプトを実行するように指定します。

go-executable-build.bash

#!/usr/bin/env bash

パッケージのインポートパスをコマンドライン引数として使用します。 これを行うには、$n変数を使用します。ここで、nは非負の数です。 変数$0には実行したスクリプトの名前が含まれ、$1以降にはユーザー指定の引数が含まれます。 この行をスクリプトに追加します。スクリプトはコマンドラインから最初の引数を取り、それをpackageという変数に格納します。

go-executable-build.bash

...
package=$1

次に、ユーザーがこの値を指定したことを確認します。 値が提供されない場合は、スクリプトの使用方法を説明するメッセージでスクリプトを終了します。

go-executable-build.bash

...

if [[z "$package" ]]; then
  echo "usage: $0 "
  exit 1
fi

このifステートメントは、$package変数の値をチェックします。 設定されていない場合は、echoを使用して正しい使用法を出力し、exitを使用してスクリプトを終了します。 exitは引数として戻り値を取ります。これは、実行が成功した場合は0であり、実行が失敗した場合はゼロ以外の値である必要があります。 スクリプトが成功しなかったため、ここでは1を使用します。

[。注意]##

Note:このスクリプトを事前定義されたパッケージで機能させる場合は、package変数を変更してそのインポートパスを指すようにします。

go-executable-build.bash

...
package="github.com/user/hello"

次に、パスからパッケージ名を抽出します。 パッケージのインポートパスは/文字で区切られ、パッケージ名はパスの最後にあります。 まず、/を区切り文字として使用して、パッケージのインポートパスを配列に分割します。

go-executable-build.bash

package_split=(${package//\// })

パッケージ名は、この新しい$package_split配列の最後の要素である必要があります。 Bashでは、負の配列インデックスを使用して、先頭ではなく末尾から配列にアクセスできます。 この行を追加して、配列からパッケージ名を取得し、package_nameという変数に格納します。

go-executable-build.bash

...
package_name=${package_split[-1]}

次に、実行可能ファイルを構築するプラットフォームとアーキテクチャを決定する必要があります。 このチュートリアルでは、Windows 64ビット、Windows 32ビット、および64ビットmacOSの実行可能ファイルをビルドします。 これらのターゲットをOS/Platformの形式の配列に配置するので、パスからパッケージ名を抽出するために使用したのと同じ方法を使用して、各ペアをGOOS変数とGOARCH変数に分割できます。 。 プラットフォームをスクリプトに追加します。

go-executable-build.bash

...
platforms=("windows/amd64" "windows/386" "darwin/amd64")

次に、プラットフォームの配列を反復処理し、各プラットフォームエントリをGOOSおよびGOARCH環境変数の値に分割し、それらを使用して実行可能ファイルをビルドします。 次のforループでこれを行うことができます。

go-executable-build.bash

...
for platform in "${platforms[@]}"
do
    ...
done

platform変数には、各反復でplatforms配列からのエントリが含まれます。 platformを2つの変数(GOOSGOARCH)に分割する必要があります。 次の行をforループに追加します。

go-executable-build.bash

for platform in "${platforms[@]}"
do
    platform_split=(${platform//\// })
    GOOS=${platform_split[0]}
    GOARCH=${platform_split[1]}

done

次に、パッケージ名とOSおよびアーキテクチャを組み合わせて、実行可能ファイルの名前を生成します。 Windows用にビルドするときは、ファイル名に.exeサフィックスを追加する必要もあります。 このコードをforループに追加します。

go-executable-build.bash

for platform in "${platforms[@]}"
do
    platform_split=(${platform//\// })
    GOOS=${platform_split[0]}
    GOARCH=${platform_split[1]}

    output_name=$package_name'-'$GOOS'-'$GOARCH

    if [ $GOOS = "windows" ]; then
        output_name+='.exe'
    fi
done

変数を設定したら、go buildを使用して実行可能ファイルを作成します。 この行をforループの本体、doneキーワードのすぐ上に追加します。

go-executable-build.bash

...
    if [ $GOOS = "windows" ]; then
        output_name+='.exe'
    fi

    env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package

done

最後に、実行可能ファイルのビルド中にエラーが発生したかどうかを確認する必要があります。 たとえば、ソースを持たないパッケージをビルドしようとすると、エラーが発生する可能性があります。 go buildコマンドの戻りコードでゼロ以外の値を確認できます。 変数$?には、前のコマンドの実行からの戻りコードが含まれています。 go build0以外を返す場合は、問題が発生しているため、スクリプトを終了します。 このコードをforループに、go buildコマンドの後、doneキーワードの上に追加します。

go-executable-build.bash

...

    env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package

    if [ $? -ne 0 ]; then
        echo 'An error has occurred! Aborting the script execution...'
        exit 1
    fi

これで、Goパッケージから複数の実行可能ファイルをビルドするスクリプトができました。 完成したスクリプトは次のとおりです。

go-executable-build.bash

#!/usr/bin/env bash

package=$1
if [[z "$package" ]]; then
  echo "usage: $0 "
  exit 1
fi
package_split=(${package//\// })
package_name=${package_split[-1]}

platforms=("windows/amd64" "windows/386" "darwin/amd64")

for platform in "${platforms[@]}"
do
    platform_split=(${platform//\// })
    GOOS=${platform_split[0]}
    GOARCH=${platform_split[1]}
    output_name=$package_name'-'$GOOS'-'$GOARCH
    if [ $GOOS = "windows" ]; then
        output_name+='.exe'
    fi

    env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package
    if [ $? -ne 0 ]; then
        echo 'An error has occurred! Aborting the script execution...'
        exit 1
    fi
done

ファイルが前述のコードと一致することを確認します。 次に、ファイルを保存してエディターを終了します。

スクリプトを使用する前に、chmodコマンドを使用してスクリプトを実行可能にする必要があります。

chmod +x go-executable-build.bash

最後に、Caddyの実行可能ファイルを作成してスクリプトをテストします。

./go-executable-build.bash github.com/mholt/caddy/caddy

すべてがうまくいけば、現在のディレクトリに実行可能ファイルがあるはずです。 スクリプトが正常に実行されたことを示す出力はありません。 lsコマンドを使用して作成された実行可能ファイルであることを確認できます。

ls caddy*

3つのバージョンがすべて表示されるはずです。

Example ls outputcaddy-darwin-amd64 caddy-windows-386.exe caddy-windows-amd64.exe

ターゲットプラットフォームを変更するには、スクリプトのplatforms変数を変更するだけです。

結論

このチュートリアルでは、Goのツールを使用してバージョン管理システムからパッケージを取得する方法と、さまざまなプラットフォーム用の実行可能ファイルをビルドおよびクロスコンパイルする方法を学びました。

また、多くのプラットフォームで単一のパッケージをクロスコンパイルするために使用できるスクリプトを作成しました。

アプリケーションが正しく機能することを確認するために、WindowsでテストするためにTravis-CIAppVeyorのようなtestingcontinuous integrationを調べることができます。

キャディとその使用方法に興味がある場合は、How to Host a Website with Caddy on Ubuntu 16.04をご覧ください。