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

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

このコミットは、Goランタイムのソースコードのディレクトリ構造を整理し、特定のOSおよびアーキテクチャに依存するコードをより論理的なパスに移動させることを目的としています。具体的には、Darwin(macOS)およびLinux向けのamd64アーキテクチャ固有のコードが、それぞれ src/runtime/darwin/amd64/ および src/runtime/linux/amd64/ のような専用のサブディレクトリに移動されました。

さらに、このコミットの重要な変更点として、Goプログラムの初期起動処理を担う rt0(runtime zero)コードが、これまで個別の .6 ファイルとして扱われていたものから、runtime.a という単一のランタイムアーカイブライブラリに統合されました。これにより、ビルドプロセスが簡素化され、リンカ(6l)がランタイムコードをより効率的に扱えるようになりました。

コミット

commit 878822f355a4c1c690be1189f726a129dbf25878
Author: Russ Cox <rsc@golang.org>
Date:   Tue Mar 24 13:06:51 2009 -0700

    move darwin specific code into runtime/darwin/
    move darwin-amd64 specific code into runtime/darwin/amd64/
    repeat for linux.
    
    move rt0 into runtime.a instead of keeping a separate .6 file.
    6l seems to have no problem with that.
    
    TBR=r
    OCL=26680
    CL=26680

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

https://github.com/golang/go/commit/878822f355a4c1c690be1189f726a129dbf25878

元コミット内容

    move darwin specific code into runtime/darwin/
    move darwin-amd64 specific code into runtime/darwin/amd64/
    repeat for linux.
    
    move rt0 into runtime.a instead of keeping a separate .6 file.
    6l seems to have no problem with that.
    
    TBR=r
    OCL=26680
    CL=26680

変更の背景

このコミットの背景には、Goランタイムのコードベースの整理とビルドプロセスの効率化という二つの主要な目的があります。

  1. コードのモジュール化と整理: Goはクロスプラットフォームを強く意識して設計されており、ランタイムには様々なOSやアーキテクチャに特化したコードが含まれています。初期のGoのコードベースでは、これらのプラットフォーム固有のファイルが src/runtime ディレクトリ直下に散在していました。これにより、コードの可読性や保守性が低下し、特定のプラットフォームのコードを探すのが困難になるという問題がありました。このコミットは、これらのファイルを src/runtime/<OS>/ および src/runtime/<OS>/<ARCH>/ のような階層的なディレクトリ構造に移動することで、コードのモジュール化を進め、整理された状態を保つことを目指しました。

  2. ビルドプロセスの簡素化: rt0(runtime zero)は、Goプログラムが実行される際に最初に実行されるアセンブリコードであり、OSとのインターフェースや初期スタックの設定など、非常に低レベルな初期化を担当します。Goの初期のビルドシステムでは、この rt0rt0_amd64_darwin.6 のように個別のオブジェクトファイルとして扱われ、リンカによって特別に処理される必要がありました。このコミットは、rt0 を通常のランタイムライブラリ runtime.a に含めることで、ビルドスクリプト(Makefile)の複雑さを軽減し、リンカが他のランタイムコードと同様に rt0 を扱えるようにしました。これは、ビルドシステムの設計が成熟していく過程で、より統一的で効率的なアプローチが模索された結果と言えます。

これらの変更は、Go言語がまだ初期開発段階にあった2009年に行われたものであり、言語の基盤となるランタイムとビルドシステムの設計が固まっていく過程における重要なステップでした。

前提知識の解説

