わかるUNIXの歴史第 0 回 / 序 ── 鶏と卵

物理シリーズの計算機版 ── 今度は“ソフトの起源”を、一段ずつ降りていく

鶏と卵 ── Linuxは、何がコンパイルしたのか Linuxカーネルは、Linux上の gcc(や clang)でコンパイルする。ではその gcc は? ── 前の gcc がコンパイルした。ではその前は? この「回り続ける輪」は、いったいどこから始まったのか。

必要な道具:好奇心だけ(コードは読めなくてよい) 合言葉:最初の卵は、手で彫った

あなたが Linux カーネルをビルドするとき、gcc という C コンパイラを使います。その gcc 自身も C で書かれたプログラムなので、動かすには誰かがコンパイルした gccが必要です。では、その gcc をコンパイルしたのは? ── また gcc。じゃあいちばん最初の gcc は、コンパイラがまだ1つも無い世界で、何が作ったのか。これはニワトリとタマゴの問題です。このシリーズは、この輪を時間の逆向きにたどって、C言語の誕生、初代UNIX、そして“最初の1バイト”まで降りていきます。

00まず、輪を目で見る

「コンパイラをコンパイルする」は、こう書くと目が回ります。

$ gcc -o vmlinux linux.c # Linux を gcc がビルド $ gcc -o gcc gcc.c # その gcc は? → 前の gcc がビルド $ gcc -o gcc gcc.c # その前の gcc は? → もっと前の gcc が… …延々と、前の自分にさかのぼる(自己ホスティング)

現役のコンパイラは、たいてい自分自身の言語で書かれ過去の自分がビルドしたものです。これを自己ホスティング(self-hosting)と呼びます。新しい gcc は古い gcc が作り、その古い gcc はもっと古い gcc が作り…と、輪がぐるぐる回り続けている。下の図で、その輪を回してみてください。

図1:自己ホスティングの輪。各世代のコンパイラは、1つ前の世代がビルドした。輪は回り続けるが ── いちばん最初の1個は、この輪の中では作れない
各コンパイラは「1つ前の自分」がビルドした。では最初の1つは?
今回の急所 ── 輪は、外から一度だけ持ち上げられた

自己ホスティングの輪は、それ自身では始められない。「前の自分」が要るのに、最初は「前の自分」が居ないからです。だから輪は必ず、輪の外にある何かによって一度だけ着火される。bootstrap(ブートストラップ)という言葉は、もともと「自分の靴ひもを引っぱって自分を持ち上げる」という物理的に不可能なほら話から来ています。ソフトの世界でも、最初の一回だけは“外の手”が持ち上げた。

01輪は、いつから回っていたのか ── 最初のLinux(1991)

時間を巻き戻します。今の Linux は Linux 上でビルドできますが、1991年の最初の Linux は、まだ Linux が無いので Linux 上ではビルドできません。ではどこで? ── 答えは MINIX という別の Unix風OSの上です。当時フィンランドの学生だった Linus Torvalds は、MINIX を積んだ386 PCで開発し、GNUの gccbash を MINIX に移植して、その gcc で Linux をコンパイルしました。

最初のLinuxの“産室”

v0.01(1991年9月)

単体では起動すらできず、MINIX が無いとコンパイルもテストもできなかった。輪はまだ回っていない ── MINIX という別のOSにおんぶしている状態。

v0.11(1991年12月)

ここで初めて Linux が Linux 自身をコンパイルできた(自己ホスティング達成)。輪が回り始めた瞬間。以後およそ30年以上、その輪はずっと回り続けている。

つまり Linux の輪の“着火”は、MINIX の上の gcc でした。では次の問いは自明です ── その gcc は何が作った? MINIX は何が作った? 輪の外に出ても、また別の「何が作った?」が待っている。この問いを繰り返すのが、このシリーズの背骨です。

つなぐ声 ── clang じゃないの? 今の Linux は clang(LLVM)でもビルドできますが、それは2010年代後半にようやく主流化した後発で、歴史のほぼ全部は gcc の物語です。そして clang 自身も C++ で書かれたプログラムで、やはり別のコンパイラがビルドした自己ホスティングの輪の中にいます。道具が gccclang かは、鶏と卵の構造を何も変えません。
◇ ◇ ◇

02これから降りる階段の、全体像

「何が作った?」を繰り返すと、下へ下へと階段を降りていきます。この階段こそ、このシリーズの目次そのものです。下の図のスライダーを動かして、時代をさかのぼり、各段で「何が、何を作ったのか」を確かめてください。降り切った底に、鶏と卵の答えがあります。

図2:さかのぼりの階段。スライダーを右へ動かすほど過去へ降りる。各段は「その時代のソフトを、何が作ったか」。底(第10回)に、輪を着火した“外の手”がある
階段の降り方(このシリーズの順路)

今の輪(gcc/clang)→ 最初のLinux(1991)はMINIX上のgcc → gccは既存のccで着火 → MINIXはACK → 最初のCコンパイラはBから育てて自己ホスティング → BはBCPLの子 → 最初のUnix(1969)はPDP-7アセンブリ → そのアセンブラは別マシンのクロスアセンブラ+紙テープ → その最初は人間がスイッチで手入力 → 底は配線されたハードウェア

03二種類の「さかのぼり」を、混ぜない

