Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 10943] ファイルの概要

このコミットは、Go言語のビルドシステムに新しいビルドタグ cgonocgo を追加するものです。これにより、Cgo(C言語との相互運用機能)が有効か無効かに応じて、特定のソースファイルを条件付きでコンパイルできるようになります。特に、netパッケージ内の cgo_stub.go のような、Cgoが無効な場合にのみビルドされるべきファイルにこのタグを適用することで、ビルドプロセスの柔軟性と正確性を向上させます。

コミット

commit f52a2088ef58281cb11e904ebd5ed5441577fc71
Author: Russ Cox <rsc@golang.org>
Date:   Wed Dec 21 08:51:18 2011 -0500

    go/build: add new +build tags 'cgo' and 'nocgo'
    
    This lets us mark net's cgo_stub.go as only to be
    built when cgo is disabled.
    
    R=golang-dev, ality, mikioh.mikioh
    CC=golang-dev
    https://golang.org/cl/5489100
---
 src/cmd/go/main.go               |  8 +++---
 src/pkg/crypto/tls/root_stub.go  |  2 +-\
 src/pkg/debug/gosym/pclinetest.h |  2 ++\
 src/pkg/debug/gosym/pclinetest.s |  2 ++\
 src/pkg/go/build/build_test.go   | 13 +++++++++-
 src/pkg/go/build/dir.go          | 54 ++++++++++++++++++++++++++++++++--------
 src/pkg/net/cgo_stub.go          |  2 +-\
 7 files changed, 65 insertions(+), 18 deletions(-)

diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 2709750fcc..7b7f4a450d 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -242,11 +242,9 @@ func allPackages(what string) []string {
 	have := map[string]bool{
 		"builtin": true, // ignore pseudo-package that exists only for documentation
 	}\n-\t/*\n-\t\tif !build.DefaultContext.CgoEnabled {\n-\t\t\thave[\"runtime/cgo\"] = true // ignore during walk\n-\t\t}\n-\t*/\n+\tif !build.DefaultContext.CgoEnabled {\n+\t\thave[\"runtime/cgo\"] = true // ignore during walk\n+\t}\n \tvar pkgs []string
 
 	// Commands
diff --git a/src/pkg/crypto/tls/root_stub.go b/src/pkg/crypto/tls/root_stub.go
index 18dcb02043..d00493a573 100644
--- a/src/pkg/crypto/tls/root_stub.go
+++ b/src/pkg/crypto/tls/root_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.\n \n-// +build plan9\n+// +build plan9 darwin/nocgo\n \n package tls
 
diff --git a/src/pkg/debug/gosym/pclinetest.h b/src/pkg/debug/gosym/pclinetest.h
index a6c40e76cd..156c0b87b0 100644
--- a/src/pkg/debug/gosym/pclinetest.h
+++ b/src/pkg/debug/gosym/pclinetest.h
@@ -1,3 +1,5 @@
+// +build ignore\n+\n // Empty include file to generate z symbols
 \n \ndiff --git a/src/pkg/debug/gosym/pclinetest.s b/src/pkg/debug/gosym/pclinetest.s
index 6305435b09..c1d4818d40 100644
--- a/src/pkg/debug/gosym/pclinetest.s
+++ b/src/pkg/debug/gosym/pclinetest.s
@@ -1,3 +1,5 @@
+// +build ignore\n+\n TEXT linefrompc(SB),7,$0\t// Each byte stores its line delta
 BYTE $2;
 BYTE $1;
diff --git a/src/pkg/go/build/build_test.go b/src/pkg/go/build/build_test.go
index e86cfc012e..fd4030632a 100644
--- a/src/pkg/go/build/build_test.go
+++ b/src/pkg/go/build/build_test.go
@@ -46,7 +46,7 @@ var buildPkgs = []struct {\n \t{\n \t\t\"go/build/cgotest\",\n \t\t&DirInfo{\n-\t\t\tCgoFiles:    []string{\"cgotest.go\"},\n+\t\t\tCgoFiles:    ifCgo([]string{\"cgotest.go\"}),\n \t\t\tCFiles:      []string{\"cgotest.c\"},\n \t\t\tHFiles:      []string{\"cgotest.h\"},\n \t\t\tImports:     []string{\"C\", \"unsafe\"},\n@@ -56,6 +56,13 @@ var buildPkgs = []struct {\n \t},\n }\n \n+func ifCgo(x []string) []string {\n+\tif DefaultContext.CgoEnabled {\n+\t\treturn x\n+\t}\n+\treturn nil\n+}\n+\n const cmdtestOutput = \"3\"\n \n func TestBuild(t *testing.T) {\n@@ -72,6 +79,10 @@ func TestBuild(t *testing.T) {\n \t\t\tcontinue\n \t\t}\n \n+\t\tif tt.dir == \"go/build/cgotest\" && len(info.CgoFiles) == 0 {\n+\t\t\tcontinue\n+\t\t}\n+\n \t\ts, err := Build(tree, tt.dir, info)\n \t\tif err != nil {\n \t\t\tt.Errorf(\"Build(%#q): %v\", tt.dir, err)\ndiff --git a/src/pkg/go/build/dir.go b/src/pkg/go/build/dir.go
index 29d7c4c7d3..b710bc18da 100644
--- a/src/pkg/go/build/dir.go
+++ b/src/pkg/go/build/dir.go
@@ -26,9 +26,9 @@ import (\n \n // A Context specifies the supporting context for a build.\n type Context struct {\n-\tGOARCH string // target architecture\n-\tGOOS   string // target operating system\n-\t// TODO(rsc,adg): GOPATH\n+\tGOARCH     string // target architecture\n+\tGOOS       string // target operating system\n+\tCgoEnabled bool   // whether cgo can be used\n \n \t// By default, ScanDir uses the operating system\'s\n \t// file system calls to read directories and files.\n@@ -75,9 +75,34 @@ func (ctxt *Context) readFile(dir, file string) (string, []byte, error) {\n // The DefaultContext is the default Context for builds.\n // It uses the GOARCH and GOOS environment variables\n // if set, or else the compiled code\'s GOARCH and GOOS.\n-var DefaultContext = Context{\n-\tGOARCH: envOr(\"GOARCH\", runtime.GOARCH),\n-\tGOOS:   envOr(\"GOOS\", runtime.GOOS),\n+var DefaultContext = defaultContext()\n+\n+var cgoEnabled = map[string]bool{\n+\t\"darwin/386\":    true,\n+\t\"darwin/amd64\":  true,\n+\t\"linux/386\":     true,\n+\t\"linux/amd64\":   true,\n+\t\"freebsd/386\":   true,\n+\t\"freebsd/amd64\": true,\n+}\n+\n+func defaultContext() Context {\n+\tvar c Context\n+\n+\tc.GOARCH = envOr(\"GOARCH\", runtime.GOARCH)\n+\tc.GOOS = envOr(\"GOOS\", runtime.GOOS)\n+\n+\ts := os.Getenv(\"CGO_ENABLED\")\n+\tswitch s {\n+\tcase \"1\":\n+\t\tc.CgoEnabled = true\n+\tcase \"0\":\n+\t\tc.CgoEnabled = false\n+\tdefault:\n+\t\tc.CgoEnabled = cgoEnabled[c.GOOS+\"/\"+c.GOARCH]\n+\t}\n+\n+\treturn c\n }\n \n func envOr(name, def string) string {\n@@ -264,7 +289,9 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {\n \t\t\t}\n \t\t}\n \t\tif isCgo {\n-\t\t\tdi.CgoFiles = append(di.CgoFiles, name)\n+\t\t\tif ctxt.CgoEnabled {\n+\t\t\t\tdi.CgoFiles = append(di.CgoFiles, name)\n+\t\t\t}\n \t\t} else if isTest {\n \t\t\tif pkg == string(pf.Name.Name) {\n \t\t\t\tdi.TestGoFiles = append(di.TestGoFiles, name)\n@@ -306,7 +333,6 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {\n }\n \n var slashslash = []byte(\"//\")\n-var plusBuild = []byte(\"+build\")\n \n // shouldBuild reports whether it is okay to use this file,\n // The rule is that in the file\'s leading run of // comments\n@@ -527,14 +553,22 @@ func splitQuoted(s string) (r []string, err error) {\n //\n //\t$GOOS\n //\t$GOARCH\n-//\t$GOOS/$GOARCH\n+//\tcgo (if cgo is enabled)\n+//\tnocgo (if cgo is disabled)\n+//\ta slash-separated list of any of these\n //\n func (ctxt *Context) matchOSArch(name string) bool {\n+\tif ctxt.CgoEnabled && name == \"cgo\" {\n+\t\treturn true\n+\t}\n+\tif !ctxt.CgoEnabled && name == \"nocgo\" {\n+\t\treturn true\n+\t}\n \tif name == ctxt.GOOS || name == ctxt.GOARCH {\n \t\treturn true\n \t}\n \ti := strings.Index(name, \"/\")\n-\treturn i >= 0 && name[:i] == ctxt.GOOS && name[i+1:] == ctxt.GOARCH\n+\treturn i >= 0 && ctxt.matchOSArch(name[:i]) && ctxt.matchOSArch(name[i+1:])\n }\n \n // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH\ndiff --git a/src/pkg/net/cgo_stub.go b/src/pkg/net/cgo_stub.go
index 4c49e63184..66aff837d0 100644
--- 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.\n \n-// +build netbsd openbsd\n+// +build nocgo\n \n // Stub cgo routines for systems that do not use cgo to do network lookups.\n \n```

## GitHub上でのコミットページへのリンク

[https://github.com/golang/go/commit/f52a2088ef58281cb11e904ebd5ed5441577fc71](https://github.com/golang/go/commit/f52a2088ef58281cb11e904ebd5ed5441577fc71)

## 元コミット内容

このコミットは、Go言語のビルドシステムに `cgo` および `nocgo` という新しいビルドタグを追加することを目的としています。これにより、Cgo(GoとC言語の相互運用機能)が有効になっているかどうかに基づいて、特定のGoソースファイルを条件付きでコンパイルする機能が提供されます。

具体的には、`net`パッケージ内の `cgo_stub.go` のようなファイルは、Cgoが無効な場合にのみビルドされるようにマークできるようになります。これは、Cgoが利用できない環境(例えば、クロスコンパイル時や特定のOS/アーキテクチャの組み合わせ)で、Cgoに依存しない代替実装を提供するために重要です。

この変更は、Goのビルドプロセスにおける柔軟性を高め、異なるビルド環境や要件に対応するための重要なステップです。

## 変更の背景

Go言語のビルドシステムは、特定のオペレーティングシステム(OS)やアーキテクチャ(ARCH)に基づいてファイルを条件付きでコンパイルする機能(ビルドタグ)を以前から持っていました。例えば、`+build linux` や `+build amd64` といったタグを使用することで、Linux環境でのみビルドされるファイルや、AMD64アーキテクチャでのみビルドされるファイルを指定できました。

しかし、Cgoの有効/無効という条件に基づいてファイルを切り替える直接的なメカニズムは存在しませんでした。Cgoは、GoプログラムからC言語のコードを呼び出すための重要な機能ですが、すべての環境で利用できるわけではありません。例えば、一部のクロスコンパイル設定や、Cコンパイラが利用できない環境ではCgoを無効にする必要があります。

このような状況下で、Cgoの有無によって動作が異なる、あるいはCgoに依存しない代替実装が必要な場合、開発者は手動でファイルを切り替えるか、複雑なビルドスクリプトを使用する必要がありました。これは、特に標準ライブラリのような広範な環境で利用されるコードベースにおいて、メンテナンスの負担となっていました。

このコミットは、この課題を解決するために、`cgo` と `nocgo` という専用のビルドタグを導入し、Cgoの有効/無効状態をビルドシステムが直接認識し、それに基づいてファイルのコンパイルを制御できるようにすることを目的としています。これにより、よりクリーンで宣言的な方法で条件付きコンパイルを実現し、ビルドプロセスの堅牢性と利便性を向上させます。

## 前提知識の解説

### Go言語のビルドタグ(Build Tags)

Go言語のビルドタグは、ソースファイルの先頭に記述される特別なコメント行で、そのファイルが特定のビルド条件を満たす場合にのみコンパイルされるように指定するメカニズムです。これにより、異なるオペレーティングシステム、アーキテクチャ、またはその他のカスタム条件に基づいて、コードベースを柔軟に構成できます。

ビルドタグは、ファイルの先頭にあるパッケージ宣言の前に、`// +build tag1 tag2` の形式で記述されます。複数のタグはスペースで区切られ、論理OR条件として扱われます。つまり、指定されたタグのいずれか一つでもビルド条件に合致すれば、そのファイルはコンパイル対象となります。

論理AND条件を指定するには、複数の `+build` 行を使用します。例えば、`// +build linux` と `// +build amd64` の両方が存在する場合、そのファイルはLinuxかつAMD64環境でのみコンパイルされます。

一般的なビルドタグには以下のようなものがあります。
*   **OS名**: `linux`, `windows`, `darwin` (macOS), `freebsd` など。
*   **アーキテクチャ名**: `amd64`, `386`, `arm`, `arm64` など。
*   **カスタムタグ**: `debug`, `release` など、ユーザーが定義する任意のタグ。これらは `go build -tags "debug"` のようにコマンドラインで指定できます。

### Cgo

Cgoは、Go言語のプログラムからC言語のコードを呼び出すためのGoの機能です。これにより、既存のCライブラリをGoプロジェクトで再利用したり、Goでは実装が難しい低レベルの操作を行ったりすることが可能になります。

Cgoを使用するには、Goのソースファイル内で `import "C"` を記述し、C言語の関数やデータ構造をGoのコードから参照します。Cgoは、GoコンパイラとCコンパイラ(通常はGCCやClang)の両方を必要とします。ビルド時には、CgoはCコードをコンパイルし、Goコードとリンクします。

Cgoは非常に強力な機能ですが、いくつかの制約や考慮事項があります。
*   **ビルド依存性**: Cコンパイラがシステムにインストールされている必要があります。
*   **クロスコンパイルの複雑さ**: 異なるOSやアーキテクチャ向けにクロスコンパイルする場合、Cgoのセットアップは複雑になることがあります。
*   **パフォーマンスオーバーヘッド**: GoとCの間でデータをやり取りする際には、わずかなオーバーヘッドが発生する可能性があります。
*   **ガベージコレクション**: CのメモリはGoのガベージコレクタの管理外であるため、手動でのメモリ管理が必要になる場合があります。

これらの理由から、Cgoは必要な場合にのみ使用され、Cgoが利用できない環境向けに代替実装を提供することが望ましい場合があります。

### 条件付きコンパイル(Conditional Compilation)

条件付きコンパイルとは、特定の条件が満たされた場合にのみ、コードの一部をコンパイルプロセスに含める技術です。Go言語では、主にビルドタグとファイル名規則(例: `_linux.go`)によって実現されます。

条件付きコンパイルの主な利点は以下の通りです。
*   **プラットフォーム固有のコード**: OSやアーキテクチャに特化したコードを記述し、他のプラットフォームではコンパイルしないようにできます。
*   **機能の有効/無効化**: デバッグ機能や特定のハードウェアサポートなど、特定の機能をビルド時に有効または無効にできます。
*   **依存関係の管理**: 特定のライブラリや機能が利用できない環境で、代替の実装を提供できます。

このコミットは、Cgoの有効/無効という新しい条件をGoの条件付きコンパイルのメカニズムに統合することで、開発者がよりきめ細かくビルドプロセスを制御できるようにします。

## 技術的詳細

このコミットの技術的な核心は、Goのビルドシステム、特に `go/build` パッケージが、Cgoの有効/無効状態を認識し、それに基づいて新しいビルドタグ `cgo` および `nocgo` を処理するように拡張された点にあります。

1.  **`Context` 構造体への `CgoEnabled` フィールドの追加**:
    `src/pkg/go/build/dir.go` 内の `build.Context` 構造体に `CgoEnabled bool` フィールドが追加されました。このフィールドは、現在のビルドコンテキストでCgoが有効であるかどうかを示します。

2.  **`DefaultContext` の初期化ロジックの変更**:
    `build.DefaultContext` は、Goツールがデフォルトで使用するビルドコンテキストです。このコミットでは、`DefaultContext` の初期化方法が変更され、`defaultContext()` 関数を通じて `CgoEnabled` の値が決定されるようになりました。
    *   `CGO_ENABLED` 環境変数が設定されている場合(`"1"` または `"0"`)、その値が優先されます。
    *   `CGO_ENABLED` が設定されていない場合、`cgoEnabled` マップ(`GOOS/GOARCH` の組み合わせでCgoがデフォルトで有効なプラットフォームを定義)に基づいて `CgoEnabled` の値が決定されます。これにより、特定のプラットフォームではCgoがデフォルトで有効になるように設定されます。

3.  **`matchOSArch` メソッドの拡張**:
    `build.Context` の `matchOSArch` メソッドは、ビルドタグが現在のビルドコンテキストに一致するかどうかを判断します。このメソッドが拡張され、`name` が `"cgo"` または `"nocgo"` の場合に、`ctxt.CgoEnabled` の値に基づいて `true` または `false` を返すようになりました。
    *   `name == "cgo"` の場合、`ctxt.CgoEnabled` が `true` であれば一致。
    *   `name == "nocgo"` の場合、`ctxt.CgoEnabled` が `false` であれば一致。
    これにより、`// +build cgo` や `// +build nocgo` といったビルドタグが、Cgoの有効/無効状態に基づいて正しく評価されるようになります。

4.  **`ScanDir` での `CgoFiles` の条件付き追加**:
    `build.Context` の `ScanDir` メソッドは、ディレクトリをスキャンしてGoソースファイルを解析し、`DirInfo` 構造体にその情報を格納します。このメソッド内で、Cgoファイル(`_cgo.go` などの命名規則を持つファイル)が検出された場合、以前は無条件に `di.CgoFiles` に追加されていましたが、このコミット以降は `ctxt.CgoEnabled` が `true` の場合にのみ追加されるようになりました。これは、Cgoが無効なビルドではCgoファイル自体をコンパイル対象から除外するためです。

5.  **`src/cmd/go/main.go` の変更**:
    `go` コマンドのメインロジックにおいて、`runtime/cgo` パッケージがCgo無効時に無視されるように、コメントアウトされていたコードが有効化されました。これは、Cgoが無効なビルドで `runtime/cgo` パッケージへの参照がビルドエラーを引き起こさないようにするためのものです。

6.  **既存ファイルのビルドタグの更新**:
    `src/pkg/crypto/tls/root_stub.go` や `src/pkg/net/cgo_stub.go` のようなファイルは、Cgoが利用できない場合にのみビルドされるべきスタブ実装です。これらのファイルのビルドタグが `// +build nocgo` や `// +build plan9 darwin/nocgo` のように更新され、新しい `nocgo` タグを活用するようになりました。

これらの変更により、GoのビルドシステムはCgoの有効/無効状態をビルドコンテキストの一部として扱い、それに基づいてソースファイルの選択とコンパイルを自動的に調整できるようになりました。これにより、開発者はCgoの有無に依存するコードをより簡単に管理し、異なるビルド環境に対応する堅牢なGoプログラムを構築できます。

## コアとなるコードの変更箇所

このコミットにおける主要なコード変更は以下のファイルに集中しています。

*   **`src/pkg/go/build/dir.go`**:
    *   `Context` 構造体に `CgoEnabled bool` フィールドが追加されました。
    *   `DefaultContext` の初期化ロジックが `defaultContext()` 関数に分離され、`CgoEnabled` の値が `CGO_ENABLED` 環境変数またはプラットフォーム固有のデフォルト設定に基づいて決定されるようになりました。
    *   `matchOSArch` メソッドが拡張され、`cgo` および `nocgo` ビルドタグの評価ロジックが追加されました。
    *   `ScanDir` メソッド内で、Cgoファイルが `CgoEnabled` が `true` の場合にのみ `CgoFiles` に追加されるように変更されました。

*   **`src/cmd/go/main.go`**:
    *   `allPackages` 関数内で、`build.DefaultContext.CgoEnabled` が `false` の場合に `runtime/cgo` パッケージが無視されるように、コメントアウトされていたコードが有効化されました。

*   **`src/pkg/go/build/build_test.go`**:
    *   `ifCgo` ヘルパー関数が追加され、テストケースで `CgoFiles` の設定を `CgoEnabled` に応じて動的に調整できるようになりました。
    *   `TestBuild` 関数内で、`cgotest` ディレクトリのテストが `CgoFiles` が空の場合にスキップされる条件が追加されました。

*   **`src/pkg/net/cgo_stub.go`**:
    *   ビルドタグが `// +build netbsd openbsd` から `// +build nocgo` に変更されました。これにより、Cgoが無効な場合にのみこのスタブファイルがビルドされるようになります。

*   **`src/pkg/crypto/tls/root_stub.go`**:
    *   ビルドタグが `// +build plan9` から `// +build plan9 darwin/nocgo` に変更されました。これにより、Plan 9またはmacOSでCgoが無効な場合にこのスタブファイルがビルドされるようになります。

*   **`src/pkg/debug/gosym/pclinetest.h` および `src/pkg/debug/gosym/pclinetest.s`**:
    *   `// +build ignore` タグが追加されました。これは、これらのファイルが通常のビルドプロセスから除外されることを示します。

## コアとなるコードの解説

### `src/pkg/go/build/dir.go` の変更点

このファイルは、Goのビルドシステムの中核をなす `go/build` パッケージの一部であり、ディレクトリのスキャン、ファイルの解析、ビルドコンテキストの管理を担当します。

#### `Context` 構造体への `CgoEnabled` の追加

```go
type Context struct {
	GOARCH     string // target architecture
	GOOS       string // target operating system
	CgoEnabled bool   // whether cgo can be used
	// ...
}

Context 構造体は、ビルドに関するすべての環境情報(ターゲットOS、アーキテクチャなど)を保持します。ここに CgoEnabled フィールドが追加されたことで、ビルドコンテキストがCgoの有効/無効状態を直接認識できるようになりました。これは、ビルドタグの評価やCgoファイルの処理において中心的な役割を果たします。

DefaultContext の初期化ロジックの変更

var DefaultContext = defaultContext()

var cgoEnabled = map[string]bool{
	"darwin/386":    true,
	"darwin/amd64":  true,
	"linux/386":     true,
	"linux/amd64":   true,
	"freebsd/386":   true,
	"freebsd/amd64": true,
}

func defaultContext() Context {
	var c Context

	c.GOARCH = envOr("GOARCH", runtime.GOARCH)
	c.GOOS = envOr("GOOS", runtime.GOOS)

	s := os.Getenv("CGO_ENABLED")
	switch s {
	case "1":
		c.CgoEnabled = true
	case "0":
		c.CgoEnabled = false
	default:
		c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
	}

	return c
}

DefaultContext は、Goツールがデフォルトで使用するビルドコンテキストです。以前は静的に初期化されていましたが、defaultContext() 関数を呼び出すように変更されました。この関数内で、CGO_ENABLED 環境変数の値がチェックされ、それが設定されていない場合は cgoEnabled マップに基づいてデフォルトのCgo有効状態が決定されます。このマップは、特定のOS/アーキテクチャの組み合わせでCgoがデフォルトで有効になるように定義されています。これにより、ユーザーが明示的に CGO_ENABLED を設定しない場合でも、適切なCgo状態が自動的に設定されます。

matchOSArch メソッドの拡張

func (ctxt *Context) matchOSArch(name string) bool {
	if ctxt.CgoEnabled && name == "cgo" {
		return true
	}
	if !ctxt.CgoEnabled && name == "nocgo" {
		return true
	}
	if name == ctxt.GOOS || name == ctxt.GOARCH {
		return true
	}
	i := strings.Index(name, "/")
	return i >= 0 && ctxt.matchOSArch(name[:i]) && ctxt.matchOSArch(name[i+1:])
}

matchOSArch メソッドは、ビルドタグ(例: linux, amd64, linux/amd64)が現在のビルドコンテキストに一致するかどうかを判断します。このコミットでは、"cgo""nocgo" という新しいタグの処理が追加されました。

  • name == "cgo" の場合、現在のコンテキストの CgoEnabledtrue であれば一致とみなされます。
  • name == "nocgo" の場合、現在のコンテキストの CgoEnabledfalse であれば一致とみなされます。 これにより、// +build cgo// +build nocgo といったビルドタグが、Cgoの有効/無効状態に基づいて正しく評価され、条件付きコンパイルが可能になります。また、darwin/nocgo のようにスラッシュで区切られた複合タグも再帰的に評価されるように変更されています。

ScanDir での CgoFiles の条件付き追加

	// ...
	if isCgo {
		if ctxt.CgoEnabled {
			di.CgoFiles = append(di.CgoFiles, name)
		}
	} else if isTest {
	// ...

ScanDir メソッドは、ディレクトリ内のGoソースファイルを解析し、その情報を DirInfo 構造体に格納します。Cgoファイル(_cgo.go などの命名規則を持つファイル)が検出された場合、以前は無条件に di.CgoFiles に追加されていました。この変更により、ctxt.CgoEnabledtrue の場合にのみ di.CgoFiles に追加されるようになりました。これは、Cgoが無効なビルドではCgoファイル自体をコンパイル対象から除外することで、ビルドエラーを防ぎ、ビルドの効率性を高めるためです。

src/cmd/go/main.go の変更点

このファイルは、go コマンドのメインエントリポイントであり、パッケージの解決やビルドプロセスの調整を行います。

	if !build.DefaultContext.CgoEnabled {
		have["runtime/cgo"] = true // ignore during walk
	}

このコードスニペットは、allPackages 関数内にあります。以前はコメントアウトされていましたが、このコミットで有効化されました。これは、build.DefaultContext.CgoEnabledfalse(Cgoが無効)の場合に、runtime/cgo パッケージをビルド対象から除外することを意味します。runtime/cgo パッケージはCgoの内部実装に関連するものであり、Cgoが無効なビルドでこのパッケージへの参照があるとビルドエラーになる可能性があるため、これを無視することで堅牢性を高めています。

src/pkg/net/cgo_stub.go および src/pkg/crypto/tls/root_stub.go の変更点

これらのファイルは、Cgoが利用できない環境や特定のOSで、Cgoに依存する機能の代替(スタブ)実装を提供するものです。

// +build nocgo

src/pkg/net/cgo_stub.go のビルドタグが // +build netbsd openbsd から // +build nocgo に変更されました。これにより、NetBSDやOpenBSDだけでなく、Cgoが有効になっていないすべての環境でこのスタブファイルがビルドされるようになります。これは、Cgoの有無に基づいてより汎用的な条件付きコンパイルを可能にします。

// +build plan9 darwin/nocgo

src/pkg/crypto/tls/root_stub.go のビルドタグが // +build plan9 から // +build plan9 darwin/nocgo に変更されました。これは、Plan 9環境、またはmacOS(darwin)でCgoが無効な場合にこのスタブファイルがビルドされることを意味します。これにより、macOS環境でCgoが利用できない場合でも、適切なTLSルート証明書のスタブが提供されるようになります。

これらの変更は、GoのビルドシステムがCgoの有効/無効状態をより細かく制御できるようになり、異なるビルド環境や要件に対応するための柔軟性を大幅に向上させました。

関連リンク

参考にした情報源リンク

  • Go言語公式ドキュメント
  • Go言語のソースコード
  • Go言語のIssueトラッカーおよびChange List (CL)
  • Stack Overflowなどの技術コミュニティでのGoビルドタグとCgoに関する議論
  • Go言語のビルドシステムに関するブログ記事や解説記事 (具体的なURLは割愛)

I have generated the detailed explanation in Markdown format, following all the specified instructions and chapter structure. I have included background, prerequisite knowledge, technical details, and explanations of core code changes. I also used the provided GitHub URL and the commit message to enrich the content. I did not save any files, only outputted to standard output.```markdown

[インデックス 10943] ファイルの概要

このコミットは、Go言語のビルドシステムに新しいビルドタグ cgonocgo を追加するものです。これにより、Cgo(C言語との相互運用機能)が有効か無効かに応じて、特定のソースファイルを条件付きでコンパイルできるようになります。特に、netパッケージ内の cgo_stub.go のような、Cgoが無効な場合にのみビルドされるべきファイルにこのタグを適用することで、ビルドプロセスの柔軟性と正確性を向上させます。

コミット

commit f52a2088ef58281cb11e904ebd5ed5441577fc71
Author: Russ Cox <rsc@golang.org>
Date:   Wed Dec 21 08:51:18 2011 -0500

    go/build: add new +build tags 'cgo' and 'nocgo'
    
    This lets us mark net's cgo_stub.go as only to be
    built when cgo is disabled.
    
    R=golang-dev, ality, mikioh.mikioh
    CC=golang-dev
    https://golang.org/cl/5489100
---
 src/cmd/go/main.go               |  8 +++---
 src/pkg/crypto/tls/root_stub.go  |  2 +-\
 src/pkg/debug/gosym/pclinetest.h |  2 ++\
 src/pkg/debug/gosym/pclinetest.s |  2 ++\
 src/pkg/go/build/build_test.go   | 13 +++++++++-
 src/pkg/go/build/dir.go          | 54 ++++++++++++++++++++++++++++++++--------
 src/pkg/net/cgo_stub.go          |  2 +-\
 7 files changed, 65 insertions(+), 18 deletions(-)

diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 2709750fcc..7b7f4a450d 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -242,11 +242,9 @@ func allPackages(what string) []string {
 	have := map[string]bool{
 		"builtin": true, // ignore pseudo-package that exists only for documentation
 	}\n-\t/*\n-\t\tif !build.DefaultContext.CgoEnabled {\n-\t\t\thave[\"runtime/cgo\"] = true // ignore during walk\n-\t\t}\n-\t*/\n+\tif !build.DefaultContext.CgoEnabled {\n+\t\thave[\"runtime/cgo\"] = true // ignore during walk\n+\t}\n \tvar pkgs []string
 
 	// Commands
diff --git a/src/pkg/crypto/tls/root_stub.go b/src/pkg/crypto/tls/root_stub.go
index 18dcb02043..d00493a573 100644
--- a/src/pkg/crypto/tls/root_stub.go
+++ b/src/pkg/crypto/tls/root_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.\n \n-// +build plan9\n+// +build plan9 darwin/nocgo\n \n package tls
 
diff --git a/src/pkg/debug/gosym/pclinetest.h b/src/pkg/debug/gosym/pclinetest.h
index a6c40e76cd..156c0b87b0 100644
--- a/src/pkg/debug/gosym/pclinetest.h
+++ b/src/pkg/debug/gosym/pclinetest.h
@@ -1,3 +1,5 @@
+// +build ignore\n+\n // Empty include file to generate z symbols
 \n \ndiff --git a/src/pkg/debug/gosym/pclinetest.s b/src/pkg/debug/gosym/pclinetest.s
index 6305435b09..c1d4818d40 100644
--- a/src/pkg/debug/gosym/pclinetest.s
+++ b/src/pkg/debug/gosym/pclinetest.s
@@ -1,3 +1,5 @@
+// +build ignore\n+\n TEXT linefrompc(SB),7,$0\t// Each byte stores its line delta
 BYTE $2;
 BYTE $1;
diff --git a/src/pkg/go/build/build_test.go b/src/pkg/go/build/build_test.go
index e86cfc012e..fd4030632a 100644
--- a/src/pkg/go/build/build_test.go
+++ b/src/pkg/go/build/build_test.go
@@ -46,7 +46,7 @@ var buildPkgs = []struct {\n \t{\n \t\t\"go/build/cgotest\",\n \t\t&DirInfo{\n-\t\t\tCgoFiles:    []string{\"cgotest.go\"},\n+\t\t\tCgoFiles:    ifCgo([]string{\"cgotest.go\"}),\n \t\t\tCFiles:      []string{\"cgotest.c\"},\n \t\t\tHFiles:      []string{\"cgotest.h\"},\n \t\t\tImports:     []string{\"C\", \"unsafe\"},\n@@ -56,6 +56,13 @@ var buildPkgs = []struct {\n \t},\n }\n \n+func ifCgo(x []string) []string {\n+\tif DefaultContext.CgoEnabled {\n+\t\treturn x\n+\t}\n+\treturn nil\n+}\n+\n const cmdtestOutput = \"3\"\n \n func TestBuild(t *testing.T) {\n@@ -72,6 +79,10 @@ func TestBuild(t *testing.T) {\n \t\t\tcontinue\n \t\t}\n \n+\t\tif tt.dir == \"go/build/cgotest\" && len(info.CgoFiles) == 0 {\n+\t\t\tcontinue\n+\t\t}\n+\n \t\ts, err := Build(tree, tt.dir, info)\n \t\tif err != nil {\n \t\t\tt.Errorf(\"Build(%#q): %v\", tt.dir, err)\ndiff --git a/src/pkg/go/build/dir.go b/src/pkg/go/build/dir.go
index 29d7c4c7d3..b710bc18da 100644
--- a/src/pkg/go/build/dir.go
+++ b/src/pkg/go/build/dir.go
@@ -26,9 +26,9 @@ import (\n \n // A Context specifies the supporting context for a build.\n type Context struct {\n-\tGOARCH string // target architecture\n-\tGOOS   string // target operating system\n-\t// TODO(rsc,adg): GOPATH\n+\tGOARCH     string // target architecture\n+\tGOOS       string // target operating system\n+\tCgoEnabled bool   // whether cgo can be used\n \n \t// By default, ScanDir uses the operating system\'s\n \t// file system calls to read directories and files.\n@@ -75,9 +75,34 @@ func (ctxt *Context) readFile(dir, file string) (string, []byte, error) {\n // The DefaultContext is the default Context for builds.\n // It uses the GOARCH and GOOS environment variables\n // if set, or else the compiled code\'s GOARCH and GOOS.\n-var DefaultContext = Context{\n-\tGOARCH: envOr(\"GOARCH\", runtime.GOARCH),\n-\tGOOS:   envOr(\"GOOS\", runtime.GOOS),\n+var DefaultContext = defaultContext()\n+\n+var cgoEnabled = map[string]bool{\n+\t\"darwin/386\":    true,\n+\t\"darwin/amd64\":  true,\n+\t\"linux/386\":     true,\n+\t\"linux/amd64\":   true,\n+\t\"freebsd/386\":   true,\n+\t\"freebsd/amd64\": true,\n+}\n+\n+func defaultContext() Context {\n+\tvar c Context\n+\n+\tc.GOARCH = envOr(\"GOARCH\", runtime.GOARCH)\n+\tc.GOOS = envOr(\"GOOS\", runtime.GOOS)\n+\n+\ts := os.Getenv(\"CGO_ENABLED\")\n+\tswitch s {\n+\tcase \"1\":\n+\t\tc.CgoEnabled = true\n+\tcase \"0\":\n+\t\tc.CgoEnabled = false\n+\tdefault:\n+\t\tc.CgoEnabled = cgoEnabled[c.GOOS+\"/\"+c.GOARCH]\n+\t}\n+\n+\treturn c\n }\n \n func envOr(name, def string) string {\n@@ -264,7 +289,9 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {\n \t\t\t}\n \t\t}\n \t\tif isCgo {\n-\t\t\tdi.CgoFiles = append(di.CgoFiles, name)\n+\t\t\tif ctxt.CgoEnabled {\n+\t\t\t\tdi.CgoFiles = append(di.CgoFiles, name)\n+\t\t\t}\n \t\t} else if isTest {\n \t\t\tif pkg == string(pf.Name.Name) {\n \t\t\t\tdi.TestGoFiles = append(di.TestGoFiles, name)\n@@ -306,7 +333,6 @@ func (ctxt *Context) ScanDir(dir string) (info *DirInfo, err error) {\n }\n \n var slashslash = []byte(\"//\")\n-var plusBuild = []byte(\"+build\")\n \n // shouldBuild reports whether it is okay to use this file,\n // The rule is that in the file\'s leading run of // comments\n@@ -527,14 +553,22 @@ func splitQuoted(s string) (r []string, err error) {\n //\n //\t$GOOS\n //\t$GOARCH\n-//\t$GOOS/$GOARCH\n+//\tcgo (if cgo is enabled)\n+//\tnocgo (if cgo is disabled)\n+//\ta slash-separated list of any of these\n //\n func (ctxt *Context) matchOSArch(name string) bool {\n+\tif ctxt.CgoEnabled && name == \"cgo\" {\n+\t\treturn true\n+\t}\n+\tif !ctxt.CgoEnabled && name == \"nocgo\" {\n+\t\treturn true\n+\t}\n \tif name == ctxt.GOOS || name == ctxt.GOARCH {\n \t\treturn true\n \t}\n \ti := strings.Index(name, \"/\")\n-\treturn i >= 0 && name[:i] == ctxt.GOOS && name[i+1:] == ctxt.GOARCH\n+\treturn i >= 0 && ctxt.matchOSArch(name[:i]) && ctxt.matchOSArch(name[i+1:])\n }\n \n // goodOSArchFile returns false if the name contains a $GOOS or $GOARCH\ndiff --git a/src/pkg/net/cgo_stub.go b/src/pkg/net/cgo_stub.go
index 4c49e63184..66aff837d0 100644
--- 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.\n \n-// +build netbsd openbsd\n+// +build nocgo\n \n // Stub cgo routines for systems that do not use cgo to do network lookups.\n \n```

## GitHub上でのコミットページへのリンク

[https://github.com/golang/go/commit/f52a2088ef58281cb11e904ebd5ed5441577fc71](https://github.com/golang/go/commit/f52a2088ef58281cb11e904ebd5ed5441577fc71)

## 元コミット内容

このコミットは、Go言語のビルドシステムに `cgo` および `nocgo` という新しいビルドタグを追加することを目的としています。これにより、Cgo(GoとC言語の相互運用機能)が有効になっているかどうかに基づいて、特定のGoソースファイルを条件付きでコンパイルする機能が提供されます。

具体的には、`net`パッケージ内の `cgo_stub.go` のようなファイルは、Cgoが無効な場合にのみビルドされるようにマークできるようになります。これは、Cgoが利用できない環境(例えば、クロスコンパイル時や特定のOS/アーキテクチャの組み合わせ)で、Cgoに依存しない代替実装を提供するために重要です。

この変更は、Goのビルドプロセスにおける柔軟性を高め、異なるビルド環境や要件に対応するための重要なステップです。

## 変更の背景

Go言語のビルドシステムは、特定のオペレーティングシステム(OS)やアーキテクチャ(ARCH)に基づいてファイルを条件付きでコンパイルする機能(ビルドタグ)を以前から持っていました。例えば、`+build linux` や `+build amd64` といったタグを使用することで、Linux環境でのみビルドされるファイルや、AMD64アーキテクチャでのみビルドされるファイルを指定できました。

しかし、Cgoの有効/無効という条件に基づいてファイルを切り替える直接的なメカニズムは存在しませんでした。Cgoは、GoプログラムからC言語のコードを呼び出すための重要な機能ですが、すべての環境で利用できるわけではありません。例えば、一部のクロスコンパイル設定や、Cコンパイラが利用できない環境ではCgoを無効にする必要があります。

このような状況下で、Cgoの有無によって動作が異なる、あるいはCgoに依存しない代替実装が必要な場合、開発者は手動でファイルを切り替えるか、複雑なビルドスクリプトを使用する必要がありました。これは、特に標準ライブラリのような広範な環境で利用されるコードベースにおいて、メンテナンスの負担となっていました。

このコミットは、この課題を解決するために、`cgo` と `nocgo` という専用のビルドタグを導入し、Cgoの有効/無効状態をビルドシステムが直接認識し、それに基づいてファイルのコンパイルを制御できるようにすることを目的としています。これにより、よりクリーンで宣言的な方法で条件付きコンパイルを実現し、ビルドプロセスの堅牢性と利便性を向上させます。

## 前提知識の解説

### Go言語のビルドタグ(Build Tags)

Go言語のビルドタグは、ソースファイルの先頭に記述される特別なコメント行で、そのファイルが特定のビルド条件を満たす場合にのみコンパイルされるように指定するメカニズムです。これにより、異なるオペレーティングシステム、アーキテクチャ、またはその他のカスタム条件に基づいて、コードベースを柔軟に構成できます。

ビルドタグは、ファイルの先頭にあるパッケージ宣言の前に、`// +build tag1 tag2` の形式で記述されます。複数のタグはスペースで区切られ、論理OR条件として扱われます。つまり、指定されたタグのいずれか一つでもビルド条件に合致すれば、そのファイルはコンパイル対象となります。

論理AND条件を指定するには、複数の `+build` 行を使用します。例えば、`// +build linux` と `// +build amd64` の両方が存在する場合、そのファイルはLinuxかつAMD64環境でのみコンパイルされます。

一般的なビルドタグには以下のようなものがあります。
*   **OS名**: `linux`, `windows`, `darwin` (macOS), `freebsd` など。
*   **アーキテクチャ名**: `amd64`, `386`, `arm`, `arm64` など。
*   **カスタムタグ**: `debug`, `release` など、ユーザーが定義する任意のタグ。これらは `go build -tags "debug"` のようにコマンドラインで指定できます。

### Cgo

Cgoは、Go言語のプログラムからC言語のコードを呼び出すためのGoの機能です。これにより、既存のCライブラリをGoプロジェクトで再利用したり、Goでは実装が難しい低レベルの操作を行ったりすることが可能になります。

Cgoを使用するには、Goのソースファイル内で `import "C"` を記述し、C言語の関数やデータ構造をGoのコードから参照します。Cgoは、GoコンパイラとCコンパイラ(通常はGCCやClang)の両方を必要とします。ビルド時には、CgoはCコードをコンパイルし、Goコードとリンクします。

Cgoは非常に強力な機能ですが、いくつかの制約や考慮事項があります。
*   **ビルド依存性**: Cコンパイラがシステムにインストールされている必要があります。
*   **クロスコンパイルの複雑さ**: 異なるOSやアーキテクチャ向けにクロスコンパイルする場合、Cgoのセットアップは複雑になることがあります。
*   **パフォーマンスオーバーヘッド**: GoとCの間でデータをやり取りする際には、わずかなオーバーヘッドが発生する可能性があります。
*   **ガベージコレクション**: CのメモリはGoのガベージコレクタの管理外であるため、手動でのメモリ管理が必要になる場合があります。

これらの理由から、Cgoは必要な場合にのみ使用され、Cgoが利用できない環境向けに代替実装を提供することが望ましい場合があります。

### 条件付きコンパイル(Conditional Compilation)

条件付きコンパイルとは、特定の条件が満たされた場合にのみ、コードの一部をコンパイルプロセスに含める技術です。Go言語では、主にビルドタグとファイル名規則(例: `_linux.go`)によって実現されます。

条件付きコンパイルの主な利点は以下の通りです。
*   **プラットフォーム固有のコード**: OSやアーキテクチャに特化したコードを記述し、他のプラットフォームではコンパイルしないようにできます。
*   **機能の有効/無効化**: デバッグ機能や特定のハードウェアサポートなど、特定の機能をビルド時に有効または無効にできます。
*   **依存関係の管理**: 特定のライブラリや機能が利用できない環境で、代替の実装を提供できます。

このコミットは、Cgoの有効/無効という新しい条件をGoの条件付きコンパイルのメカニズムに統合することで、開発者がよりきめ細かくビルドプロセスを制御できるようにします。

## 技術的詳細

このコミットの技術的な核心は、Goのビルドシステム、特に `go/build` パッケージが、Cgoの有効/無効状態を認識し、それに基づいて新しいビルドタグ `cgo` および `nocgo` を処理するように拡張された点にあります。

1.  **`Context` 構造体への `CgoEnabled` フィールドの追加**:
    `src/pkg/go/build/dir.go` 内の `build.Context` 構造体に `CgoEnabled bool` フィールドが追加されました。このフィールドは、現在のビルドコンテキストでCgoが有効であるかどうかを示します。

2.  **`DefaultContext` の初期化ロジックの変更**:
    `build.DefaultContext` は、Goツールがデフォルトで使用するビルドコンテキストです。このコミットでは、`DefaultContext` の初期化方法が変更され、`defaultContext()` 関数を通じて `CgoEnabled` の値が決定されるようになりました。
    *   `CGO_ENABLED` 環境変数が設定されている場合(`"1"` または `"0"`)、その値が優先されます。
    *   `CGO_ENABLED` が設定されていない場合、`cgoEnabled` マップ(`GOOS/GOARCH` の組み合わせでCgoがデフォルトで有効なプラットフォームを定義)に基づいて `CgoEnabled` の値が決定されます。これにより、特定のプラットフォームではCgoがデフォルトで有効になるように設定されます。

3.  **`matchOSArch` メソッドの拡張**:
    `build.Context` の `matchOSArch` メソッドは、ビルドタグが現在のビルドコンテキストに一致するかどうかを判断します。このメソッドが拡張され、`name` が `"cgo"` または `"nocgo"` の場合に、`ctxt.CgoEnabled` の値に基づいて `true` または `false` を返すようになりました。
    *   `name == "cgo"` の場合、`ctxt.CgoEnabled` が `true` であれば一致。
    *   `name == "nocgo"` の場合、`ctxt.CgoEnabled` が `false` であれば一致。
    これにより、`// +build cgo` や `// +build nocgo` といったビルドタグが、Cgoの有効/無効状態に基づいて正しく評価されるようになります。

4.  **`ScanDir` での `CgoFiles` の条件付き追加**:
    `build.Context` の `ScanDir` メソッドは、ディレクトリをスキャンしてGoソースファイルを解析し、`DirInfo` 構造体にその情報を格納します。このメソッド内で、Cgoファイル(`_cgo.go` などの命名規則を持つファイル)が検出された場合、以前は無条件に `di.CgoFiles` に追加されていましたが、このコミット以降は `ctxt.CgoEnabled` が `true` の場合にのみ追加されるようになりました。これは、Cgoが無効なビルドではCgoファイル自体をコンパイル対象から除外するためです。

5.  **`src/cmd/go/main.go` の変更**:
    `go` コマンドのメインロジックにおいて、`runtime/cgo` パッケージがCgo無効時に無視されるように、コメントアウトされていたコードが有効化されました。これは、Cgoが無効なビルドで `runtime/cgo` パッケージへの参照がビルドエラーを引き起こさないようにするためのものです。

6.  **既存ファイルのビルドタグの更新**:
    `src/pkg/crypto/tls/root_stub.go` や `src/pkg/net/cgo_stub.go` のようなファイルは、Cgoが利用できない場合にのみビルドされるべきスタブ実装です。これらのファイルのビルドタグが `// +build nocgo` や `// +build plan9 darwin/nocgo` のように更新され、新しい `nocgo` タグを活用するようになりました。

これらの変更により、GoのビルドシステムはCgoの有効/無効状態をビルドコンテキストの一部として扱い、それに基づいてソースファイルの選択とコンパイルを自動的に調整できるようになりました。これにより、開発者はCgoの有無に依存するコードをより簡単に管理し、異なるビルド環境に対応する堅牢なGoプログラムを構築できます。

## コアとなるコードの変更箇所

このコミットにおける主要なコード変更は以下のファイルに集中しています。

*   **`src/pkg/go/build/dir.go`**:
    *   `Context` 構造体に `CgoEnabled bool` フィールドが追加されました。
    *   `DefaultContext` の初期化ロジックが `defaultContext()` 関数に分離され、`CgoEnabled` の値が `CGO_ENABLED` 環境変数またはプラットフォーム固有のデフォルト設定に基づいて決定されるようになりました。
    *   `matchOSArch` メソッドが拡張され、`cgo` および `nocgo` ビルドタグの評価ロジックが追加されました。
    *   `ScanDir` メソッド内で、Cgoファイルが `CgoEnabled` が `true` の場合にのみ `CgoFiles` に追加されるように変更されました。

*   **`src/cmd/go/main.go`**:
    *   `allPackages` 関数内で、`build.DefaultContext.CgoEnabled` が `false` の場合に `runtime/cgo` パッケージが無視されるように、コメントアウトされていたコードが有効化されました。

*   **`src/pkg/go/build/build_test.go`**:
    *   `ifCgo` ヘルパー関数が追加され、テストケースで `CgoFiles` の設定を `CgoEnabled` に応じて動的に調整できるようになりました。
    *   `TestBuild` 関数内で、`cgotest` ディレクトリのテストが `CgoFiles` が空の場合にスキップされる条件が追加されました。

*   **`src/pkg/net/cgo_stub.go`**:
    *   ビルドタグが `// +build netbsd openbsd` から `// +build nocgo` に変更されました。これにより、Cgoが無効な場合にのみこのスタブファイルがビルドされるようになります。

*   **`src/pkg/crypto/tls/root_stub.go`**:
    *   ビルドタグが `// +build plan9` から `// +build plan9 darwin/nocgo` に変更されました。これにより、Plan 9またはmacOSでCgoが無効な場合にこのスタブファイルがビルドされるようになります。

*   **`src/pkg/debug/gosym/pclinetest.h` および `src/pkg/debug/gosym/pclinetest.s`**:
    *   `// +build ignore` タグが追加されました。これは、これらのファイルが通常のビルドプロセスから除外されることを示します。

## コアとなるコードの解説

### `src/pkg/go/build/dir.go` の変更点

このファイルは、Goのビルドシステムの中核をなす `go/build` パッケージの一部であり、ディレクトリのスキャン、ファイルの解析、ビルドコンテキストの管理を担当します。

#### `Context` 構造体への `CgoEnabled` の追加

```go
type Context struct {
	GOARCH     string // target architecture
	GOOS       string // target operating system
	CgoEnabled bool   // whether cgo can be used
	// ...
}

Context 構造体は、ビルドに関するすべての環境情報(ターゲットOS、アーキテクチャなど)を保持します。ここに CgoEnabled フィールドが追加されたことで、ビルドコンテキストがCgoの有効/無効状態を直接認識できるようになりました。これは、ビルドタグの評価やCgoファイルの処理において中心的な役割を果たします。

DefaultContext の初期化ロジックの変更

var DefaultContext = defaultContext()

var cgoEnabled = map[string]bool{
	"darwin/386":    true,
	"darwin/amd64":  true,
	"linux/386":     true,
	"linux/amd64":   true,
	"freebsd/386":   true,
	"freebsd/amd64": true,
}

func defaultContext() Context {
	var c Context

	c.GOARCH = envOr("GOARCH", runtime.GOARCH)
	c.GOOS = envOr("GOOS", runtime.GOOS)

	s := os.Getenv("CGO_ENABLED")
	switch s {
	case "1":
		c.CgoEnabled = true
	case "0":
		c.CgoEnabled = false
	default:
		c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
	}

	return c
}

DefaultContext は、Goツールがデフォルトで使用するビルドコンテキストです。以前は静的に初期化されていましたが、defaultContext() 関数を呼び出すように変更されました。この関数内で、CGO_ENABLED 環境変数の値がチェックされ、それが設定されていない場合は cgoEnabled マップに基づいてデフォルトのCgo有効状態が決定されます。このマップは、特定のOS/アーキテクチャの組み合わせでCgoがデフォルトで有効になるように定義されています。これにより、ユーザーが明示的に CGO_ENABLED を設定しない場合でも、適切なCgo状態が自動的に設定されます。

matchOSArch メソッドの拡張

func (ctxt *Context) matchOSArch(name string) bool {
	if ctxt.CgoEnabled && name == "cgo" {
		return true
	}
	if !ctxt.CgoEnabled && name == "nocgo" {
		return true
	}
	if name == ctxt.GOOS || name == ctxt.GOARCH {
		return true
	}
	i := strings.Index(name, "/")
	return i >= 0 && ctxt.matchOSArch(name[:i]) && ctxt.matchOSArch(name[i+1:])
}

matchOSArch メソッドは、ビルドタグ(例: linux, amd64, linux/amd64)が現在のビルドコンテキストに一致するかどうかを判断します。このコミットでは、"cgo""nocgo" という新しいタグの処理が追加されました。

  • name == "cgo" の場合、現在のコンテキストの CgoEnabledtrue であれば一致とみなされます。
  • name == "nocgo" の場合、現在のコンテキストの CgoEnabledfalse であれば一致とみなされます。 これにより、// +build cgo// +build nocgo といったビルドタグが、Cgoの有効/無効状態に基づいて正しく評価され、条件付きコンパイルが可能になります。また、darwin/nocgo のようにスラッシュで区切られた複合タグも再帰的に評価されるように変更されています。

ScanDir での CgoFiles の条件付き追加

	// ...
	if isCgo {
		if ctxt.CgoEnabled {
			di.CgoFiles = append(di.CgoFiles, name)
		}
	} else if isTest {
	// ...

ScanDir メソッドは、ディレクトリ内のGoソースファイルを解析し、その情報を DirInfo 構造体に格納します。Cgoファイル(_cgo.go などの命名規則を持つファイル)が検出された場合、以前は無条件に di.CgoFiles に追加されていました。この変更により、ctxt.CgoEnabledtrue の場合にのみ di.CgoFiles に追加されるようになりました。これは、Cgoが無効なビルドではCgoファイル自体をコンパイル対象から除外することで、ビルドエラーを防ぎ、ビルドの効率性を高めるためです。

src/cmd/go/main.go の変更点

このファイルは、go コマンドのメインエントリポイントであり、パッケージの解決やビルドプロセスの調整を行います。

	if !build.DefaultContext.CgoEnabled {
		have["runtime/cgo"] = true // ignore during walk
	}

このコードスニペットは、allPackages 関数内にあります。以前はコメントアウトされていましたが、このコミットで有効化されました。これは、build.DefaultContext.CgoEnabledfalse(Cgoが無効)の場合に、runtime/cgo パッケージをビルド対象から除外することを意味します。runtime/cgo パッケージはCgoの内部実装に関連するものであり、Cgoが無効なビルドでこのパッケージへの参照があるとビルドエラーになる可能性があるため、これを無視することで堅牢性を高めています。

src/pkg/net/cgo_stub.go および src/pkg/crypto/tls/root_stub.go の変更点

これらのファイルは、Cgoが利用できない環境や特定のOSで、Cgoに依存する機能の代替(スタブ)実装を提供するものです。

// +build nocgo

src/pkg/net/cgo_stub.go のビルドタグが // +build netbsd openbsd から // +build nocgo に変更されました。これにより、NetBSDやOpenBSDだけでなく、Cgoが有効になっていないすべての環境でこのスタブファイルがビルドされるようになります。これは、Cgoの有無に基づいてより汎用的な条件付きコンパイルを可能にします。

// +build plan9 darwin/nocgo

src/pkg/crypto/tls/root_stub.go のビルドタグが // +build plan9 から // +build plan9 darwin/nocgo に変更されました。これは、Plan 9環境、またはmacOS(darwin)でCgoが有効な場合にこのスタブファイルがビルドされることを意味します。これにより、macOS環境でCgoが利用できない場合でも、適切なTLSルート証明書のスタブが提供されるようになります。

これらの変更は、GoのビルドシステムがCgoの有効/無効状態をより細かく制御できるようになり、異なるビルド環境や要件に対応するための柔軟性を大幅に向上させました。

関連リンク

参考にした情報源リンク

  • Go言語公式ドキュメント
  • Go言語のソースコード
  • Go言語のIssueトラッカーおよびChange List (CL)
  • Stack Overflowなどの技術コミュニティでのGoビルドタグとCgoに関する議論
  • Go言語のビルドシステムに関するブログ記事や解説記事 (具体的なURLは割愛)