go buildを使用した条件コンパイル

5102 ワード

私たちが作成したgoコードが特定のプラットフォームやcpuアーキテクチャに依存している場合、私たちは異なる実装を与える必要があります.
C言語にはプリプロセッサがあり、マクロまたは#defineが特定のプラットフォームで指定したコードを含んでコンパイルすることができる
しかし、Goにはプリプロセッサがありません.彼はgo/buildパッケージで定義されたtagsと命名規則を通じて、Goのパッケージが異なるプラットフォームのコードを管理することができます.
この記事では,Goの条件コンパイルシステムがどのように実現され,使用方法を実例で説明する
1.予備知識:go listコマンドの使用
条件コンパイルを話す前にgo listの簡単な使い方を理解する必要があります
go listアクセスソースファイルのコンパイルプロセス内部に影響を及ぼすデータ構造
go listはgo build,test,installのほとんどのパラメータと同じですが、go listはコンパイル操作を実行しません.-fパラメータを使用すると、私たちが提供するtext/templateのコードにgo/buildを含めることができます.Packageコンテキストの環境で正しく実行する(go/build.Packageのコンテキストをtext/templateのこのフォーマット'{.GoFiles}'のプレースホルダをフォーマットさせ、http serverプログラムを書いたことがある学生はよく知っているはずだ)
フォーマットパラメータを使用すると、goリストからコンパイルされるファイル名を取得できます.
% go list -f '{{.GoFiles}}' os/exec
[exec.go lp_unix.go]

上記の例では、linux/armプラットフォームの下でos/execパッケージにコンパイルされるファイルをgo listで表示します.
結果:exec.goには共通のコードが含まれています.すべてのプラットフォームで使用できます.lp_unix.goには*nixシステムのexecが含まれています.LookPath
Windowsシステムで同じコマンドを実行すると、次のようになります.
C:\go> go list -f '{{.GoFiles}}' os/exec
[exec.go lp_windows.go]

上の例はGo条件コンパイルシステムの2つの部分であり、コンパイル制約と呼ばれ、以下で詳細に説明する.
2.第一条件のコンパイル方法:ラベルのコンパイル
ソースコードに寸法を追加し、通常はコンパイルラベル(build tag)と呼ばれます.
コンパイルラベルは、ソースファイルの上部にできるだけ近い場所にコメントで追加されます.
go buildは、パッケージを構築するときに、このパッケージの各ソースファイルを読み取り、コンパイルメモを分析します.これらのラベルは、このソースファイルが今回のコンパイルに参加するかどうかを決定します.
ラベルをコンパイルして追加するルール(原文を添付):
1. a build tag is evaluated as the OR of space-separated options 2. each option evaluates as the AND of its comma-separated terms 3. each term is an alphanumeric word or, preceded by !, its negation
1). コンパイルラベルは、スペースで区切られたコンパイルオプション(options)で「または」の論理関係で構成されます.
2). 各コンパイルオプションは、カンマで区切られた条件アイテムで論理的に「と」の関係で構成されます.
3). 各条件項目の名前はアルファベット+数字で表し、前に付けます!否定の意を表す
例(コンパイルラベルをソースファイルの上部に置く)
// +build darwin freebsd netbsd openbsd

これにより、このソースファイルはkqueueをサポートするBSDシステムでのみコンパイルできます.
1つのソースファイルには複数のコンパイルラベルがあり、複数のコンパイルラベルの間には論理的「と」の関係があります.
// +build linux darwin
// +build 386

これにより、このソースファイルはlinux/386またはdarwin/386プラットフォームでのみコンパイルできます.
コメントの説明について
最初にコンパイルラベルを使用すると、次のエラーが発生することがよくあります.
// +build !linux
package mypkg // wrong
この例のコンパイルラベルとパッケージの宣言の間には役に立たない.
空の行は区切られており、コンパイルラベルはパッケージ宣言として扱われます.
ラベルをコンパイルして無視するのではなく、コメント
次は正しいラベルの書き方です.ラベルの最後に空の行を追加すると、ラベルは他の宣言の注釈になりません.
// +build !linux

