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

Goは、複数のプラットフォームのサポートを直接に組み込むことで、この問題を解決します。 go build ツール、およびGoツールチェーンの残りの部分。 環境変数およびビルドタグを使用することで、プラットフォームの包含をすばやく切り替えることができるワークフローをまとめるだけでなく、最終的なバイナリを構築するOSとアーキテクチャを制御できます。コードベースを変更せずに依存するコード。

このチュートリアルでは、文字列をファイルパスに結合するサンプルアプリケーションをまとめ、プラットフォームに依存するスニペットを作成して選択的に含め、独自のシステムで複数のオペレーティングシステムとシステムアーキテクチャのバイナリを構築します。 Goプログラミング言語のこの強力な機能を使用する方法を説明します。

前提条件

この記事の例に従うには、次のものが必要です。

可能なプラットフォーム GOOSGOARCH

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

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

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

  1. go tool dist list

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

Output
aix/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では、これらのオペレーティングシステムは環境変数の可能な値です GOOS、「goose」と発音します。これは、 Go OperatingSystemの略です。 後の2番目の部分 /、はアーキテクチャです。 前と同じように、これらはすべて環境変数の可能な値です。 GOARCH. これは「gore-ch」と発音され、 GoArchitectureの略です。

これらの組み合わせの1つを分解して、それが何を意味し、どのように機能するかを理解しましょう。 linux/386 例として。 キーと値のペアは、 GOOS、この例では linux LinuxOSを参照してください。 The GOARCH ここになります 386Intel80386マイクロプロセッサの略です。

で利用可能な多くのプラットフォームがあります go build コマンドですが、ほとんどの場合、使用することになります linux , windows、 また darwin の値として GOOS. これらは、 Linux Windows 、およびDarwinオペレーティングシステムに基づくmacOSの3つの大きなOSプラットフォームをカバーしています。と呼ばれる darwin. ただし、Goは、次のような主流ではないプラットフォームもカバーできます。 naclGoogleのネイティブクライアントを表します。

次のようなコマンドを実行すると go build、Goは現在のプラットフォームを使用します GOOSGOARCH バイナリの構築方法を決定します。 プラットフォームの組み合わせを確認するには、 go env コマンドとパス GOOSGOARCH 引数として:

  1. go env GOOS GOARCH

この例のテストでは、 AMD64アーキテクチャを搭載したマシンのmacOSでこのコマンドを実行したため、次の出力が表示されます。

Output
darwin amd64

ここで、コマンドの出力は、私たちのシステムが持っていることを示しています GOOS=darwinGOARCH=amd64.

あなたは今何を知っています GOOSGOARCH Goにあり、それらの可能な値も同様です。 次に、これらの環境変数を使用してタグを作成し、他のプラットフォームのバイナリを作成する方法の例として使用するプログラムをまとめます。

プラットフォームに依存するプログラムを作成する filepath.Join()

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

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

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

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

  1. mkdir app

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

  1. cd app

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

  1. nano main.go

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

src / app / main.go
package main

import (
  "fmt"
  "path/filepath"
)

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

The main() このファイルの関数は filepath.Join() 3つの文字列を、プラットフォームに依存する正しいパス区切り文字と連結します。

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

  1. go run main.go

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

Output
a\b\c

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

Output
a/b/c

これは、これらのオペレーティングシステムで使用されるファイルシステムプロトコルが異なるため、プログラムがプラットフォームごとに異なるコードを作成する必要があることを示しています。 ただし、OSによってはすでに異なるファイルセパレータを使用しているため、 filepath.Join() すでにプラットフォームの違いを説明しています。 これは、Goツールチェーンがマシンのを自動的に検出するためです。 GOOSGOARCH この情報を使用して、適切なビルドタグとファイルセパレータを備えたコードスニペットを使用します。

どこで filepath.Join() 関数はからセパレータを取得します。 次のコマンドを実行して、Goの標準ライブラリから関連するスニペットを調べます。

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

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

/usr/local/go/os/path_unix.go
. . .
// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris

package os

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

このセクションでは、 PathSeparator Goがサポートするあらゆる種類のUnixライクなシステムに対応します。 上部にあるすべてのビルドタグに注目してください。これらはそれぞれ、可能なUnixの1つです。 GOOS Unixに関連するプラットフォーム。 いつ GOOS これらの用語に一致すると、プログラムはUnixスタイルのファイルパスセパレータを生成します。

プレス q コマンドラインに戻ります。

次に、の動作を定義するファイルを開きます filepath.Join() Windowsで使用する場合:

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

次のように表示されます。

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

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

