さまざまなオペレーティングシステムとアーキテクチャ向けのGoアプリケーションの構築

ソフトウェア開発では、https://en.wikipedia.org/wiki/Operating_system [オペレーティングシステム]および基盤となるプロセッサhttps://en.wikipedia.org/wiki/Microarchitecture [アーキテクチャ]を検討することが重要ですバイナリをコンパイルします。 多くの場合、異なるOS /アーキテクチャプラットフォームでバイナリを実行するのは遅いか不可能であるため、プログラムの視聴者を最大化するために、多くの異なるプラットフォームで最終的なバイナリを構築するのが一般的です。 ただし、開発に使用しているプラ​​ットフォームがプログラムのデプロイ先のプラットフォームと異なる場合、これは困難な場合があります。 過去には、たとえば、Windowsでプログラムを開発してLinuxまたはmacOSマシンに展開するには、バイナリが必要な環境ごとにビルドマシンをセットアップする必要がありました。 また、コストを追加し、共同テストと配布をより困難にする他の考慮事項に加えて、ツールの同期を維持する必要があります。

Goは、複数のプラットフォームのサポートを「+ go build」ツールとGoツールチェーンの残りの部分に直接組み込むことで、この問題を解決します。 environment variablesおよびhttps://を使用してwww.digitalocean.com/community/tutorials/customizing-go-binaries-with-build-tags[build tags]では、最終的なバイナリがどのOSおよびアーキテクチャ向けに構築されているかを制御できます。コードベースを変更せずにプラットフォーム依存コードの包含を切り替えます。

このチュートリアルでは、https://www.digitalocean.com/community/tutorials/an-introduction-to-working-with-strings-in-go [strings]をファイルパスに結合するサンプルアプリケーションを作成します。プラットフォーム依存のスニペットを作成して選択的に組み込み、独自のシステムで複数のオペレーティングシステムとシステムアーキテクチャのバイナリをビルドし、Goプログラミング言語のこの強力な機能の使用方法を示します。

前提条件

この記事の例を実行するには、次のものが必要です。

  • Goのインストール方法に従ってセットアップされたGoワークスペースローカルプログラミング環境のセットアップ]。

`+ GOOS `および ` GOARCH +`の可能なプラットフォーム

ビルドプロセスを制御してさまざまなプラットフォームのバイナリをビルドする方法を示す前に、Goがビルドできるプラットフォームの種類と、Goが環境変数 `+ GOOS `および ` GOARCH +`を使用してこれらのプラットフォームを参照する方法を最初に調べましょう。

Goツールには、Goが構築できるプラットフォームのリストを印刷できるコマンドがあります。 このリストは、Goの新しいリリースごとに変更される可能性があるため、ここで説明する組み合わせは、Goの別のバージョンでは同じではない場合があります。 このチュートリアルを書いている時点では、現在のGoリリースはhttps://golang.org/doc/go1.13 [+ 1.13 +]です。

可能なプラットフォームのこのリストを見つけるには、次を実行します。

go tool dist list

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

Outputaix/ppc64        freebsd/amd64   linux/mipsle   openbsd/386
android/386      freebsd/arm     linux/ppc64    openbsd/amd64
android/amd64    illumos/amd64   linux/ppc64le  openbsd/arm
android/arm      js/wasm         linux/s390x    openbsd/arm64
android/arm64    linux/386       nacl/386       plan9/386
darwin/386       linux/amd64     nacl/amd64p32  plan9/amd64
darwin/amd64     linux/arm       nacl/arm       plan9/arm
darwin/arm       linux/arm64     netbsd/386     solaris/amd64
darwin/arm64     linux/mips      netbsd/amd64   windows/386
dragonfly/amd64  linux/mips64    netbsd/arm     windows/amd64
freebsd/386      linux/mips64le  netbsd/arm64   windows/arm

この出力は、「+ / 」で区切られたキーと値のペアのセットです。 組み合わせの「 / 」の前の最初の部分は、オペレーティングシステムです。 Goでは、これらのオペレーティングシステムは、「Goose」と発音される環境変数「 GOOS 」の可能な値であり、これは* Go Operating System *の略です。 ` / `の後の2番目の部分はアーキテクチャです。 前と同様に、これらはすべて環境変数の可能な値です: ` GOARCH +`。 これは「gore-ch」と発音され、* Go Architecture *の略です。

