[インデックス 19650] ファイルの概要
このコミットは、Go言語のビルドシステムにAndroidプラットフォームのサポートを追加するものです。特に、AndroidがLinuxカーネルをベースとしているという特性を活かし、GOOS=android
の場合に linux
向けのビルドタグやファイルがマッチするように変更が加えられています。これにより、既存のLinux向けコード資産をAndroidビルドで再利用しやすくなり、Androidサポートの導入が効率化されています。
コミット
commit a36348008c4acb493be8e4faf209a3818a11f0af
Author: David Crawshaw <david.crawshaw@zentus.com>
Date: Tue Jul 1 17:21:50 2014 -0400
all: add GOOS=android
As android and linux have significant overlap, and
because build tags are a poor way to represent an
OS target, this CL introduces an exception into
go/build: linux is treated as a synonym for android
when matching files.
http://golang.org/s/go14android
https://groups.google.com/forum/#!topic/golang-dev/P1ATVp1mun0
LGTM=rsc, minux
R=golang-codereviews, mikioh.mikioh, dave, aram, minux, gobot, rsc, aram.h, elias.naur, iant
CC=golang-codereviews, rsc
https://golang.org/cl/105270043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a36348008c4acb493be8e4faf209a3818a11f0af
元コミット内容
all: add GOOS=android
As android and linux have significant overlap, and
because build tags are a poor way to represent an
OS target, this CL introduces an exception into
go/build: linux is treated as a synonym for android
when matching files.
http://golang.org/s/go14android
https://groups.google.com/forum/#!topic/golang-dev/P1ATVp1mun0
LGTM=rsc, minux
R=golang-codereviews, mikioh.mikioh, dave, aram, minux, gobot, rsc, aram.h, elias.naur, iant
CC=golang-codereviews, rsc
https://golang.org/cl/105270043
変更の背景
このコミットの主な背景は、Go言語がAndroidプラットフォームを公式にサポートするための基盤を構築することにあります。コミットメッセージに明記されているように、AndroidはLinuxカーネルをベースにしているため、両者には「significant overlap(大きな重複)」があります。
従来のGoのビルドシステムでは、特定のOSをターゲットにするためにビルドタグ(// +build linux
のようなディレクティブや、_linux.go
のようなファイル名サフィックス)を使用していました。しかし、AndroidとLinuxのように多くの共通点を持つプラットフォームに対して、完全に独立したビルドタグを設けることは、コードの重複や管理の複雑さを招く可能性があります。コミットメッセージは、このようなビルドタグの利用方法が「poor way to represent an OS target(OSターゲットを表現するのに不適切な方法)」であると指摘しています。
この問題を解決するため、この変更では go/build
パッケージに特別な例外を導入しています。具体的には、GOOS=android
の場合に linux
が android
の「同義語(synonym)」として扱われるようにすることで、既存のLinux向けコード資産をAndroidビルドで自動的に利用できるようにし、Androidサポートの導入をより効率的かつ柔軟に行うことを目指しています。これにより、GoアプリケーションをAndroidデバイスで実行するための道が開かれました。
前提知識の解説
Goのビルドシステム
Go言語は、その強力なクロスコンパイル機能と、プラットフォーム固有のコードを扱うための洗練されたビルドシステムで知られています。
GOOS
とGOARCH
: Goのビルドプロセスにおいて、GOOS
(Operating System) とGOARCH
(Architecture) は非常に重要な環境変数です。これらは、コンパイル対象のオペレーティングシステムとCPUアーキテクチャを指定します。例えば、GOOS=linux GOARCH=amd64
と設定すると、Linux x86-64ビット環境向けのバイナリが生成されます。- ビルドタグ (Build Tags): Goのソースファイルは、特定のビルド条件に基づいて含めたり除外したりすることができます。これは主に以下の2つの方法で行われます。
- ファイル名サフィックス:
filename_GOOS.go
やfilename_GOOS_GOARCH.go
のような命名規則を使用します。例えば、network_linux.go
はLinuxビルドでのみコンパイルされ、syscall_windows_amd64.go
はWindows x86-64ビルドでのみコンパイルされます。 // +build
ディレクティブ: ソースファイルの先頭に// +build tag1 tag2
のようなコメントを記述することで、特定のビルドタグが有効な場合にのみそのファイルをコンパイル対象に含めることができます。複数のタグを指定した場合、スペースで区切るとOR条件、カンマで区切るとAND条件になります。例えば、// +build linux,amd64
はLinuxかつAMD64の場合にのみコンパイルされます。
- ファイル名サフィックス:
- 条件付きコンパイルの決定:
go build
コマンドは、GOOS
、GOARCH
、およびその他のビルド環境(Cgoの有効/無効など)に基づいて、どのソースファイルをコンパイル対象に含めるかを決定します。これにより、単一のコードベースから複数のプラットフォーム向けのバイナリを効率的に生成できます。
Androidプラットフォーム
Androidは、Googleによって開発されたモバイルオペレーティングシステムです。Go言語がAndroidをターゲットにする上で理解すべき重要な特性がいくつかあります。
- Linuxカーネルベース: Androidは、その基盤としてLinuxカーネルを使用しています。これは、GoがLinux向けに提供する多くの低レベル機能やシステムコールが、Android環境でも理論的には利用可能であることを意味します。
- 非標準のユーザーランド: しかし、Androidは標準的なLinuxディストリビューションとは異なり、独自のユーザーランド(ユーザー空間のライブラリやツール)を持っています。特に、標準CライブラリとしてGNU C Library (glibc) ではなく、Bionic C Libraryを使用しています。この違いが、Goのような言語がAndroidをターゲットにする際に、単にLinuxバイナリをそのまま実行するだけでは不十分である理由となります。Goのランタイムや標準ライブラリは、BionicのようなAndroid固有の環境に適応する必要があります。
- クロスコンパイルの必要性: 開発は通常、デスクトップ環境(Linux, macOS, Windows)で行われるため、Androidデバイス向けのGoバイナリを生成するにはクロスコンパイルが不可欠です。
クロスコンパイル
クロスコンパイルとは、あるプラットフォーム(ホスト)上で、別のプラットフォーム(ターゲット)向けの実行可能ファイルを生成するプロセスです。Goは、GOOS
と GOARCH
環境変数を設定するだけで、非常に簡単にクロスコンパイルを実行できることで知られています。この機能は、Androidのような異なるOS/アーキテクチャをターゲットにする際に極めて重要です。
技術的詳細
このコミットは、GoのビルドシステムとランタイムにAndroidサポートを統合するために、複数のファイルにわたる変更を加えています。
go/build
パッケージの変更
go/build
パッケージは、Goのソースファイルを解析し、ビルド条件に基づいてどのファイルをコンパイルに含めるかを決定する役割を担っています。
src/pkg/go/build/build.go
:cgoEnabled
マップにandroid/386
,android/amd64
,android/arm
のエントリが追加されました。これにより、これらのAndroidターゲットアーキテクチャでCgo(GoとC言語の相互運用機能)が有効になります。Context.match
関数に以下のロジックが追加されました。
これは、現在のビルドターゲットのif ctxt.GOOS == "android" && name == "linux" { return true }
GOOS
がandroid
であり、かつビルドタグの名前がlinux
である場合、そのタグをマッチさせるという重要な変更です。これにより、// +build linux
のようなビルドタグを持つファイルがAndroidビルドでも有効になります。Context.goodOSArchFile
関数(ファイル名サフィックスに基づいてファイルをマッチさせる関数)にも同様のロジックが追加されました。
これにより、if ctxt.GOOS == "android" && l[n-2] == "linux" { return true } // ... if ctxt.GOOS == "android" && l[n-1] == "linux" { return true }
filename_linux.go
やfilename_linux_arm.go
のようなファイルが、GOOS=android
の場合でも適切にコンパイル対象に含まれるようになります。
src/pkg/go/build/build_test.go
:matchFileTests
にctxtAndroid
(GOOS: "android", GOARCH: "arm") を使用したテストケースが追加され、foo_linux.go
やfoo_android.go
が正しくマッチすることを確認しています。これは、上記のContext.match
およびContext.goodOSArchFile
の変更が意図通りに機能するかを検証するためのものです。
src/pkg/go/build/doc.go
:- Goのビルドタグに関するドキュメントに、
GOOS=android
の場合にlinux
タグやファイルもマッチするという例外が明記されました。// Using GOOS=android matches build tags and files as for GOOS=linux // in addition to android tags and files.
- Goのビルドタグに関するドキュメントに、
src/pkg/go/build/syslist.go
:goosList
定数に"android"
が追加され、Goが認識するOSのリストにAndroidが正式に加わりました。
cmd/dist
の変更
cmd/dist
はGoの配布ツールであり、Goのビルドプロセス自体を管理します。
src/cmd/dist/build.c
:okgoos
配列に"android"
が追加され、dist
ツールがAndroidを有効なターゲットOSとして認識するようになりました。matchfield
関数(ビルドタグや環境変数をマッチさせる内部関数)に、GOOS
がandroid
の場合にf
が"linux"
と一致すればtrue
を返すロジックが追加されました。これは、Goのビルドシステム全体でAndroidとLinuxの関連付けを強化するものです。
src/cmd/dist/buildruntime.c
:mkzgoos
関数(ランタイムのOS定数を生成する関数)において、GOOS
がlinux
の場合に// +build !android
というビルドタグを自動的に追加するロジックが導入されました。これは、Linux固有のコードがAndroidビルドに含まれないようにするための措置であり、AndroidとLinuxの間の意図的な区別を維持しつつ、共通部分を共有するためのバランスを取っています。
liblink
の変更
liblink
はGoのリンカライブラリです。
src/liblink/sym.c
:static struct { ... }
の定義に、"android"
がHlinux
(Linuxヘッダー) にマッピングされるエントリが追加されました。これは、AndroidがLinuxカーネルを使用しているため、リンカがAndroidをLinuxと同様に扱うべきであることを示しています。
runtime
パッケージの追加ファイル
Goのランタイムは、ガベージコレクション、スケジューリング、システムコールなど、Goプログラムの実行に必要な低レベルの機能を提供します。Androidサポートのために、いくつかの新しいファイルが追加されました。
src/pkg/runtime/defs_android_arm.h
: ARMアーキテクチャのAndroid向け定義ファイル。多くの場合、defs_linux_arm.h
をインクルードしています。src/pkg/runtime/os_android.h
: Android固有のOS定義ファイル。os_linux.h
をインクルードしています。src/pkg/runtime/rt0_android_arm.s
: ARMアーキテクチャのAndroid向けランタイムエントリポイントのアセンブリコード。プログラムの開始時に必要な初期化処理を行います。src/pkg/runtime/signal_android_386.h
: x86アーキテクチャのAndroid向けシグナル定義ファイル。signal_linux_386.h
をインクルードしています。src/pkg/runtime/signal_android_arm.h
: ARMアーキテクチャのAndroid向けシグナル定義ファイル。signal_linux_arm.h
をインクルードしています。src/pkg/runtime/signals_android.h
: Android固有のシグナル定義ファイル。signals_linux.h
をインクルードしています。
これらの追加ファイルは、Android環境でGoランタイムが正しく動作するために必要な、OS固有の低レベルなインターフェースや定義を提供します。多くの場合、Linuxの対応するファイルを再利用または参照することで、コードの重複を最小限に抑えています。
コアとなるコードの変更箇所
このコミットの核心的な変更は、GoのビルドシステムがAndroidとLinuxの間の関係をどのように扱うかを定義する部分にあります。
-
src/pkg/go/build/build.go
内のContext.match
関数: この関数は、ビルドタグが現在のビルドコンテキストにマッチするかどうかを判断します。--- a/src/pkg/go/build/build.go +++ b/src/pkg/go/build/build.go @@ -1124,6 +1127,9 @@ func (ctxt *Context) match(name string, allTags map[string]bool) bool { if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler { return true } + if ctxt.GOOS == "android" && name == "linux" { + return true + } // other tags for _, tag := range ctxt.BuildTags {
-
src/pkg/go/build/build.go
内のContext.goodOSArchFile
関数: この関数は、ファイル名サフィックス(例:_linux.go
,_arm.go
)に基づいて、ファイルが現在のOS/アーキテクチャに適切であるかを判断します。--- a/src/pkg/go/build/build.go +++ b/src/pkg/go/build/build.go @@ -1165,12 +1172,21 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool { \tallTags[l[n-2]] = true \tallTags[l[n-1]] = true } -\t\treturn l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH +\t\tif l[n-1] != ctxt.GOARCH {\n+\t\t\treturn false\n+\t\t}\n +\t\tif ctxt.GOOS == "android" && l[n-2] == "linux" {\n+\t\t\treturn true\n+\t\t}\n +\t\treturn l[n-2] == ctxt.GOOS } if n >= 1 && knownOS[l[n-1]] { if allTags != nil { \tallTags[l[n-1]] = true } +\t\tif ctxt.GOOS == "android" && l[n-1] == "linux" {\n+\t\t\treturn true\n+\t\t}\n \t\treturn l[n-1] == ctxt.GOOS } if n >= 1 && knownArch[l[n-1]] {
-
src/cmd/dist/build.c
内のmatchfield
関数: Goのビルドツールチェーンの低レベルな部分で、ビルド条件を評価します。--- a/src/cmd/dist/build.c +++ b/src/cmd/dist/build.c @@ -1149,7 +1150,7 @@ matchfield(char *f)\n \n \tp = xstrrchr(f, ',');\n \tif(p == nil)\n -\t\treturn streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap") || streq(f, "go1.1"); +\t\treturn streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap") || streq(f, "go1.1") || (streq(goos, "android") && streq(f, "linux")); \t*p = 0;\n \tres = matchfield(f) && matchfield(p+1);\n \t*p = ',';
コアとなるコードの解説
Context.match
関数 (src/pkg/go/build/build.go
)
この変更は、Goのビルドタグの評価ロジックの中心に位置します。 追加された行:
if ctxt.GOOS == "android" && name == "linux" {
return true
}
このコードは、現在のビルドコンテキストのターゲットOS (ctxt.GOOS
) が "android"
であり、かつ評価対象のビルドタグ名 (name
) が "linux"
である場合に、そのタグをマッチすると判断します。
これにより、例えば // +build linux
と記述されたGoソースファイルは、GOOS=android
でビルドする際にもコンパイル対象に含まれるようになります。これは、AndroidがLinuxカーネルをベースとしているため、多くのLinux向けコードがAndroidでもそのまま利用できるという事実をGoのビルドシステムに反映させるための、非常に効率的な方法です。
Context.goodOSArchFile
関数 (src/pkg/go/build/build.go
)
この関数は、ファイル名に埋め込まれたOSやアーキテクチャのサフィックス(例: _linux.go
, _arm.go
)を処理し、そのファイルが現在のビルドコンテキストに適しているかを判断します。
変更された部分:
if ctxt.GOOS == "android" && l[n-2] == "linux" {
return true
}
// ...
if ctxt.GOOS == "android" && l[n-1] == "linux" {
return true
}
l[n-2]
や l[n-1]
は、ファイル名のサフィックスから抽出されたOS名やアーキテクチャ名を表します。この変更は、GOOS
が "android"
の場合に、ファイル名に "linux"
が含まれるファイル(例: foo_linux.go
や bar_linux_arm.go
)も有効であると判断するようにビルドシステムを拡張します。
これにより、ビルドタグと同様に、ファイル名ベースのプラットフォーム選択においてもLinux向けに書かれたファイルがAndroidビルドで自動的に考慮されるようになり、Androidサポートのためのコードの再利用性が大幅に向上します。
matchfield
関数 (src/cmd/dist/build.c
)
このC言語の関数は、Goのビルドツールチェーンの内部で、ビルド条件を評価する際に使用されます。 変更された行:
return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap") || streq(f, "go1.1") || (streq(goos, "android") && streq(f, "linux"));
この行は、既存の条件(現在のOS、アーキテクチャ、ブートストラップモード、Goバージョンとの一致)に加えて、新たな条件 (streq(goos, "android") && streq(f, "linux"))
を追加しています。
これは、goos
(現在のターゲットOS) が "android"
であり、かつ評価対象のフィールド f
が "linux"
である場合に、マッチすると判断することを意味します。この変更は、Goのビルドシステム全体でAndroidとLinuxの間の特別な関係を認識させるための、低レベルかつ重要な調整です。これにより、ビルドツールがAndroidをターゲットとする際に、Linux関連のビルド設定やファイルが適切に処理されるようになります。
これらのコアな変更は、GoがAndroidを「Linuxの特殊なバリアント」として扱うという設計思想を反映しており、既存のLinux向けコード資産を最大限に活用しつつ、Android固有の要件にも対応できる柔軟なビルドシステムを構築するための基盤となっています。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/a36348008c4acb493be8e4faf209a3818a11f0af
- Go 1.4 Androidに関する情報 (コミットメッセージより): http://golang.org/s/go14android
- golang-dev メーリングリストの議論 (コミットメッセージより): https://groups.google.com/forum/#!topic/golang-dev/P1ATVp1mun0
参考にした情報源リンク
- Go言語のコミットメッセージと差分情報
- Go言語のビルドシステムに関する一般的な知識
- Androidプラットフォームのアーキテクチャに関する一般的な知識
- クロスコンパイルに関する一般的な知識