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

[インデックス 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言語がまだ一般に公開される前の初期開発段階にありました。この時期のコードベースは急速に進化しており、ビルドシステムも同様に成熟途上にありました。

この変更の主な背景は以下の通りです。

  1. ビルドスクリプトの整理と可読性向上: src/lib/make.bash は、Go言語の標準ライブラリやツールをビルドするための主要なスクリプトでした。初期のスクリプトは、機能が追加されるにつれて肥大化し、重複するコードや複雑なロジックが含まれる傾向にありました。このコミットは、共通のビルドパターンを関数として抽出し、スクリプト全体の構造をより明確にすることで、可読性と保守性を向上させることを目的としています。
  2. io パッケージのビルド順序の最適化: コミットメッセージに明記されているように、「io をより早くする」という目的がありました。Go言語の io パッケージは、入出力操作の基本的なインターフェースと機能を提供し、多くの他の標準ライブラリパッケージ(例: bufio, net, os など)が io パッケージに依存しています。したがって、io パッケージが他の依存パッケージよりも先にビルドされることは、ビルドプロセスの整合性と効率性を確保するために重要でした。これは、依存関係の解決や、ビルドエラーの回避に寄与します。

前提知識の解説

このコミットの変更内容を理解するためには、以下の前提知識が役立ちます。

  1. 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 にインストールされるのが一般的なパターンでした。
  2. シェルスクリプト (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: カレントディレクトリを指定されたディレクトリに変更します。
  3. Go言語のパッケージ依存関係:
    • Go言語のパッケージは、他のパッケージの機能を利用するためにインポートします。このとき、インポートされる側のパッケージは、インポートする側のパッケージよりも先にコンパイルされ、利用可能になっている必要があります。
    • io パッケージは、Goの標準ライブラリの中でも非常に基本的なパッケージであり、Reader, Writer などのインターフェースを定義しています。これらのインターフェースは、ファイル操作、ネットワーク通信、バッファリングなど、Goの多くのI/O関連機能の基盤となっています。そのため、io パッケージは他の多くのパッケージから直接的または間接的に依存されています。

技術的詳細

このコミットの技術的な変更点は、主に src/lib/make.bash スクリプトの構造化とビルド順序の調整にあります。

  1. 関数の導入によるコードのモジュール化:
    • 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 ループとコンパイル/インストールコマンドが抽象化され、スクリプト全体の行数が削減され、意図が明確になりました。
  2. ビルド順序の再編成:
    • 変更前は、strings.gosyscall, 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 が早期にビルドされることで、後続の依存パッケージのビルドがスムーズに行われるようになります。
  3. 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言語のビルドプロセスをより堅牢で理解しやすいものにしています。

  1. buildfiles 関数の導入:
    • この関数は、単一のGoソースファイルをコンパイルする共通のパターンを抽象化します。以前は、strings.goflag.go など、個々のファイルをコンパイルする際に同じ rm -f *.6, for ループ, basename, echo 6g, 6g コマンドのシーケンスが繰り返されていました。
    • buildfiles を使うことで、これらの繰り返しが排除され、スクリプトがよりDRY (Don't Repeat Yourself) になりました。
    • buildfiles strings.go のように呼び出すことで、strings.go がコンパイルされることが明確になります。
  2. builddirs 関数の導入:
    • この関数は、Goのパッケージディレクトリ(例: syscall, os)に入り、その中で make install を実行し、元のディレクトリに戻るという共通のパターンを抽象化します。
    • 以前は、各パッケージディレクトリに対して echo, cd, make install, cd .. のシーケンスが繰り返されていました。
    • builddirs syscall math os reflect のように呼び出すことで、複数のディレクトリがまとめてビルドされることが一目でわかります。
  3. ビルド順序の変更と io.go の位置:
    • 最も重要な変更点の一つは、buildfiles io.go の呼び出しが、以前よりも早い段階に移動したことです。具体的には、strings.gosyscall, math, os, reflect のビルドの直後に配置されています。
    • これは、Goの io パッケージが、bufio, net, http など、後続の多くのパッケージの基本的な依存関係であることを考慮したものです。io パッケージが早期にビルドされることで、これらの依存パッケージが io の機能を利用できるようになり、ビルドの失敗を防ぎ、依存関係の解決を保証します。
  4. set -e の移動:
    • set -e が関数定義の後に移動したことで、スクリプトの実行フローがより明確になります。関数定義自体は通常エラーを発生させないため、実際のコマンド実行が始まる前に set -e が有効になっていれば十分です。これにより、スクリプトの初期化フェーズでの潜在的な問題を回避し、ビルドプロセスの堅牢性を高めます。

これらの変更により、make.bash スクリプトはより構造化され、Go言語のビルドプロセスがより効率的かつ信頼性の高いものになりました。これは、Go言語が成熟していく過程で、ビルドシステムの基盤がどのように整備されていったかを示す良い例です。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (GitHub): https://github.com/golang/go
  • Bashスクリプトのドキュメントやチュートリアル (例: GNU Bash Manual, Shell Scripting Tutorial)
  • Go言語の歴史に関する記事やブログポスト (初期のGoのビルドプロセスに関する情報)
  • Go言語の io パッケージの設計に関する議論やドキュメント