例として `+ linux / 386 `を使用して、これらの組み合わせの1つを分解して、その意味と動作を理解しましょう。 キーと値のペアは「 GOOS 」で始まります。この例では、https://www.digitalocean.com/community/tutorial_series/getting-started-with-linux [Linux OS]。 ここでの「 GOARCH 」は「+386」であり、https://en.wikipedia.org/wiki/Intel_80386 [Intel 80386マイクロプロセッサ]を表します。

「+ go build」コマンドで使用できるプラットフォームは多数ありますが、ほとんどの場合、「+ GOOSe」の値として「+ linux 」、「 windows 」、または「 darwin 」を使用することになります。 これらは、https://en.wikipedia.org/wiki/Linux [Linux]、https://en.wikipedia.org/wiki/Microsoft_Windows [Windows]、およびhttps://en.wikipediaの3つのOSプラットフォームをカバーしています。 .org / wiki / MacOS [macOS]。これはhttps://en.wikipedia.org/wiki/Darwin_(operating_system)[Darwin operating system]に基づいているため、「 darwin 」と呼ばれます。 ただし、Goはhttps://developer.chrome.com/native-client[Googleのネイティブクライアント]を表す ` nacl +`のようなあまり主流ではないプラットフォームもカバーできます。

+ go build +`のようなコマンドを実行すると、Goは現在のプラットフォームの `+ GOOS`と + GOARCH`を使用して、バイナリのビルド方法を決定します。 プラットフォームの組み合わせを確認するには、 `+ go env `コマンドを使用して、引数として ` GOOS `と ` GOARCH +`を渡します。

go env GOOS GOARCH

この例をテストする際に、https://en.wikipedia.org/wiki/X86-64 [AMD64 architecture]のマシンでmacOSでこのコマンドを実行したため、次の出力を受け取ります。

Output

ここで、コマンドの出力は、システムに `+ GOOS = darwin `および ` GOARCH = amd64 +`があることを示しています。

これで、Goでの `+ GOOS `と ` GOARCH +`の値と、可能な値がわかりました。 次に、これらの環境変数を使用してタグを作成し、他のプラットフォーム用のバイナリを作成する方法の例として使用するプログラムを作成します。

`+ filepath.Join()+`でプラットフォーム依存のプログラムを書く

他のプラットフォーム用のバイナリの作成を開始する前に、サンプルプログラムを作成しましょう。 この目的に適したサンプルは、Go標準ライブラリのhttps://godoc.org/path/filepath [+ path / filepath +]パッケージの `+ Join +`関数です。 この関数はいくつかの文字列を受け取り、正しいファイルパス区切り文字で結合された1つの文字列を返します。

プログラムの動作は実行しているOSに依存するため、これは良いサンプルプログラムです。 Windowsでは、パス区切り文字はバックスラッシュ「+ \ 」ですが、Unixベースのシステムではスラッシュ「 / +」を使用します。

まず、 `+ filepath.Join()`を使用するアプリケーションの構築から始めましょう。その後、コードをプラットフォーム固有のバイナリにカスタマイズする ` Join()+`関数の独自の実装を記述します。

まず、アプリの名前で `+ src +`ディレクトリにフォルダーを作成します:

mkdir

そのディレクトリに移動します。

cd

次に、 `+ main.go +`という名前のテキストエディターで新しいファイルを作成します。 このチュートリアルでは、Nanoを使用します。

nano main.go

ファイルが開いたら、次のコードを追加します。

src / app / main.go

package main

import (
 "fmt"
 "path/filepath"
)

func main() {
 s := filepath.Join("a", "b", "c")
 fmt.Println(s)
}

このファイルの「+ main()」関数は「 filepath.Join()+」を使用して3つのhttps://www.digitalocean.com/community/tutorials/an-introduction-to-working-with-stringsを連結します-in-go [strings]と正しいプラットフォーム依存のパス区切り文字。

ファイルを保存して終了し、プログラムを実行します。

go run main.go

このプログラムを実行すると、使用しているプラ​​ットフォームに応じて異なる出力を受け取ります。 Windowsでは、「+ \ +」で区切られた文字列が表示されます。

Outputabc

macOSやLinuxなどのUnixシステムでは、次のものを受け取ります。

Outputabc

