[インデックス 16530] ファイルの概要
このコミットは、Go言語の標準ライブラリであるnetパッケージにおいて、Cgoに依存しない「純粋なGo」実装をビルドするための新しいビルドタグnetgoを導入するものです。これにより、Cgoの依存関係を排除し、クロスコンパイルや静的リンクされたバイナリの生成を容易にすることが目的とされています。
コミット
- コミットハッシュ:
06f55f50097293027a4634ba88140c75702c6a5d - Author: Shenghou Ma minux.ma@gmail.com
- Date: Tue Jun 11 02:55:16 2013 +0800
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/06f55f50097293027a4634ba88140c75702c6a5d
元コミット内容
net: introduce netgo build tag to build a pure Go net package.
Fixes #4078.
R=golang-dev, bradfitz, rsc, iant
CC=golang-dev
https://golang.org/cl/7100050
変更の背景
Go言語のnetパッケージは、ネットワーク関連の操作(DNSルックアップなど)を行う際に、OSのネイティブなCライブラリ(例えばglibcのgetaddrinfoなど)を利用するためにCgoを使用することがあります。これは、特にDNS解決において、システムの設定(/etc/resolv.confなど)を尊重し、より堅牢な動作を保証するためです。
しかし、Cgoを使用すると、以下のような問題が発生する可能性があります。
- クロスコンパイルの複雑化: 異なるOSやアーキテクチャ向けにGoプログラムをコンパイルする際、Cgoが依存するCライブラリもターゲット環境に合わせてビルド・リンクする必要があり、プロセスが複雑になります。
- 静的リンクの困難さ: Cgoを使用すると、生成されるバイナリは動的リンクされるCライブラリに依存することが多く、完全に静的にリンクされた単一のバイナリを生成するのが難しくなります。これは、コンテナ環境や最小限の実行環境でGoアプリケーションをデプロイする際に問題となることがあります。
- Cライブラリの依存性: 特定のCライブラリのバージョンや存在に依存するため、デプロイ環境での互換性の問題が発生する可能性があります。
このコミットは、これらの問題を解決するために、Cgoに依存しない純粋なGo実装のnetパッケージをビルドするオプションを提供することを目的としています。これにより、開発者は必要に応じてCgoの依存関係を排除したバイナリを生成できるようになります。
前提知識の解説
Cgo
Cgoは、GoプログラムからC言語のコードを呼び出すためのGoの機能です。Goのソースファイル内にCコードを埋め込んだり、既存のCライブラリをリンクしたりすることができます。Goの標準ライブラリの多くは、パフォーマンスやOSとの連携のためにCgoを利用しています。例えば、os/userパッケージやnetパッケージの一部は、システムコールやネイティブライブラリの機能を利用するためにCgoを使用しています。
Goのビルドタグ(Build Tags)
Goのビルドタグは、Goのソースファイルを条件付きでコンパイルするためのメカニズムです。ソースファイルの先頭に// +build tagnameのような形式でコメントを記述することで、特定のタグが有効な場合にのみそのファイルをコンパイルするように指定できます。
// +build tag1:tag1が有効な場合にコンパイルされます。// +build !tag2:tag2が有効でない場合にコンパイルされます。// +build tag1,tag2:tag1とtag2の両方が有効な場合にコンパイルされます(AND条件)。// +build tag1 tag2:tag1またはtag2のいずれかが有効な場合にコンパイルされます(OR条件)。
ビルド時にgo build -tags tagnameのように-tagsオプションを指定することで、特定のビルドタグを有効にできます。
純粋なGo (pure Go)
Go言語の文脈で「純粋なGo」とは、Cgoを一切使用せず、Go言語のみで実装されたコードやパッケージを指します。純粋なGoで書かれたプログラムは、CコンパイラやCライブラリへの依存がなく、クロスコンパイルが容易で、完全に静的にリンクされたバイナリを生成しやすいという利点があります。
netパッケージの場合、DNS解決などの一部の機能はCgoに依存していましたが、このコミットによって、Cgoを使用しない代替実装(Go言語のみで書かれたDNSリゾルバなど)を選択できるようになります。
技術的詳細
このコミットは、netgoという新しいビルドタグを導入することで、netパッケージのビルドプロセスを制御します。
Goのnetパッケージには、Cgoを使用してネットワーク関連のシステムコールやライブラリ関数を呼び出すためのファイル(例: cgo_bsd.go, cgo_linux.goなど)と、Cgoを使用しない純粋なGoで実装された代替ファイル(例: cgo_stub.go)が存在します。
通常、GoはターゲットOSに応じて適切なCgoファイルを選択してコンパイルします。しかし、netgoタグが有効な場合、Cgoに依存するファイルはコンパイルから除外され、代わりに純粋なGoで書かれた代替実装が使用されるようになります。
具体的には、以下の変更が行われています。
-
cgo_*.goファイルへの!netgoタグの追加:src/pkg/net/cgo_bsd.go,src/pkg/net/cgo_linux.go,src/pkg/net/cgo_netbsd.go,src/pkg/net/cgo_openbsd.go,src/pkg/net/cgo_unix.goといったCgoに依存するファイルには、// +build !netgoというビルドタグが追加されました。これは、「netgoタグが有効でない場合にのみこのファイルをコンパイルする」という意味です。 また、cgo_linux.go,cgo_netbsd.go,cgo_openbsd.goには既存の+build cgoに加えて!netgoが追加され、+build cgo,!netgoとなっています。これは、「Cgoが有効で、かつnetgoが有効でない場合にのみこのファイルをコンパイルする」という意味になります。 -
cgo_stub.goファイルへのnetgoタグの追加:src/pkg/net/cgo_stub.goは、Cgoが利用できない環境や、Cgoを使用しない場合にフォールバックとして使用されるスタブ実装のファイルです。このファイルには、既存の// +build !cgoに加えてnetgoが追加され、// +build !cgo netgoとなりました。これは、「Cgoが有効でない場合、またはnetgoタグが有効な場合にこのファイルをコンパイルする」という意味になります。
これらの変更により、go build -tags netgoコマンドを実行すると、Cgoに依存するnetパッケージのコードがコンパイルから除外され、純粋なGoで実装されたネットワーク機能が使用されるようになります。これにより、Cライブラリへの依存がない、完全にGoだけで構成されたバイナリを生成することが可能になります。
コアとなるコードの変更箇所
このコミットでは、主にsrc/pkg/netディレクトリ内のCgo関連のGoソースファイルのビルドタグが変更されています。
doc/go1.2.txt: Go 1.2のリリースノートにnetgoタグの導入が追記されました。src/pkg/net/cgo_bsd.go:// +build !netgoが追加されました。src/pkg/net/cgo_linux.go:// +build cgo,!netgoに変更されました。src/pkg/net/cgo_netbsd.go:// +build cgo,!netgoに変更されました。src/pkg/net/cgo_openbsd.go:// +build cgo,!netgoに変更されました。src/pkg/net/cgo_stub.go:// +build !cgo netgoに変更されました。src/pkg/net/cgo_unix.go:// +build !netgoが追加されました。
コアとなるコードの解説
変更の核心は、Goのビルドタグの論理的な組み合わせにあります。
cgo_bsd.go, cgo_unix.go の変更
--- a/src/pkg/net/cgo_bsd.go
+++ b/src/pkg/net/cgo_bsd.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !netgo
// +build darwin freebsd
package net
これらのファイルは、BSD系のOS(Darwin/macOS, FreeBSD)や一般的なUnix系OS向けのCgo実装を含んでいます。// +build !netgoが追加されたことで、netgoタグが指定されたビルドではこれらのファイルがコンパイルされなくなります。これにより、Cgoに依存するネットワーク機能が除外されます。
cgo_linux.go, cgo_netbsd.go, cgo_openbsd.go の変更
--- a/src/pkg/net/cgo_linux.go
+++ b/src/pkg/net/cgo_linux.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build cgo,!netgo
+
package net
これらのファイルは、Linux, NetBSD, OpenBSD向けのCgo実装を含んでいます。既存の+build cgoに加えて,!netgoが追加されました。これは、Cgoが有効であり、かつnetgoタグが有効でない場合にのみこれらのファイルがコンパイルされることを意味します。つまり、netgoタグが有効な場合は、Cgoが有効であってもこれらのファイルはコンパイルされません。
cgo_stub.go の変更
--- a/src/pkg/net/cgo_stub.go
+++ b/src/pkg/net/cgo_stub.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !cgo
+// +build !cgo netgo
// Stub cgo routines for systems that do not use cgo to do network lookups.
cgo_stub.goは、Cgoが利用できない環境(例: GOARCH=jsなど)や、Cgoを使用しない場合にフォールバックとして使用されるスタブ実装です。元のタグは// +build !cgoでした。これにnetgoが追加され、// +build !cgo netgoとなりました。これは、「Cgoが有効でない場合、またはnetgoタグが有効な場合」にこのファイルがコンパイルされることを意味します。
この変更により、go build -tags netgoを実行すると、Cgoに依存するファイルが除外され、代わりにcgo_stub.goがコンパイルされるようになります。これにより、netパッケージはCgoの依存なしに動作し、純粋なGoで実装されたネットワーク機能(例えば、Go自身のDNSリゾルバ)を使用するようになります。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/06f55f50097293027a4634ba88140c75702c6a5d
- Go Code Review (CL): https://golang.org/cl/7100050
- コミットメッセージに記載されているIssue
#4078については、公開されているGoのIssueトラッカーでは直接的な情報を見つけることができませんでした。
参考にした情報源リンク
- Go言語のビルドタグに関する公式ドキュメントやブログ記事 (一般的なGoのビルドタグの動作について)
- Cgoに関するGo言語の公式ドキュメント (Cgoの基本的な概念と使用法について)
- Goの
netパッケージの内部実装に関する情報 (Cgoがどのように利用されているかについて)