このコミットを理解するためには、以下のGo言語およびシステムプログラミングに関する前提知識が必要です。

  1. Goランタイム (Go Runtime): Goランタイムは、Goプログラムの実行を管理するC/アセンブリ言語で書かれたライブラリです。ガベージコレクション、スケジューラ(ゴルーチンの管理)、メモリ割り当て、システムコールインターフェースなど、Goの並行処理モデルとメモリ管理を支える中核的な機能を提供します。Goプログラムは、コンパイル時にこのランタイムとリンクされ、単一の実行可能ファイルを生成します。

  2. rt0 (Runtime Zero): rt0 は "runtime zero" の略で、Goプログラムが起動する際にOSによって最初に実行されるコードです。これは通常、アセンブリ言語で書かれており、非常に低レベルな初期化タスクを担当します。具体的には、以下のような処理を行います。

    • OSスレッドの初期化
    • 初期スタックのセットアップ
    • コマンドライン引数と環境変数の処理
    • Goランタイムの主要コンポーネント(ガベージコレクタ、スケジューラなど)の初期化
    • 最初のゴルーチン(g0)とマシン(m0)の作成
    • 最終的にGoの runtime.main 関数(そしてユーザーの main.main 関数)を呼び出すための準備 rt0 はOSとアーキテクチャに強く依存するため、プラットフォームごとに異なる実装が存在します。
  3. Goのビルドプロセス: Goのビルドプロセスは、主に以下のステップを含みます。

    • コンパイル: Goソースコード(.go)は、Goコンパイラ(例: 6g for amd64)によってオブジェクトファイル(.6)にコンパイルされます。
    • アセンブル: アセンブリ言語ソースコード(.s)は、Goアセンブラ(例: 6a for amd64)によってオブジェクトファイル(.6)にアセンブルされます。
    • アーカイブ: 複数のオブジェクトファイルは、Goアーカイバ(例: 6ar)によってライブラリファイル(.a)にまとめられます。Goランタイムは通常、runtime.a というアーカイブライブラリとして提供されます。
    • リンク: コンパイルされたオブジェクトファイルと必要なライブラリ(runtime.a など)は、Goリンカ(例: 6l for amd64)によって結合され、最終的な実行可能ファイルが生成されます。リンカは、プログラムのエントリポイント(この場合は rt0)から実行を開始できるように、コードとデータを配置します。
  4. Makefile: Makefile は、ソフトウェアのビルドプロセスを自動化するためのスクリプトファイルです。make コマンドによって解釈され、ソースファイルのコンパイル、リンク、ライブラリの作成などの手順を定義します。このコミットでは、ランタイムのビルド方法を変更するために src/runtime/Makefile が修正されています。

  5. OSとアーキテクチャの識別: Goのビルドシステムでは、GOOS(オペレーティングシステム、例: darwin, linux)と GOARCH(アーキテクチャ、例: amd64)という環境変数を使用して、ターゲットプラットフォームを識別します。これにより、異なるプラットフォーム向けのコードを条件付きでコンパイルしたり、適切なパスからファイルをインクルードしたりすることが可能になります。

技術的詳細