これは、これらのオペレーティングシステムで使用されるファイルシステムプロトコルが異なるため、プログラムはプラットフォームごとに異なるコードを構築する必要があることを示しています。 しかし、OSに応じて異なるファイルセパレータをすでに使用しているため、 `+ filepath.Join()`はすでにプラットフォームの違いを考慮していることがわかります。 これは、Goツールチェーンがマシンの ` GOOS `および ` GOARCH +`を自動的に検出し、この情報を使用して正しいhttps://www.digitalocean.com/community/tutorials/customizing-go-のコードスニペットを使用するためです。 binaries-with-build-tags [ビルドタグ]とファイルセパレータ。

`+ filepath.Join()+`関数がセパレータを取得する場所を考えてみましょう。 次のコマンドを実行して、Goの標準ライブラリから関連するスニペットを検査します。

less /usr/local/go/src/os/path_unix.go

これにより、 `+ path_unix.go +`の内容が表示されます。 ファイルの次の部分を探します。

/usr/local/go/os/path_unix.go

. . .


package os

const (
 PathSeparator     = '/' // OS-specific path separator
 PathListSeparator = ':' // OS-specific path list separator
)
. . .

このセクションでは、GoがサポートするすべてのUnixライクシステムの `+ PathSeparator `を定義します。 上部のすべてのビルドタグに注目してください。これらは、Unixに関連付けられている可能性のあるUnix ` GOOS `プラットフォームのそれぞれです。 ` GOOS +`がこれらの用語に一致すると、プログラムはUnixスタイルのファイルパス区切り文字を生成します。

コマンドラインに戻るには、「+ q +」を押します。

次に、Windowsで使用するときの `+ filepath.Join()+`の動作を定義するファイルを開きます。

less /usr/local/go/src/os/path_windows.go

以下が表示されます。

/usr/local/go/os/path_unix.go

. . .
package os

const (
       PathSeparator     = '\\' // OS-specific path separator
       PathListSeparator = ';'  // OS-specific path list separator
)
. . .

ここでは + PathSeparator +`の値は `+ \\ +`ですが、最初のバックスラッシュはエスケープ文字としてのみ必要なので、コードはWindowsファイルパスに必要な単一のバックスラッシュ( `+ \ +)をレンダリングします。

Unixファイルとは異なり、上部にビルドタグがないことに注意してください。 これは、アンダースコア( + _ +)と環境変数値をファイル名のサフィックスとして追加することで、 `+ GOOS `と ` GOARCH `を ` go build `に渡すことができるためです。セクションhttps://www.digitalocean.com/community/tutorials/building-go-applications-for-different-operating-systems-and-architectures#using-goos-and-goarch-filename-suffixes[*Using GOOSおよびGOARCHファイル名サフィックス*]。 ここで、 ` path_windows.go `の ` _windows `部分は、ファイルの上部にビルドタグ ` // + build windows `があるかのようにファイルを動作させます。 このため、プログラムをWindowsで実行する場合、コードスニペットの ` PathSeparator `と ` PathListSeparator +`の定数を使用します。

コマンドラインに戻るには、「+ q 」を押して「 less +」を終了します。

このステップでは、Goがどのように `+ GOOS `と ` GOARCH `をビルドタグに自動的に変換するかを示すプログラムをビルドしました。 これを念頭に置いて、プログラムを更新し、ビルドタグを使用してWindowsおよびUnixプラットフォーム用の正しい ` PathSeparator `を手動で設定して、 ` filepath.Join()+`の独自の実装を記述できるようになりました。

プラットフォーム固有の機能の実装

Goの標準ライブラリがプラットフォーム固有のコードを実装する方法がわかったので、ビルドタグを使用して独自の `+`プログラムでこれを行うことができます。 これを行うには、 ` filepath.Join()+`の独自の実装を記述します。

`+ main.go +`ファイルを開きます:

nano main.go

`+ Join()`と呼ばれる独自の関数を使用して、 ` main.go +`の内容を次のものに置き換えます。

src / app / main.go

package main

import (
 "fmt"
 "strings"
)

func Join(parts ...string) string {
 return strings.Join(parts, PathSeparator)
}

func main() {
 s := Join("a", "b", "c")
 fmt.Println(s)
}

+ Join +`関数はいくつかの `+ parts +`を受け取り、https:// wwwのhttps://godoc.org/strings.Join [+ strings.Join()`]メソッドを使用してそれらを結合します.digitalocean.com / community / tutorials / an-introduction-to-the-strings-package-in-go [` strings ` package]は、 ` PathSeparator `を使用して ` parts +`を連結します。

