[インデックス 1127] ファイルの概要
このコミットは、Go言語の初期開発段階におけるビルドスクリプト src/lib/make.bash
のクリーンアップと再編成に関するものです。具体的には、ビルドプロセスの可読性と保守性を向上させるために、共通のビルドロジックを関数として抽出し、また io
パッケージのビルド順序を他のパッケージよりも前倒しにしています。
コミット
commit f3e354ec26622805f156e4f0d1a2b23fadead89c
Author: Rob Pike <r@golang.org>
Date: Fri Nov 14 12:53:44 2008 -0800
clean up make script
reorder pieces so io is earlier
R=rsc
DELTA=66 (27 added, 24 deleted, 15 changed)
OCL=19248
CL=19255
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f3e354ec26622805f156e4f0d1a2b23fadead89c
元コミット内容
clean up make script
reorder pieces so io is earlier
変更の背景
このコミットが行われた2008年11月は、Go言語がまだ一般に公開される前の初期開発段階にありました。この時期のコードベースは急速に進化しており、ビルドシステムも同様に成熟途上にありました。
この変更の主な背景は以下の通りです。
- ビルドスクリプトの整理と可読性向上:
src/lib/make.bash
は、Go言語の標準ライブラリやツールをビルドするための主要なスクリプトでした。初期のスクリプトは、機能が追加されるにつれて肥大化し、重複するコードや複雑なロジックが含まれる傾向にありました。このコミットは、共通のビルドパターンを関数として抽出し、スクリプト全体の構造をより明確にすることで、可読性と保守性を向上させることを目的としています。 io
パッケージのビルド順序の最適化: コミットメッセージに明記されているように、「io
をより早くする」という目的がありました。Go言語のio
パッケージは、入出力操作の基本的なインターフェースと機能を提供し、多くの他の標準ライブラリパッケージ(例:bufio
,net
,os
など)がio
パッケージに依存しています。したがって、io
パッケージが他の依存パッケージよりも先にビルドされることは、ビルドプロセスの整合性と効率性を確保するために重要でした。これは、依存関係の解決や、ビルドエラーの回避に寄与します。
前提知識の解説
このコミットの変更内容を理解するためには、以下の前提知識が役立ちます。
- Go言語の初期のビルドシステム:
6g
コンパイラ: 当時のGo言語のコンパイラは、ターゲットアーキテクチャに応じて6g
(amd64),8g
(386),5g
(arm) のように命名されていました。これらのコンパイラはGoのソースコードをコンパイルし、オブジェクトファイル(.6
,.8
,.5
など)を生成しました。make.bash
: Go言語のプロジェクトでは、C言語のmake
のようなビルドシステムではなく、シェルスクリプト(特にbash
)がビルドプロセスを管理するためによく使用されていました。これは、Goのクロスプラットフォームな性質と、シンプルなビルドプロセスを好む設計思想に合致していました。GOROOT/pkg
: ビルドされたGoパッケージのアーカイブファイル(.a
拡張子)やオブジェクトファイルは、GOROOT/pkg
ディレクトリ以下に配置され、他のパッケージから参照可能になります。make install
: Goのパッケージディレクトリ内でmake install
を実行すると、そのパッケージがコンパイルされ、GOROOT/pkg
にインストールされるのが一般的なパターンでした。
- シェルスクリプト (
bash
) の基本:#!/bin/bash
: スクリプトがbash
で実行されることを指定するシバン。set -e
: このコマンドは、スクリプト内で実行されるコマンドが一つでも失敗(ゼロ以外の終了ステータスを返す)した場合、スクリプト全体の実行を即座に終了させる設定です。これにより、エラーが発生した際に不完全なビルドが続行されるのを防ぎます。function name() { ... }
:bash
における関数の定義構文。rm -f *.6
: 現在のディレクトリにある.6
拡張子を持つファイルを強制的に削除します。これは、古いビルド成果物をクリーンアップするためによく使われます。for i in ...; do ...; done
: リスト内の各要素に対してループ処理を行う構文。basename $i .go
: ファイルパスからディレクトリ部分と指定された拡張子(.go
)を取り除き、ファイル名のみを抽出します。echo
: 標準出力に文字列を出力します。デバッグや進捗表示によく使われます。cd directory
: カレントディレクトリを指定されたディレクトリに変更します。
- Go言語のパッケージ依存関係:
- Go言語のパッケージは、他のパッケージの機能を利用するためにインポートします。このとき、インポートされる側のパッケージは、インポートする側のパッケージよりも先にコンパイルされ、利用可能になっている必要があります。
io
パッケージは、Goの標準ライブラリの中でも非常に基本的なパッケージであり、Reader
,Writer
などのインターフェースを定義しています。これらのインターフェースは、ファイル操作、ネットワーク通信、バッファリングなど、Goの多くのI/O関連機能の基盤となっています。そのため、io
パッケージは他の多くのパッケージから直接的または間接的に依存されています。
技術的詳細
このコミットの技術的な変更点は、主に src/lib/make.bash
スクリプトの構造化とビルド順序の調整にあります。
- 関数の導入によるコードのモジュール化:
buildfiles
関数:.go
ファイルを個別にコンパイルするためのロジックをカプセル化します。引数として渡された各Goファイルを6g
コンパイラでコンパイルし、GOROOT/pkg
ディレクトリにオブジェクトファイル(.6
)として出力します。function buildfiles() { rm -f *.6 for i do base=$(basename $i .go) echo 6g -o $GOROOT/pkg/$base.6 $i 6g -o $GOROOT/pkg/$base.6 $i done }
builddirs
関数: ディレクトリ(Goパッケージ)をビルドし、インストールするためのロジックをカプセル化します。引数として渡された各ディレクトリにcd
し、その中でmake install
を実行し、元のディレクトリに戻ります。function builddirs() { for i do echo; echo; echo %%%% making lib/$i %%%%; echo cd $i make install cd .. done }
for
ループとコンパイル/インストールコマンドが抽象化され、スクリプト全体の行数が削減され、意図が明確になりました。 - ビルド順序の再編成:
- 変更前は、
strings.go
、syscall
,os
,math
,reflect
,fmt
、そしてflag.go
,container/vector.go
,rand.go
,sort.go
,io.go
,bufio.go
,once.go
,bignum.go
、最後にnet
,time
,http
,regexp
の順でビルドされていました。 - 変更後は、
buildfiles strings.go
の後、builddirs syscall math os reflect
が続き、その直後にbuildfiles io.go
が配置されています。これは、以前のflag.go
などを含むグループよりも前にio.go
がビルドされることを意味します。 - この順序変更は、Goの標準ライブラリにおける
io
パッケージの基本的な性質と、他の多くのパッケージがio
に依存しているという事実を反映しています。io
が早期にビルドされることで、後続の依存パッケージのビルドがスムーズに行われるようになります。
- 変更前は、
set -e
の位置:- 変更前は、スクリプトの冒頭(シバンとコメントの直後)に
set -e
がありました。 - 変更後は、関数定義の後に
set -e
が移動しています。これは、関数定義自体が失敗する可能性は低く、実際のビルドコマンドが実行される前にset -e
が有効になっていれば十分であるという判断に基づいている可能性があります。また、関数定義の前にset -e
があると、スクリプトの解析段階で予期せぬ挙動を引き起こす可能性を排除するためかもしれません。
- 変更前は、スクリプトの冒頭(シバンとコメントの直後)に
コアとなるコードの変更箇所
src/lib/make.bash
ファイルにおける diff
の主要な変更点は以下の通りです。
--- a/src/lib/make.bash
+++ b/src/lib/make.bash
@@ -4,49 +4,52 @@
#!/bin/bash
-set -e
+function buildfiles() {
+\trm -f *.6
+\tfor i
+\tdo
+\t\tbase=$(basename $i .go)\n
+\t\techo 6g -o $GOROOT/pkg/$base.6 $i
+\t\t6g -o $GOROOT/pkg/$base.6 $i
+\tdone
+}
+\n
+function builddirs() {
+\tfor i
+\tdo
+\t\techo; echo; echo %%%% making lib/$i %%%%; echo
+\t\tcd $i
+\t\tmake install
+\t\tcd ..
+\tdone
+}
\n
-# Don\'t sort the files in the for loop - some of the orderings matter.\n
-rm -f *.6\n
-for i in \\\n
-\tstrings.go\\\n
-\n
-do\n
-\tbase=$(basename $i .go)\n
-\techo 6g -o $GOROOT/pkg/$base.6 $i\n
-\t6g -o $GOROOT/pkg/$base.6 $i\n
-done\n
-\n
-for i in syscall os math reflect fmt\n
-do\n
-\techo; echo; echo %%%% making lib/$i %%%%; echo\n
-\tcd $i\n
-\tmake install\n
-\tcd ..\n
-done\n
-\n
-# Don\'t sort the files in the for loop - some of the orderings matter.\n
+set -e\n
rm -f *.6\n
-for i in \\\n
-\tflag.go\\\n
-\tcontainer/vector.go\\\n
-\trand.go\\\n
-\tsort.go\\\n
-\tio.go\\\n
-\tbufio.go\\\n
-\tonce.go\\\n
-\tbignum.go\\\n
-\n
-do\n
-\tbase=$(basename $i .go)\n
-\techo 6g -o $GOROOT/pkg/$base.6 $i\n
-\t6g -o $GOROOT/pkg/$base.6 $i\n
-done\n
-\n
-for i in net time http regexp\n
-do\n
-\techo; echo; echo %%%% making lib/$i %%%%; echo\n
-\tcd $i\n
-\tmake install\n
-\tcd ..\n
-done\n
+\n
+# Don\'t sort the elements of the lists - some of the orderings matter.\n
+\n
+buildfiles\tstrings.go\n
+\n
+builddirs\tsyscall \\\n
+\t\tmath \\\n
+\t\tos\t\\\n
+\t\treflect \\\n
+\t\n
+buildfiles\tio.go\n
+\n
+builddirs\tfmt\n
+\n
+buildfiles\tflag.go\\\n
+\t\tcontainer/vector.go\\\n
+\t\trand.go\\\n
+\t\tsort.go\\\n
+\t\tbufio.go\\\n
+\t\tonce.go\\\n
+\t\tbignum.go\\\n
+\t\n
+builddirs\tnet\\\n
+\t\ttime\\\n
+\t\thttp\\\n
+\t\tregexp\\\n
+\n
コアとなるコードの解説
この変更は、make.bash
スクリプトの構造を大幅に改善し、Go言語のビルドプロセスをより堅牢で理解しやすいものにしています。
buildfiles
関数の導入:- この関数は、単一のGoソースファイルをコンパイルする共通のパターンを抽象化します。以前は、
strings.go
やflag.go
など、個々のファイルをコンパイルする際に同じrm -f *.6
,for
ループ,basename
,echo 6g
,6g
コマンドのシーケンスが繰り返されていました。 buildfiles
を使うことで、これらの繰り返しが排除され、スクリプトがよりDRY (Don't Repeat Yourself) になりました。buildfiles strings.go
のように呼び出すことで、strings.go
がコンパイルされることが明確になります。
- この関数は、単一のGoソースファイルをコンパイルする共通のパターンを抽象化します。以前は、
builddirs
関数の導入:- この関数は、Goのパッケージディレクトリ(例:
syscall
,os
)に入り、その中でmake install
を実行し、元のディレクトリに戻るという共通のパターンを抽象化します。 - 以前は、各パッケージディレクトリに対して
echo
,cd
,make install
,cd ..
のシーケンスが繰り返されていました。 builddirs syscall math os reflect
のように呼び出すことで、複数のディレクトリがまとめてビルドされることが一目でわかります。
- この関数は、Goのパッケージディレクトリ(例:
- ビルド順序の変更と
io.go
の位置:- 最も重要な変更点の一つは、
buildfiles io.go
の呼び出しが、以前よりも早い段階に移動したことです。具体的には、strings.go
とsyscall
,math
,os
,reflect
のビルドの直後に配置されています。 - これは、Goの
io
パッケージが、bufio
,net
,http
など、後続の多くのパッケージの基本的な依存関係であることを考慮したものです。io
パッケージが早期にビルドされることで、これらの依存パッケージがio
の機能を利用できるようになり、ビルドの失敗を防ぎ、依存関係の解決を保証します。
- 最も重要な変更点の一つは、
set -e
の移動:set -e
が関数定義の後に移動したことで、スクリプトの実行フローがより明確になります。関数定義自体は通常エラーを発生させないため、実際のコマンド実行が始まる前にset -e
が有効になっていれば十分です。これにより、スクリプトの初期化フェーズでの潜在的な問題を回避し、ビルドプロセスの堅牢性を高めます。
これらの変更により、make.bash
スクリプトはより構造化され、Go言語のビルドプロセスがより効率的かつ信頼性の高いものになりました。これは、Go言語が成熟していく過程で、ビルドシステムの基盤がどのように整備されていったかを示す良い例です。
関連リンク
- Go言語公式ウェブサイト: https://go.dev/
- Go言語の初期のコミット履歴 (GitHub): https://github.com/comemo/go/commits/master (このリポジトリはGoの公式リポジトリのミラーまたはフォークである可能性があります)
- Go言語の
io
パッケージのドキュメント: https://pkg.go.dev/io
参考にした情報源リンク
- Go言語のソースコード (GitHub): https://github.com/golang/go
- Bashスクリプトのドキュメントやチュートリアル (例: GNU Bash Manual, Shell Scripting Tutorial)
- Go言語の歴史に関する記事やブログポスト (初期のGoのビルドプロセスに関する情報)
- Go言語の
io
パッケージの設計に関する議論やドキュメント