[インデックス 11347] ファイルの概要
このコミットは、Go言語のコマンドラインツールcmd/go
に関連するもので、ビルドプロセスで不足していたファイルを追加することで、ビルドエラーを修正することを目的としています。具体的には、bootstrap.go
とhttp.go
という2つの新しいファイルが追加されています。
コミット
このコミットは、Go言語の主要な開発者の一人であるRuss Coxによって行われました。コミットの目的は、cmd/go
のビルドを修正するために、不足していたファイルを追加することです。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1cfae8bcbf283b3c6837ca5b8db9ddae05f311c0
元コミット内容
cmd/go: add missing files (fix build)
TBR=r
CC=golang-dev
https://golang.org/cl/5571050
変更の背景
このコミットの背景には、Go言語のビルドシステム、特にcmd/go
コマンドのブートストラッププロセスがあります。Goのビルドは、Go自身を使ってGoをビルドするという、いわゆる「セルフホスト」な性質を持っています。このプロセスでは、まず非常に基本的なGoコンパイラとツールチェイン(ブートストラップ版)がビルドされ、それを使って完全なGoツールチェインがビルドされます。
このコミットが行われた2012年1月時点では、Goのビルドシステムはまだ進化の途中にありました。cmd/go
は、バージョン管理システム(VCS)からのコード取得など、ネットワークアクセスを必要とする機能を持っています。これらの機能は通常、net/http
パッケージを使用します。しかし、ブートストラップビルドの段階では、net/http
のような依存関係の多いパッケージをビルドに含めることは、ビルド時間や複雑性を増大させるため、避けたいという意図がありました。
このコミットは、ブートストラップビルド時にnet/http
パッケージが利用できないことによるビルドエラーを解決するために導入されました。具体的には、ブートストラップビルド用のスタブ(ダミー)実装と、通常のビルド用の実際のHTTPクライアント実装を、ビルドタグを使って切り替えることで、この問題を解決しています。これにより、ブートストラップビルドは軽量に保たれつつ、最終的なgo
コマンドは完全な機能を持つことができるようになります。
前提知識の解説
-
Go言語のビルドプロセスとブートストラップ: Go言語は「セルフホスト」な言語であり、Goコンパイラやツールチェイン自体がGoで書かれています。そのため、GoのソースコードからGoツールチェインをビルドする際には、まず既存のGoコンパイラ(またはC言語で書かれた初期のコンパイラ)を使って、Goツールチェインの「ブートストラップ版」をビルドします。このブートストラップ版は、必要最小限の機能しか持たず、主に完全なGoツールチェインをビルドするために使用されます。その後、このブートストラップ版のツールチェインを使って、最終的なGoツールチェインがビルドされます。この多段階ビルドプロセスにより、Goは自身の進化をGo言語自身で支えることができます。
-
Goのビルドタグ (
+build
ディレクティブ): Goのソースファイルには、ファイルの先頭に+build
ディレクティブを記述することで、そのファイルを特定の条件下でのみコンパイルするように指定できます。これは「ビルドタグ」と呼ばれます。例えば、// +build linux
と書かれたファイルはLinux環境でのみコンパイルされ、// +build debug
と書かれたファイルはgo build -tags debug
のようにdebug
タグが指定された場合にのみコンパイルされます。 このコミットでは、+build cmd_go_bootstrap
と+build !cmd_go_bootstrap
という2つのタグが使用されています。+build cmd_go_bootstrap
: このタグを持つファイルは、cmd_go_bootstrap
タグが有効な場合にのみコンパイルされます。これはブートストラップビルド時に使用されます。+build !cmd_go_bootstrap
: 先頭の!
は否定を意味します。このタグを持つファイルは、cmd_go_bootstrap
タグが有効でない場合にのみコンパイルされます。これは通常のビルド時に使用されます。
-
net/http
パッケージ: Go言語の標準ライブラリに含まれるnet/http
パッケージは、HTTPクライアントおよびサーバー機能を提供します。Webアプリケーションやネットワーク通信を行うGoプログラムでは頻繁に利用されます。このパッケージは、ネットワークスタックやTLS/SSLなど、比較的多くの依存関係を持つため、ブートストラップビルドのような軽量な環境では、その依存関係が問題となることがあります。
技術的詳細
このコミットは、Goのビルドシステムにおける条件付きコンパイルの典型的な例を示しています。src/cmd/go/bootstrap.go
とsrc/cmd/go/http.go
の2つのファイルが追加され、それぞれ異なるビルドタグが適用されています。
-
src/cmd/go/bootstrap.go
: このファイルは// +build cmd_go_bootstrap
というビルドタグを持っています。これは、Goツールチェインのブートストラップビルド時にのみコンパイルされることを意味します。 このファイルには、httpGET
という関数が定義されていますが、その実装は非常にシンプルで、常にエラーを返すスタブ(ダミー)となっています。func httpGET(url string) ([]byte, error) { return nil, errors.New("no http in bootstrap go command") }
このスタブ実装の目的は、ブートストラップビルド時に
net/http
パッケージのような重い依存関係を導入することなく、httpGET
という関数シグネチャが存在するようにすることです。これにより、cmd/go
の他の部分がhttpGET
を呼び出しても、コンパイルエラーにならず、ブートストラップビルドが成功するようになります。ただし、ブートストラップ版のgo
コマンドでは、HTTP通信を伴う機能(例:go get
)は利用できません。 -
src/cmd/go/http.go
: このファイルは// +build !cmd_go_bootstrap
というビルドタグを持っています。これは、cmd_go_bootstrap
タグが有効でない場合、つまり通常のGoツールチェインのビルド時にのみコンパイルされることを意味します。 このファイルには、実際のHTTP GETリクエストを実行するhttpGET
関数の実装が含まれています。package main import ( "fmt" "io/ioutil" "net/http" ) // httpGET returns the data from an HTTP GET request for the given URL. func httpGET(url string) ([]byte, error) { resp, err := http.Get(url) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != 200 { return nil, fmt.Errorf("%s: %s", url, resp.Status) } b, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("%s: %v", url, err) } return b, nil }
この実装は、
net/http
パッケージを利用して実際のHTTP通信を行い、指定されたURLからデータを取得します。ステータスコードのチェックやエラーハンドリングも含まれています。このファイルがコンパイルされることで、最終的にユーザーが利用するgo
コマンドは、ネットワーク通信を伴うすべての機能(例:go get
によるリモートリポジトリからのパッケージ取得)を完全に利用できるようになります。
この二重の実装とビルドタグによる切り替えは、Goのビルドシステムが、異なるビルドフェーズ(ブートストラップと最終ビルド)で異なる要件(軽量性 vs. 完全な機能)を満たすための巧妙な設計パターンを示しています。
コアとなるコードの変更箇所
このコミットで追加された主要なコードは以下の2つのファイルです。
-
src/cmd/go/bootstrap.go
// Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build cmd_go_bootstrap // This code is compiled only into the bootstrap 'go' binary. // These stubs avoid importing packages with large dependency // trees, like the use of "net/http" in vcs.go. package main import "errors" func httpGET(url string) ([]byte, error) { return nil, errors.New("no http in bootstrap go command") }
-
src/cmd/go/http.go
// Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // +build !cmd_go_bootstrap // This code is compiled into the real 'go' binary, but it is not // compiled into the binary that is built during all.bash, so as // to avoid needing to build net (and thus use cgo) during the // bootstrap process. package main import ( "fmt" "io/ioutil" "net/http" ) // httpGET returns the data from an HTTP GET request for the given URL. func httpGET(url string) ([]byte, error) { resp, err := http.Get(url) if err != nil { return nil, err } defer resp.Body.Close() if resp.StatusCode != 200 { return nil, fmt.Errorf("%s: %s", url, resp.Status) } b, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("%s: %v", url, err) } return b, nil }
コアとなるコードの解説
-
src/cmd/go/bootstrap.go
:// +build cmd_go_bootstrap
: この行が最も重要で、このファイルがブートストラップビルド時にのみコンパイルされることを示します。func httpGET(url string) ([]byte, error)
:httpGET
という関数が定義されていますが、その実装は常にエラーを返すダミーです。これは、ブートストラップビルド時にnet/http
パッケージの複雑な依存関係を避けるためのプレースホルダーとして機能します。ブートストラップ版のgo
コマンドでは、HTTP通信を必要とする機能は意図的に無効化されます。
-
src/cmd/go/http.go
:// +build !cmd_go_bootstrap
: この行は、このファイルが通常のビルド時にのみコンパイルされることを示します。ブートストラップビルド時にはコンパイルされません。import ("fmt", "io/ioutil", "net/http")
: 実際のHTTP通信に必要な標準ライブラリパッケージがインポートされています。特にnet/http
が重要です。func httpGET(url string) ([]byte, error)
: こちらのhttpGET
関数は、net/http.Get
を使用して実際にHTTP GETリクエストを実行し、レスポンスボディを読み取ってバイトスライスとして返します。HTTPステータスコードが200以外の場合や、ネットワークエラーが発生した場合には、適切なエラーを返します。この実装により、最終的なgo
コマンドは完全なHTTP通信機能を持つことができます。
この2つのファイルは、同じ関数名httpGET
を定義していますが、ビルドタグによってどちらか一方のみがコンパイルされるため、名前の衝突は発生しません。これはGoのビルドシステムにおける強力な機能の一つです。
関連リンク
- Go CL 5571050: https://golang.org/cl/5571050 (GoのコードレビューシステムGerritへのリンク)
参考にした情報源リンク
- Go言語の公式ドキュメント (ビルドタグに関する情報): https://pkg.go.dev/cmd/go#hdr-Build_constraints
- Go言語のブートストラッププロセスに関する一般的な情報 (Goのソースコードや関連する設計ドキュメント)