`+ PathSeparator `をまだ定義していないので、別のファイルで定義します。 保存して ` main.go `を終了し、お気に入りのエディターを開き、 ` path.go +`という名前の新しいファイルを作成します。

nano path.go

`+ PathSeparator `を定義し、Unixファイルパス区切り文字 ` / +`と等しく設定します。

src / app / path.go

package main

const PathSeparator = "/"

アプリケーションをコンパイルして実行します。

go build
./app

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

Outputa/b/c

これは正常に実行され、Unixスタイルのファイルパスを取得します。 しかし、これはまだ私たちが望んでいるものではありません。実行するプラットフォームに関係なく、出力は常に「+ a / b / c 」です。 Windowsスタイルのファイルパスを作成する機能を追加するには、Windowsバージョンの ` PathSeparator `を追加し、使用するバージョンを ` go build +`コマンドに伝える必要があります。 次のセクションでは、https://www.digitalocean.com/community/tutorials/customizing-go-binaries-with-build-tags [build tags]を使用してこれを実現します。

`+ GOOS `または ` GOARCH +`ビルドタグの使用

Windowsプラットフォームを説明するために、 `+ path.go `の代替ファイルを作成し、ビルドタグを使用して、 ` GOOS `と ` GOARCH +`が適切なプラットフォームである場合にのみコードスニペットが実行されるようにします。

しかし、最初に、ビルドタグを `+ path.go +`に追加して、Windows以外のすべてのためにビルドするように指示します。 ファイルを開きます。

nano path.go

次の強調表示されたビルドタグをファイルに追加します。

src / app / path.go

package main

const PathSeparator = "/"

Goビルドタグは反転を許可します。つまり、Windows以外のプラットフォーム用にこのファイルをビルドするようにGoに指示できます。 ビルドタグを反転するには、タグの前に「!」を配置します。

ファイルを保存して終了します。

このプログラムをWindowsで実行すると、次のエラーが表示されます。

Output./main.go:9:29: undefined: PathSeparator

この場合、Goは変数「+ PathSeparator 」を定義するために「 path.go +」を含めることができません。

`+ GOOS `がWindowsの場合に ` path.go `が実行されないようにしたので、新しいファイル ` windows.go +`を追加します。

nano windows.go

`+ windows.go `で、Windowsの ` PathSeparator `を定義するとともに、 ` go build +`コマンドにWindows実装であることを知らせるビルドタグを定義します。

src / app / windows.go

// +build windows

package main

const PathSeparator = "\\"

ファイルを保存し、テキストエディターを終了します。 これで、アプリケーションはWindows用に別の方法でコンパイルし、他のすべてのプラットフォーム用に別の方法でコンパイルできます。

バイナリはプラットフォーム用に正しくビルドされるようになりましたが、アクセスできないプラットフォーム用にコンパイルするためにさらに変更する必要があります。 これを行うには、次のステップでローカルの `+ GOOS `および ` GOARCH +`環境変数を変更します。

ローカルの `+ GOOS `および ` GOARCH +`環境変数を使用する

以前、「+ go env GOOS GOARCH 」コマンドを実行して、作業中のOSとアーキテクチャを確認しました。 ` go env `コマンドを実行すると、2つの環境変数 ` GOOS `および ` GOARCH `が検索されました。見つかった場合、それらの値が使用されますが、見つからない場合、Goはそれらに現在のプラットフォームの情報を設定します。 つまり、デフォルトのローカルOSとアーキテクチャにならないように、「 GOOS 」または「 GOARCH +」を変更できます。

+ go build`コマンドは、 + go env`コマンドと同じように動作します。 環境変数 `+ GOOS `または ` GOARCH `を設定して、 ` go build +`を使用して別のプラットフォーム用にビルドできます。

Windowsシステムを使用していない場合、 `+ go build `コマンドの実行時に ` GOOS `環境変数を ` windows `に設定して、 `+`の `+ windows +`バイナリをビルドします。

GOOS=windows go build

次に、現在のディレクトリ内のファイルをリストします。

ls

ディレクトリのリストの出力は、プロジェクトディレクトリに + app.exe + Windows実行可能ファイルがあることを示しています。

Outputapp    main.go  path.go  windows.go

`+ file`コマンドを使用すると、このファイルに関する詳細情報を取得して、ビルドを確認できます。

file app.exe

受け取るもの:

Outputapp.exe: PE32+ executable (console) x86-64 (stripped to external PDB),

ビルド時に一方または両方の環境変数を設定することもできます。 以下を実行してください。

GOOS=linux GOARCH=ppc64 go build

`+`実行可能ファイルは、異なるアーキテクチャのファイルに置き換えられます。 このバイナリで ` file`コマンドを実行します:

file app

次のような出力を受け取ります。

app: ELF 64-bit MSB executable, , version 1 (SYSV), statically linked, not stripped

ローカルの `+ GOOS `および ` GOARCH +`環境変数を設定することで、複雑な設定やセットアップなしで、Goの互換性のあるプラットフォーム向けにバイナリを構築できるようになりました。 次に、ファイル名の規則を使用して、ファイルをきちんと整理し、特定のプラットフォーム用にビルドタグなしで自動的にビルドします。

`+ GOOS `および ` GOARCH +`ファイル名サフィックスの使用

前に見たように、Go標準ライブラリはビルドタグを多用し、異なるプラットフォーム実装を異なるファイルに分離することでコードを簡素化します。 `+ os / path_unix.go `ファイルを開いたとき、Unixライクなプラットフォームと考えられるすべての可能な組み合わせをリストしたビルドタグがありました。 しかし、 ` os / path_windows.go +`ファイルにはビルドタグが含まれていません。これは、ファイル名の接尾辞が、ファイルがどのプラットフォームを対象としているかをGoに伝えるのに十分だからです。

この機能の構文を見てみましょう。 + .go +`ファイルに名前を付けるとき、ファイル名にサフィックスとして `+ GOOS +`と `+ GOARCH +`をこの順序で追加し、値をアンダースコア( `+ _ +)で区切ります。 `+ filename.go `という名前のGoファイルがある場合、ファイル名を ` filename __。go `に変更することでOSとアーキテクチャを指定できます。 たとえば、64ビットhttps://en.wikipedia.org/wiki/ARM_architecture[ARMアーキテクチャ]でWindows用にコンパイルする場合、ファイルの名前を ` filename_windows_arm64.go +`にします。 この命名規則は、コードをきちんと整理するのに役立ちます。

ビルドタグの代わりにファイル名のサフィックスを使用するようにプログラムを更新します。 最初に、 `+ os `パッケージで使用される規則を使用するために、 ` path.go `および ` windows.go +`ファイルの名前を変更します。

mv path.go path_unix.go
mv windows.go path_windows.go

2つのファイル名を変更したら、 `+ path_windows.go +`に追加したビルドタグを削除できます。

nano path_windows.go

ファイルが次のようになるように、 `+ // + build windows +`を削除します。

path_windows.go

package main

const PathSeparator = "\\"

ファイルを保存して終了します。

`+ unix `は有効な ` GOOS `ではないため、 ` _unix.go `サフィックスはGoコンパイラにとって意味がありません。 ただし、ファイルの意図された目的は伝えます。 ` os / path_unix.go `ファイルと同様に、 ` path_unix.go +`ファイルはビルドタグを使用する必要があるため、そのファイルを変更しないでください。

ファイル名の規則を使用することにより、ソースコードから不要なビルドタグを削除し、ファイルシステムをよりクリーンで明確にしました。

結論

依存関係を必要としない複数のプラットフォーム用のバイナリを生成する機能は、Goツールチェーンの強力な機能です。 このチュートリアルでは、ビルドタグとファイル名サフィックスを追加してこの機能を使用し、特定のアーキテクチャ用にのみコンパイルするように特定のコードスニペットをマークしました。 独自のプラッタ依存プログラムを作成してから、 + GOOS`および + GOARCH`環境変数を操作して、現在のプラットフォーム以外のプラットフォーム用のバイナリを生成しました。 これは貴重なスキルです。なぜなら、これらの環境変数を自動的に実行してすべてのプラットフォーム用のバイナリを構築する継続的な統合プロセスを持つのが一般的な方法だからです。

「+ go build +」の詳細については、https://www.digitalocean.com/community/tutorials/customizing-go-binaries-with-build-tags [ビルドタグを使用したGoバイナリのカスタマイズ]チュートリアルをご覧ください。 Goプログラミング言語全般について詳しく知りたい場合は、https://www.digitalocean.com/community/tutorial_series/how-to-code-in-go [Goのコーディング方法シリーズ]全体をご覧ください。 ]。