先回りして、初学者が必ずハマる罠を1つだけ潰しておきます。「Linux は MINIX から来て、MINIX は BSD から来て…」という系譜(血統)の話と、いま見てきた何がコンパイルしたかの話は、別物です。

直交する二つの問い

① コードの血統:実際のソースコードを受け継いだか。
Unix → BSD → NetBSD/FreeBSD… のように遺伝子(コード)が流れる系統樹。

② ツールチェーンのブートストラップ:何が何をコンパイルしたか。
このシリーズが追う、鶏と卵の輪。Linux も MINIX も、実は誰かの血を引いた子ではなく、“Unixらしく振る舞う”白紙からの再実装です(だから①の血統には載らない)。この腑分けは第1回で。

この2つを混ぜると「Linux は MINIX の子だ」といった誤解になります。正しくは、Linux は MINIX という産室(開発環境)を借りて育っただけで、血のつながりは無い。この気持ちよい種明かしは、次回いちばん最初にやります。

正直な線 ── 「手で彫った」は、比喩と事実の中間

このシリーズの合言葉「最初の卵は、手で彫った」は、詩的な比喩に聞こえますが、底の段ではほぼ文字通りの事実です(第9回)。初期の計算機では、人間が命令表を見て機械語の数値を手で作り、トグルスイッチで1語ずつメモリに入れました。一方で「Linux は MINIX の上の gcc がコンパイルした」のような各段の主張は、年号・人物まで出典の取れる史実です。この2種類 ── 検証できる史実と、理解のための言い回し ── を、各話の脚注できちんと分けて示します。

また、v0.01 と v0.11 の線引き(どこから「自己ホスティング」と呼ぶか)や、「gcc か clang か」のように、雑に言うと角が立つ点は、その都度ていねいに区別します。

練習問題(今回の話だけで解けます)
  1. 「自己ホスティング」とは何か。一文で。
    答えを見る
    コンパイラ(などのツール)が、自分自身の言語で書かれ、過去の自分でビルドされている状態。新しい版は古い版が作る。
  2. 自己ホスティングの輪は、なぜ「それ自身では始められない」のか。
    答えを見る
    動かすには「前の自分」が要るのに、いちばん最初には「前の自分」が存在しないから。だから輪の外にある何か(別のコンパイラ/別のOS/最後は人間の手)が一度だけ着火する必要がある。
  3. 最初の Linux(v0.01) は、何の上の何でコンパイルされたか。
    答えを見る
    MINIX というUnix風OSの上に移植された gcc。Linux が Linux 自身をビルドできる(自己ホスティング)ようになるのは v0.11 から。
  4. 「Linux は MINIX の子だ」という言い方の、どこが不正確か。
    答えを見る
    コードの血統(遺伝子)と、開発環境(産室)を混同している。Linux は MINIX 上で開発され影響も受けたが、MINIX のソースコードは受け継いでいない。両者とも「Unix風の白紙からの再実装」。

まとめ輪は回り続け、最初の一回だけ外から着火された

Linux をコンパイルする gcc は、前の gcc が作った ── コンパイラは自分自身の言語で書かれ、過去の自分がビルドする自己ホスティングの輪の中にいる。だが輪は自力では始まらない。最初は「前の自分」が居ないからだ。Linux の輪は、1991年に MINIX 上の gcc によって着火され(v0.01)、v0.11 で自立した。

「何が作った?」を繰り返すと、gcc → 既存cc → C → B → BCPL → アセンブリ → クロスアセンブラ → 手入力 → ハードウェア、と階段を降りていく。底にあるのは、輪の外から一度だけ持ち上げた人間の手と、配線された機械。それがこのシリーズの答えの形だ ── 最初の卵は、手で彫った。 なお「何がコンパイルしたか(ブートストラップ)」と「誰の遺伝子か(血統)」は別問題で、混ぜないこと。次回はまずその腑分けから。

この文書は「わかるUNIXの歴史」シリーズ第0回(序)です。史実:Linux はフィンランドの学生 Linus Torvalds が1991年に開発を開始し、初期バージョン(v0.01)は MINIX 上でしかコンパイル・テストできず、Torvalds は gcc(1.40) と bash(1.08) を移植した。Linux が自分自身をコンパイルできる(自己ホスティング)ようになったのは v0.11(1991年12月)とされる。clang/LLVM による Linux カーネルのビルドは2010年代後半に主流化した後発の選択肢で、歴史的な標準コンパイラは gcc。「自己ホスティング」「ブートストラップ(bootstrap=自分の靴ひもで自分を持ち上げる、の含意)」は計算機科学の標準用語。コードの血統(BSD 系など実コードの継承)と、Unix風の白紙再実装(MINIX・Linux・GNU)は別系統で、本シリーズ第1回で詳述する。「手で彫った」等の表現は理解のための言い回しだが、初期計算機での手作業によるブートストラップ(ハンドアセンブル・スイッチ入力)は事実に基づく(第9回)。 ── 印刷する場合はブラウザの「印刷」から「PDF に保存」を(印刷版ではスライダーとアニメ・解答は静止/非表示になります)。

印刷 / PDF 化:⌘+P(Windows は Ctrl+P)。画面では図1の「▶ 輪を回す」で自己ホスティングを回し、図2のスライダーで時代をさかのぼれます。「答えを見る」で解答が開きます。