このコミットにおける技術的な変更点は多岐にわたりますが、主に以下の3つのカテゴリに分類できます。

  1. ディレクトリ構造の再編成: 最も顕著な変更は、Goランタイムのプラットフォーム固有のコードが新しい階層的なディレクトリ構造に移動されたことです。

    • 旧パス: src/runtime/amd64_darwin.h, src/runtime/rt0_amd64_darwin.s, src/runtime/signals_darwin.h など
    • 新パス: src/runtime/darwin/amd64/defs.h, src/runtime/darwin/amd64/rt0.s, src/runtime/darwin/signals.h など 同様の変更がLinux関連のファイルにも適用され、src/runtime/linux/amd64/ および src/runtime/linux/ ディレクトリが導入されました。 この変更により、特定のOSやアーキテクチャに関連するファイルがまとめて配置されるようになり、コードベースのモジュール性と保守性が向上しました。特に、defs.h は以前の amd64_darwin.h のようにOSとアーキテクチャをファイル名に含めるのではなく、ディレクトリ構造でその情報を表現するようになりました。
  2. rt0runtime.a への統合: 以前は、rt0rt0_$(GOARCH)_$(GOOS).$O のように個別のオブジェクトファイルとしてビルドされ、リンカによって特別に扱われていました。このコミットでは、src/cmd/6l/obj.c から rt0 を個別に読み込むロジックが削除されました。

    --- a/src/cmd/6l/obj.c
    +++ b/src/cmd/6l/obj.c
    @@ -353,12 +353,6 @@ main(int argc, char *argv[])
      	}
      	lookup(INITENTRY, 0)->type = SXREF;
     
    -	if(!debug['l']) {
    -		a = mal(strlen(goroot)+strlen(goarch)+strlen(goos)+20);
    -		sprint(a, "%s/lib/rt0_%s_%s.%c", goroot, goarch, goos, thechar);
    -		objfile(a);
    -	}
    -
      	while(*argv)
      		objfile(*argv++);
    

    代わりに、rt0.$Osrc/runtime/MakefileOFILES 変数に追加され、他のランタイムオブジェクトファイルと同様に runtime.a ライブラリにアーカイブされるようになりました。

    --- a/src/runtime/Makefile
    +++ b/src/runtime/Makefile
    @@ -2,19 +2,14 @@
     # Use of this source code is governed by a BSD-style
     # license that can be found in the LICENSE file.
     
    -CFLAGS=
    +CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF
     O=6
     CC=$(O)c
     AS=$(O)a
     
     LIB=lib_$(GOARCH)_$(GOOS).a
     
    -RT0OFILES=\
    -\trt0_$(GOARCH)_$(GOOS).$O\\\
    -
    -LIBOFILES=\
    -\trt1_$(GOARCH)_$(GOOS).$O\\\
    -\tsys_$(GOARCH)_$(GOOS).$O\\\
    +OFILES=\
     	array.$O\\\
     	asm.$O\\\
     	chan.$O\\\
    @@ -36,25 +31,24 @@ LIBOFILES=\\\
     	proc.$O\\\
     	rune.$O\\\
     	runtime.$O\\\
    +\trt0.$O\\\
    +\trt1.$O\\\
     	sema.$O\\\
     	sema_go.$O\\\
     	string.$O\\\
     	symtab.$O\\\
    +\tsys.$O\\\
     	traceback.$O\\\
     
    -OFILES=$(RT0OFILES) $(LIBOFILES)\n OS_H=$(GOARCH)_$(GOOS).h\n HFILES=runtime.h hashmap.h malloc.h $(OS_H_)\n \n-install: rt0 $(LIB) runtime.acid\n-\tcp $(RT0OFILES) $(GOROOT)/lib\n+install: $(LIB) runtime.acid\n \tcp $(LIB) $(GOROOT)/lib\n \tcp runtime.acid $(GOROOT)/acid/runtime.acid\n \n-rt0:\t$(RT0OFILES)\n-\n-$(LIB): $(LIBOFILES)\n-\t$(O)ar rc $(LIB) $(LIBOFILES)\n+$(LIB): $(OFILES)\n+\t$(O)ar rc $(LIB) $(OFILES)\n     ```
    これにより、リンカは `runtime.a` を読み込むだけで `rt0` を含むすべてのランタイムコードを自動的に解決できるようになり、ビルドスクリプトが簡素化されました。
    
    
  3. Makefileの変更とコンパイルフラグの調整: src/runtime/Makefile では、新しいディレクトリ構造に対応するために、コンパイル時のインクルードパスが調整されました。

    --- a/src/runtime/Makefile
    +++ b/src/runtime/Makefile
    @@ -2,19 +2,14 @@
     # Use of this source code is governed by a BSD-style
     # license that can be found in the LICENSE file.\n \n-CFLAGS=\n+CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF
    

    CFLAGS-I$(GOOS)-I$(GOOS)/$(GOARCH) が追加され、コンパイラが新しいOS/アーキテクチャ固有のヘッダーファイル(例: defs.h, signals.h)を正しく見つけられるようになりました。 また、ソースファイルのコンパイルルールも更新され、新しいパスからのコンパイルをサポートしています。

    --- a/src/runtime/Makefile
    +++ b/src/runtime/Makefile
    @@ -65,17 +59,23 @@ clean:\n \trm -f *.$(O) *.a runtime.acid cgo2c\n \n %.$O:\t%.c\n-\t$(CC) $(CFLAGS) -wF $<\n+\t$(CC) $(CFLAGS) $<\n \n %.$O:\t$(GOARCH)/%.c\n-\t$(CC) $(CFLAGS) -wF $<\n+\t$(CC) $(CFLAGS) $<\n \n-%.$O:\t%.s\n-\t$(AS) $<\n+%.$O:\t$(GOOS)/%.c\n+\t$(CC) $(CFLAGS) $<\n+\n+%.$O:\t$(GOOS)/$(GOARCH)/%.c\n+\t$(CC) $(CFLAGS) $<\n \n %.$O:\t$(GOARCH)/%.s\n \t$(AS) $<\n \n+%.$O:\t$(GOOS)/$(GOARCH)/%.s\n+\t$(AS) $<\n     ```
    これにより、`$(GOOS)/%.c` や `$(GOOS)/$(GOARCH)/%.c` のようなパスにあるCソースファイルやアセンブリソースファイルが適切にコンパイル・アセンブルされるようになりました。
    
    

