前書き
Goでは、build tag、つまりビルド制約は、build
プロセス中にファイルをパッケージに含めるタイミングを決定するコードに追加される識別子です。 これにより、同じソースコードからGoアプリケーションのさまざまなバージョンを構築し、それらを迅速かつ体系的に切り替えることができます。 多くの開発者はビルドタグを使用して、異なるオペレーティングシステム間の差異を考慮してコードの変更を必要とするプログラムなど、クロスプラットフォーム互換のアプリケーションを構築するワークフローを改善します。 ビルドタグはintegration testingにも使用されるため、統合コードとmock service or stubを含むコードをすばやく切り替えたり、アプリケーション内のさまざまなレベルの機能セットに使用したりできます。
顧客の機能セットが異なるという問題を例として見てみましょう。 一部のアプリケーションを作成するときは、Free、Pro、およびEnterpriseレベルを提供するアプリケーションなど、バイナリに含める機能を制御したい場合があります。 顧客がこれらのアプリケーションのサブスクリプションレベルを上げると、より多くの機能がロック解除されて利用可能になります。 この問題を解決するには、別々のプロジェクトを維持し、import
ステートメントを使用してそれらの同期を維持しようとします。 このアプローチは機能しますが、時間が経つと退屈でエラーが発生しやすくなります。 別のアプローチは、ビルドタグを使用することです。
この記事では、Goでビルドタグを使用して、サンプルアプリケーションのFree、Pro、およびEnterpriseの機能セットを提供するさまざまな実行可能バイナリを生成します。 それぞれに異なる機能セットが用意されており、無料版がデフォルトです。
前提条件
この記事の例を実行するには、次のものが必要です。
-
How To Install Go and Set Up a Local Programming Environmentに従ってセットアップされたGoワークスペース。
無料版の構築
ビルドタグなしでgo build
を実行するとデフォルトになるため、アプリケーションの無料バージョンをビルドすることから始めましょう。 後で、ビルドタグを使用して、プログラムに他のパーツを選択的に追加します。
src
ディレクトリに、アプリケーションの名前でフォルダを作成します。 このチュートリアルでは、app
を使用します。
mkdir app
このフォルダーに移動します。
cd app
次に、選択したテキストエディタでmain.go
という名前の新しいテキストファイルを作成します。
nano main.go
次に、アプリケーションの無料版を定義します。 次の内容をmain.go
に追加します。
main.go
package main
import "fmt"
var features = []string{
"Free Feature #1",
"Free Feature #2",
}
func main() {
for _, f := range features {
fmt.Println(">", f)
}
}
このファイルでは、features
という名前のsliceを宣言するプログラムを作成しました。このプログラムは、Freeアプリケーションの機能を表す2つのstringsを保持しています。 アプリケーションのmain()
関数は、features
スライスを介してfor
loop to range
を使用し、画面で使用可能なすべての機能を出力します。
ファイルを保存して終了します。 このファイルが保存されたので、記事の残りの部分で編集する必要はなくなりました。 代わりに、ビルドタグを使用して、そこからビルドするバイナリの機能を変更します。
プログラムをビルドして実行します。
go build
./app
次の出力が表示されます。
Output> Free Feature #1
> Free Feature #2
プログラムは2つの無料機能を印刷し、アプリの無料版を完成させました。
これまでのところ、非常に基本的な機能セットを持つアプリケーションを作成しました。 次に、ビルド時にアプリケーションに機能を追加する方法を構築します。
go build
を使用したPro機能の追加
これまで、main.go
に変更を加えることを避け、メインコードを変更したり、場合によっては壊したりせずにコードを追加する必要がある一般的な本番環境をシミュレートしました。 main.go
ファイルを編集できないため、ビルドタグを使用してfeatures
スライスにさらに多くの機能を挿入するための別のメカニズムを使用する必要があります。
init()
関数を使用してfeatures
スライスに機能を追加するpro.go
という新しいファイルを作成しましょう。
nano pro.go
エディターがファイルを開いたら、次の行を追加します。
pro.go
package main
func init() {
features = append(features,
"Pro Feature #1",
"Pro Feature #2",
)
}
このコードでは、init()
を使用して、アプリケーションのmain()
関数の前にコードを実行し、続いてappend()
を使用してPro機能をfeatures
スライスに追加しました。 ファイルを保存して終了します。
go build
を使用してアプリケーションをコンパイルして実行します。
go build
現在のディレクトリには2つのファイル(pro.go
とmain.go
)があるため、go build
は両方からバイナリを作成します。 このバイナリを実行します:
./app
これにより、次の機能セットが提供されます。
Output> Free Feature #1
> Free Feature #2
> Pro Feature #1
> Pro Feature #2
このアプリケーションには、Pro機能とFree機能の両方が含まれています。 ただし、これは望ましくありません。バージョンに区別がないため、無料版には現在、Proバージョンでのみ使用できるはずの機能が含まれています。 これを修正するには、アプリケーションのさまざまな層を管理するコードを追加するか、ビルドタグを使用して、ビルドする.go
ファイルと無視するファイルをGoツールチェーンに指示します。 次のステップでビルドタグを追加しましょう。
ビルドタグの追加
ビルドタグを使用して、アプリケーションのProバージョンと無料バージョンを区別できるようになりました。
ビルドタグがどのように見えるかを調べることから始めましょう。
// +build tag_name
このコード行をパッケージの最初の行として配置し、tag_name
をビルドタグの名前に置き換えることで、このパッケージに、最終的なバイナリに選択的に含めることができるコードとしてタグを付けることができます。 ビルドタグをpro.go
ファイルに追加して、タグが指定されていない限り無視するようにgo build
コマンドに指示して、これが実際に動作することを確認しましょう。 テキストエディターでファイルを開きます。
nano pro.go
次に、強調表示された次の行を追加します。
pro.go
// +build pro
package main
func init() {
features = append(features,
"Pro Feature #1",
"Pro Feature #2",
)
}
pro.go
ファイルの先頭に、// +build pro
を追加し、その後に空白の改行を追加しました。 この末尾の改行は必須です。それ以外の場合、Goはこれをコメントとして解釈します。 ビルドタグ宣言も.go
ファイルの一番上にある必要があります。 ビルドタグの上にあるものは、コメントでさえありません。
+build
宣言は、これがコメントではなく、ビルドタグであることをgo build
コマンドに通知します。 2番目の部分はpro
タグです。 このタグをpro.go
ファイルの先頭に追加することにより、go build
コマンドには、pro
タグが存在するpro.go
ファイルのみが含まれるようになります。
アプリケーションをコンパイルして再度実行します。
go build
./app
次の出力が表示されます。
Output> Free Feature #1
> Free Feature #2
pro.go
ファイルにはpro
タグが存在する必要があるため、ファイルは無視され、アプリケーションはそれなしでコンパイルされます。
go build
コマンドを実行する場合、-tags
フラグを使用して、タグ自体を引数として追加することにより、コンパイルされたソースに条件付きでコードを含めることができます。 pro
タグに対してこれを実行しましょう。
go build -tags pro
これは以下を出力します。
Output> Free Feature #1
> Free Feature #2
> Pro Feature #1
> Pro Feature #2
これで、pro
ビルドタグを使用してアプリケーションをビルドするときにのみ、追加機能を取得できます。
バージョンが2つしかない場合はこれで問題ありませんが、タグを追加すると複雑になります。 次のステップでアプリのエンタープライズバージョンを追加するには、ブールロジックで結合された複数のビルドタグを使用します。
ビルドタグブールロジック
Goパッケージに複数のビルドタグがある場合、タグはBoolean logicを使用して相互作用します。 これを示すために、pro
タグとenterprise
タグの両方を使用してアプリケーションのエンタープライズレベルを追加します。
エンタープライズバイナリを構築するには、デフォルト機能、プロレベルの機能、およびエンタープライズ向けの新しい機能セットの両方を含める必要があります。 まず、エディターを開き、新しいエンタープライズ機能を追加する新しいファイルenterprise.go
を作成します。
nano enterprise.go
enterprise.go
の内容は、pro.go
とほぼ同じように見えますが、新しい機能が含まれています。 ファイルに次の行を追加します。
enterprise.go
package main
func init() {
features = append(features,
"Enterprise Feature #1",
"Enterprise Feature #2",
)
}
ファイルを保存して終了します。
現在、enterprise.go
ファイルにはビルドタグがありません。pro.go
を追加したときに学習したように、これは、go.build
の実行時にこれらの機能が無料バージョンに追加されることを意味します。 pro.go
の場合、ファイルの先頭に// +build pro
と改行を追加して、-tags pro
が使用されている場合にのみ含める必要があることをgo build
に通知しました。 この状況では、目標を達成するために必要なビルドタグは1つだけです。 ただし、新しいエンタープライズ機能を追加する場合は、最初にPro機能も必要です。
まず、pro
ビルドタグのサポートをenterprise.go
に追加しましょう。 テキストエディターでファイルを開きます。
nano enterprise.go
次に、package main
宣言の前にビルドタグを追加し、ビルドタグの後に改行を含めるようにしてください。
enterprise.go
// +build pro
package main
func init() {
features = append(features,
"Enterprise Feature #1",
"Enterprise Feature #2",
)
}
ファイルを保存して終了します。
タグなしでアプリケーションをコンパイルして実行します。
go build
./app
次の出力が表示されます。
Output> Free Feature #1
> Free Feature #2
エンタープライズ機能は、無料版では表示されなくなりました。 次に、pro
ビルドタグを追加して、アプリケーションをビルドして再度実行します。
go build -tags pro
./app
次の出力が表示されます。
Output> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2
> Pro Feature #1
> Pro Feature #2
これはまだ必要なものではありません。Proバージョンをビルドしようとすると、エンタープライズ機能が表示されるようになりました。 これを解決するには、別のビルドタグを使用する必要があります。 ただし、pro
タグとは異なり、pro
機能とenterprise
機能の両方が使用可能であることを確認する必要があります。
Goビルドシステムは、ビルドタグシステムでいくつかの基本的なブールロジックの使用を許可することにより、この状況を考慮します。
enterprise.go
をもう一度開きましょう:
nano enterprise.go
pro
タグと同じ行に別のビルドタグenterprise
を追加します。
enterprise.go
// +build pro enterprise
package main
func init() {
features = append(features,
"Enterprise Feature #1",
"Enterprise Feature #2",
)
}
ファイルを保存して閉じます。
それでは、新しいenterprise
ビルドタグを使用してアプリケーションをコンパイルして実行しましょう。
go build -tags enterprise
./app
これにより、以下が得られます。
Output> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2
Pro機能が失われました。 これは、.go
ファイルの同じ行に複数のビルドタグを配置すると、go build
がそれらをOR
ロジックを使用していると解釈するためです。 行// +build pro enterprise
を追加すると、eitherがpro
ビルドタグであるか、enterprise
ビルドタグが存在する場合、enterprise.go
ファイルがビルドされます。 ビルドタグを正しく設定してbothを要求し、代わりにAND
ロジックを使用する必要があります。
両方のタグを同じ行に配置する代わりに、別々の行に配置すると、go build
はAND
ロジックを使用してそれらのタグを解釈します。
もう一度enterprise.go
を開き、ビルドタグを複数の行に分けましょう。
enterprise.go
// +build pro
// +build enterprise
package main
func init() {
features = append(features,
"Enterprise Feature #1",
"Enterprise Feature #2",
)
}
次に、新しいenterprise
ビルドタグを使用してアプリケーションをコンパイルして実行します。
go build -tags enterprise
./app
次の出力が表示されます。
Output> Free Feature #1
> Free Feature #2
まだ完全ではありません。AND
ステートメントでは両方の要素をtrue
と見なす必要があるため、pro
とenterprise
の両方のビルドタグを使用する必要があります。
もう一度試してみましょう。
go build -tags "enterprise pro"
./app
次の出力が表示されます。
Output> Free Feature #1
> Free Feature #2
> Enterprise Feature #1
> Enterprise Feature #2
> Pro Feature #1
> Pro Feature #2
これで、複数の方法で同じソースツリーからアプリケーションを構築し、それに応じてアプリケーションの機能をロック解除できます。
この例では、新しい// +build
タグを使用してAND
ロジックを示していますが、ビルドタグを使用してブールロジックを表す別の方法があります。 次の表には、ビルドタグの他の構文フォーマットの例と、それに相当するブール値が含まれています。
ビルドタグの構文 | タグサンプルの作成 | ブールステートメント |
---|---|---|
スペースで区切られた要素 |
|
|
カンマ区切りの要素 |
|
|
感嘆符の要素 |
|
|
結論
このチュートリアルでは、ビルドタグを使用して、どのコードをバイナリにコンパイルするかを制御できるようにしました。 最初に、ビルドタグを宣言し、それらをgo build
で使用し、次にブール論理で複数のタグを組み合わせました。 次に、無料版、プロ版、およびエンタープライズ版のさまざまな機能セットを表すプログラムを作成し、ビルドタグでプロジェクトを制御できる強力なレベルの制御を示しました。
ビルドタグについて詳しく知りたい場合は、Golang documentation on the subjectを確認するか、引き続きHow To Code in Go seriesを調べてください。