の値が PathSeparator\\ ここでは、コードは単一の円記号をレンダリングします(\)最初の円記号はエスケープ文字としてのみ必要なため、Windowsファイルパスに必要です。

Unixファイルとは異なり、上部にビルドタグがないことに注意してください。 それの訳は GOOSGOARCH に渡すこともできます go build アンダースコアを追加する(_)およびファイル名のサフィックスとしての環境変数値については、GOOSおよびGOARCHファイル名のサフィックスの使用のセクションで詳しく説明します。 ここでは、 _windows 一部の path_windows.go ファイルにビルドタグがあるかのように動作させます // +build windows ファイルの先頭にあります。 このため、プログラムをWindowsで実行すると、次の定数が使用されます。 PathSeparatorPathListSeparator から path_windows.go コードスニペット。

コマンドラインに戻るには、終了します less を押すことによって q.

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

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

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

あなたの main.go ファイル:

  1. nano main.go

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

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)
}

The Join 関数はいくつかを取ります parts 文字列パッケージstrings.Join()メソッドを使用してそれらを結合し、 parts 一緒に使用して PathSeparator.

あなたは定義していません PathSeparator それでも、別のファイルでそれを実行してください。 保存して終了します main.go、お気に入りのエディタを開き、という名前の新しいファイルを作成します path.go:

nano path.go

を定義する PathSeparator Unixファイルパスセパレータと同じに設定します。 /:

src / app / path.go
package main

const PathSeparator = "/"

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

  1. go build
  2. ./app

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

Output
a/b/c

これは正常に実行され、Unixスタイルのファイルパスを取得します。 しかし、これはまだ私たちが望んでいることではありません。出力は常に a/b/c、実行するプラットフォームに関係なく。 Windowsスタイルのファイルパスを作成する機能を追加するには、Windowsバージョンの PathSeparator と言う go build 使用するバージョンをコマンドします。 次のセクションでは、ビルドタグを使用してこれを実現します。

使用する GOOS また GOARCH タグを作成する

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

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

  1. nano path.go

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

src / app / path.go
// +build !windows

package main

const PathSeparator = "/"

Goビルドタグでは反転が可能です。つまり、Windowsを除くすべてのプラットフォームでこのファイルをビルドするようにGoに指示できます。 ビルドタグを反転するには、 ! タグの前。

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

ここで、このプログラムをWindowsで実行すると、次のエラーが発生します。

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

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

これで、次のことを確認できました path.go 次の場合は実行されません GOOS Windowsの場合、新しいファイルを追加します。 windows.go:

  1. nano windows.go

windows.go、Windowsを定義します PathSeparator、およびビルドタグを使用して go build コマンドはそれがWindowsの実装であることを知っています:

src / app / windows.go
// +build windows

package main

const PathSeparator = "\\"

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

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

ローカルを使用する GOOSGOARCH 環境変数

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

The go build コマンドは、 go env 指図。 どちらかを設定できます GOOS また GOARCH を使用して別のプラットフォーム用に構築する環境変数 go build.

Windowsシステムを使用していない場合は、 windows のバイナリ app を設定することによって GOOS 環境変数から windows 実行時 go build 指図:

  1. GOOS=windows go build

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

  1. ls

ディレクトリを一覧表示する出力は、現在、 app.exe プロジェクトディレクトリ内のWindows実行可能ファイル:

Output
app app.exe main.go path.go windows.go

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

  1. file app.exe

あなたは受け取るでしょう:

Output
app.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows

ビルド時に一方または両方の環境変数を設定することもできます。 次を実行します。

  1. GOOS=linux GOARCH=ppc64 go build

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

  1. file app

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

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

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

使用する GOOSGOARCH ファイル名のサフィックス

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

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

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

  1. mv path.go path_unix.go
  2. mv windows.go path_windows.go

2つのファイル名を変更すると、追加したビルドタグを削除できます path_windows.go:

  1. 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ツールチェーンの強力な機能です。 このチュートリアルでは、ビルドタグとファイル名のサフィックスを追加してこの機能を使用し、特定のアーキテクチャでのみコンパイルする特定のコードスニペットをマークしました。 独自のplatorm依存プログラムを作成してから、 GOOSGOARCH 現在のプラットフォーム以外のプラットフォームのバイナリを生成するための環境変数。 これらの環境変数を自動的に実行してすべてのプラットフォームのバイナリを構築する継続的インテグレーションプロセスを使用するのが一般的な方法であるため、これは貴重なスキルです。

さらなる研究のために go buildビルドタグを使用したGoバイナリのカスタマイズチュートリアルをご覧ください。 Goプログラミング言語全般について詳しく知りたい場合は、Goシリーズのコーディング方法全体を確認してください。