これらの変更は、Goランタイムのビルドシステムとコード構造をより堅牢でスケーラブルなものにするための初期段階の改善であり、後のGoの発展の基盤となりました。

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

このコミットで変更された主要なファイルと、その変更の概要は以下の通りです。

  • src/cmd/6l/obj.c:

    • rt0 を個別のオブジェクトファイルとして読み込むためのハードコードされたパスとロジックが削除されました。これにより、リンカは rt0runtime.a の一部として扱うようになります。
  • src/runtime/Makefile:

    • CFLAGS-I$(GOOS)-I$(GOOS)/$(GOARCH) が追加され、新しいディレクトリ構造のヘッダーファイルをインクルードできるようになりました。
    • RT0OFILES および LIBOFILES 変数が削除され、OFILES 変数に rt0.$O, rt1.$O, sys.$O が直接追加されました。これにより、rt0runtime.a に含まれるようになりました。
    • install ターゲットから rt0 のコピーが削除され、$(LIB)runtime.a)のみがコピーされるようになりました。
    • rt0 を個別にビルドするルールが削除され、$(LIB) のビルドルールが $(OFILES) 全体を対象とするように変更されました。
    • 新しいディレクトリ構造($(GOOS)/%.c, $(GOOS)/$(GOARCH)/%.c, $(GOOS)/$(GOARCH)/%.s)からのCソースファイルおよびアセンブリソースファイルのコンパイル・アセンブルルールが追加されました。
  • ファイルのリネームと移動: 以下のファイルが、より整理されたディレクトリ構造に移動・リネームされました。

    • src/runtime/amd64_darwin.h -> src/runtime/darwin/amd64/defs.h
    • src/runtime/rt0_amd64_darwin.s -> src/runtime/darwin/amd64/rt0.s
    • src/runtime/rt1_amd64_darwin.c -> src/runtime/darwin/amd64/rt1.c
    • src/runtime/sys_amd64_darwin.s -> src/runtime/darwin/amd64/sys.s
    • src/runtime/signals_darwin.h -> src/runtime/darwin/signals.h
    • src/runtime/amd64_linux.h -> src/runtime/linux/amd64/defs.h
    • src/runtime/rt0_amd64_linux.s -> src/runtime/linux/amd64/rt0.s
    • src/runtime/rt1_amd64_linux.c -> src/runtime/linux/amd64/rt1.c
    • src/runtime/sys_amd64_linux.s -> src/runtime/linux/amd64/sys.s
    • src/runtime/signals_linux.h -> src/runtime/linux/signals.h
  • src/runtime/darwin/amd64/rt1.c:

    • インクルードパスが変更され、"amd64_darwin.h""signals_darwin.h" がそれぞれ "defs.h""signals.h" に変更されました。これは、新しいディレクトリ構造とファイル命名規則に対応するためです。

コアとなるコードの解説

src/cmd/6l/obj.c の変更

このファイルはGoリンカ 6l の一部です。変更前は、リンカが rt0 を特定のパスから明示的に読み込むロジックを持っていました。これは、rt0 がGoプログラムのエントリポイントであり、他のランタイムコードとは異なる特別な扱いが必要だったためです。しかし、このアプローチはビルドシステムに rt0 のパスをハードコードすることになり、柔軟性に欠けていました。