package mypkg // correct

go vetコマンドでもこの空行が欠けているエラーを検出でき、初期にはこのコマンドで空行が欠けているエラーを避けることができます.
% go vet mypkg
mypkg.go:1: +build comment appears too late in file
exit status 1

参考までに、以下の例ではlicence宣言、コンパイルラベル、パッケージ宣言を一緒に置いています.
% head headspin.go 
// Copyright 2013 Way out enterprises. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build someos someotheros thirdos,!amd64

// Package headspin implements calculates numbers so large
// they will make your head spin.
package headspin

3.第2の条件のコンパイル方法:ファイル接尾辞
この方法はファイル名の接尾辞を変更することによって条件コンパイルを提供し,このスキームはコンパイルラベルよりも簡単であり,go/buildはソースファイルを読み込まずにどのファイルがコンパイルに参加する必要がないかを決定することができる.
ファイル命名規則はgo/buildパッケージに詳細な説明を見つけることができます.簡単に言えば、ソースファイルに接尾辞が含まれている場合は:$GOOS.go、では、このソースファイルはこのプラットフォームの下でコンパイルされます.GOARCH.goもそうです.この2つの接尾辞は一緒に使用できますが、順序に注意してください:$GOOS_$GOARCH.go、逆に使えない:$GOARCH_$GOOS.go
例は次のとおりです.
mypkg_freebsd_arm.go // only builds on freebsd/arm systems
mypkg_plan9.go       // only builds on plan9

ソースファイルには条件付きコンパイル接尾辞だけでなく、ファイル名も必要です.
_linux.go
_freebsd_386.go

この2つのソースファイルは、go/buildが次の線または点の先頭にあるすべてのソースファイルを無視するため、すべてのプラットフォームで無視されます.
4.ラベルとファイル接尾辞をコンパイルする選択
ラベルとファイル接尾辞をコンパイルする機能に重複があります.たとえば、ファイル名:mypkg_linux.goに//+build linuxが含まれていると冗長になります
通常、ソースファイルがプラットフォームまたはcpuアーキテクチャと完全に一致している場合は、次のようなファイル接尾辞が使用されます.
mypkg_linux.go         // only builds on linux systems
mypkg_windows_amd64.go // only builds on windows 64bit platforms

逆に、このソースファイルが1つ以上のプラットフォームまたは1つ以上のcpuアーキテクチャで使用可能または指定されたプラットフォームを除去する必要がある場合は、次のようなコンパイルラベルを使用して、すべての*nixプラットフォームでコンパイルできます.
% grep '+build' $HOME/go/src/pkg/os/exec/lp_unix.go 
// +build darwin dragonfly freebsd linux netbsd openbsd

Windows以外のすべてのプラットフォームでコンパイルできます
% grep '+build' $HOME/go/src/pkg/os/types_notwin.go 
// +build !windows

5.まとめ
この文章は主にgo toolでコンパイルできるすべてのgoソースファイル、コンパイルラベルとファイル接尾辞名(.cと.sファイルも含む)に注目します.
Goの標準ライブラリには多くのサンプルが含まれており、特にruntime、syscall、os、netパッケージは、読者がこれらのパッケージで学ぶことができます.
Testファイルは、ラベルとファイル接尾辞条件のコンパイルもサポートし、goソースファイルと同じように機能します.いくつかのテストサンプルは、異なるプラットフォームの下で条件付きで含めることができます.同様に、標準ライブラリにも多くの例が含まれています.
最後に、このファイルはgo toolで条件コンパイルを達成する方法を説明しますが、条件コンパイルはgo toolに限らず、go/buildパッケージで自分の条件コンパイルツールを書くことができます.