変更後、この明示的な読み込みロジックが削除されました。これは、rt0 が通常のランタイムライブラリ runtime.a の一部として提供されるようになったため、リンカが他のオブジェクトファイルと同様に rt0 を解決できるようになったことを意味します。これにより、リンカのコードが簡素化され、rt0 の管理がビルドシステム(Makefile)に一元化されました。

src/runtime/Makefile の変更

Makefile の変更は、このコミットのビルドシステム側の核心です。

  • CFLAGS の変更: CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF この変更は、新しいディレクトリ構造に対応するために不可欠です。-I フラグはCコンパイラにインクルードパスを追加します。以前は src/runtime ディレクトリ直下にあったヘッダーファイル(例: amd64_darwin.h)が、src/runtime/darwin/amd64/defs.h のようにサブディレクトリに移動したため、コンパイラがこれらの新しい場所にあるヘッダーファイルを見つけられるように、$(GOOS)(例: darwin)と $(GOOS)/$(GOARCH)(例: darwin/amd64)をインクルードパスに追加しています。これにより、Cソースファイル内で #include "defs.h" のように記述しても、正しいヘッダーファイルが参照されるようになります。

  • OFILES 変数の再定義と rt0 の統合: 変更前は RT0OFILESLIBOFILES という変数が存在し、rt0 が他のランタイムオブジェクトファイルとは別に扱われていました。 変更後、これらの変数は廃止され、OFILES という単一の変数にすべてのランタイムオブジェクトファイル(array.$O, asm.$O, chan.$O, ..., rt0.$O, rt1.$O, sys.$O, ...)がリストされるようになりました。 そして、$(LIB): $(OFILES) というルールにより、runtime.a ライブラリがこれらのすべてのオブジェクトファイルから作成されるようになりました。これは、rt0 が他のランタイムコードと同様に runtime.a にアーカイブされることを意味します。これにより、ビルドプロセスが統一され、rt0 の特別な扱いが不要になりました。

  • インストールルールの簡素化: install ターゲットから rt0 の個別のコピーが削除されました。これは、rt0runtime.a に含まれるようになったため、runtime.a をコピーするだけで十分になったためです。

  • 新しいコンパイルルールの追加: %.$O: $(GOOS)/%.c%.$O: $(GOOS)/$(GOARCH)/%.c などの新しいルールが追加されました。これらは、新しいディレクトリ構造に配置されたCソースファイルやアセンブリソースファイル(例: src/runtime/darwin/amd64/rt0.s)を適切にコンパイル・アセンブルするためのものです。make はこれらのルールを使用して、対応するオブジェクトファイルを生成します。

ファイルのリネームと内容の変更

多くのファイルがリネームされ、src/runtime/<OS>/ および src/runtime/<OS>/<ARCH>/ の形式に移動されました。例えば、src/runtime/amd64_darwin.hsrc/runtime/darwin/amd64/defs.h になりました。このリネームは、ファイル名からOSとアーキテクチャの情報を削除し、その情報をディレクトリ構造に委ねるという設計思想の変更を反映しています。これにより、ファイル名が短くなり、ディレクトリ構造を見るだけでどのプラットフォームのコードかが一目でわかるようになりました。

また、src/runtime/darwin/amd64/rt1.c のように、移動されたCソースファイル内では、インクルードするヘッダーファイルのパスが新しい命名規則に合わせて変更されています。

#include "runtime.h"
#include "defs.h" // 以前は "amd64_darwin.h"
#include "signals.h" // 以前は "signals_darwin.h"

これは、新しいディレクトリ構造とファイル命名規則に合わせた内部的な整合性を保つための変更です。

これらの変更は、Goランタイムのコードベースをより整理し、将来の拡張やメンテナンスを容易にするための基盤を築きました。特に、rt0 の統合は、Goのビルドシステムがより洗練され、効率的になる方向性を示しています。

関連リンク

参考にした情報源リンク