前回 は過去25年間にリリースされたカーネルのサイズと日付を元に、Linuxの成長過程を概観してみました。最後のグラフで紹介したように、過去25年間の間、Linuxのサイズは順調に増大しているものの、その増加ペースは必ずしも一定ではなく、サイズが急増する時期とそうでない時期があるようです。今回から数回に渡って、それぞれの時期にどのような変更が行なわれてきたのかもう少し詳しく見ていくことにします。
前回のグラフはリリースされた日付やサイズが明確になっているlinux-1.0以降を対象にしました。しかし、Linuxの成長過程を考える場合、「 LinuxがLinuxになった時期 」を忘れるわけには行きません。そこで、まず最初にLinuxが公式版である1.0に到達するまでの過程を調べてみることにします。
linux-0.01とlinux-1.0
前回も紹介したように、最初に公開されたlinux-0.01 は総ファイル数が88、総行数は10239でした。一方、最初の公式版であるlinux-1.0 になると、総ファイル数が561、総行数は176250にまで増加しています。
linux-0.01はLinusさんが一人で自分の持っているハードウェアのみを対象に書きあげたバージョン、linux-1.0はその後2年半ほどの間に世界中の開発者から寄せられたコードを取りこんで、80386CPU用のUNIX(POSIX)用カーネルに必要な機能を整えたバージョンです。
両者の間にどれくらいの違いがあるかを見るために、まずはそれぞれのソースコードを展開したディレクトリでリストを取ってみました。
$ ls linux-0.01
Makefile boot/ fs/ include/ init/ kernel/ lib/ mm/ tools/
$ ls linux-1.0
CHANGES CREDITS Makefile boot/ drivers/ ibcs/ init/ kernel/ makever.sh* net/ zBoot/
COPYING Configure README config.in fs/ include/ ipc/ lib/ mm/ tools/
この結果を見ると、linux-0.01ではソースコードはboot、fs、include、init、kernel、lib、mm、toolsの8つ のディレクトリに収められているのに対し、linux-1.0ではdrivers、ibcs、ipc、net、zBootという5つのディレクトリが増えて13 のディレクトリに収められています。それぞれのディレクトリのサイズをduで調べてみたところ、以下のような結果になりました。なお、duで得られるディレクトリのサイズはファイルシステムの種類によって多少異なることがあり、以下の例はBtrfs上で取った結果です。
linux-0.01 linux-1.0
boot/ 16KB 44KB
drivers/ 2800KB
fs/ 108KB 1100KB
ibcs/ 8KB
include/ 4KB 780KB
init/ 4KB 16KB
ipc/ 56KB
kernel/ 116KB 208KB
lib/ 48KB 64KB
mm/ 16KB 92KB
net/ 496KB
tools/ 4KB 12KB
zBoot/ 80KB
計 464KB 5800KB
この結果を見ると、linux-0.01と1.0の間でもっとも差があるのは周辺機器用のドライバを収めたdrivers ディレクトリでしょう。ソースコードを眺めると、linux-0.01では周辺機器としてキーボードとVT102互換のコンソール、IDE HDDにしか対応していないので、それら用のコードはすべてkernelディレクトリに収められていました。
それに対し、linux-1.0ではdriversディレクトリ以下はFPU-emu、block、char、net、scsi、soundの6つのサブディレクトリに分かれ、HDDやFDDといったデータ記録用のブロックデバイスとコンソールやキーボード、マウスといったキャラクタデバイス、対応しているネットワークカードやSCSIカード、サウンドカード用のドライバがそれぞれのディレクトリに整理された結果、これだけの違いになったようです。
FPU-emuは「浮動小数点演算用プロセッサ・エミュレータ(Floating Point Unit Emulator) 」の意で、80386CPUでは外付けのオプションだった数値演算用コプロセッサ(80387)の機能をソフトウェア的に実現するためのコードを収めています。
また、ファイルシステム回りのコードも10倍近く 増えており、これも内容を見ると、linux-0.01ではMinix用のファイルシステムにしか対応していなかったのに対し、linux-1.0ではMinix FSに加えてLinux専用に開発されたext/ext2 FS、xiafs、相互運用用のmsdos、sysv(SystemV系UNIX用) 、hpfs(OS/2用) 、CD-ROM用のisofs、ネットワーク用のNFS、カーネルの内部情報を操作するためのproc FSが追加されています。
もうひとつ、TCP/IPネットワーク機能のコードを収めたnet ディレクトリが追加されたのも目を引きます。他の多くのUNIX系OSではBSDが開発したTCP/IP用のコードを流用しているのに対し、Linuxでは0からTCP/IP用のコードを再開発し、linux-1.0の時点ではNET2D(NET2 Debugged)と呼ばれる3世代目のコードが採用されています(NET→NET2→NET2D) 。
linux-0.01と1.0を比べると、良く言えばプロトタイプ、悪く言えば学生のおもちゃレベルだったカーネルが、まがりなりにもPOSIX互換OSのカーネル として使えるようになるためには、10倍以上のソースコードが必要だったことが見てとれます。
0.01と1.0の間
linux-0.01が公開されたのが1991年9月、最初の公式版である1.0が公開されたのは1994年3月で、linux-1.0の開発には約2年半 かかっています。この間に前節で紹介したようなソースコードのディレクトリ構成が変わる規模の変更が加えられたわけですが、その過程をもう少し詳しく見るために0.01と1.0の間で4つほどのバージョンを調べてみました。対象にしたのは1992年1月に公開されたlinux-0.12、1992年3月に公開された0.95、1993年3月の0.99.5、1994年2月の0.99.15です。
それぞれのバージョンのソースコードに含まれている各ディレクトリのサイズを前節同様の表にまとめてみると以下のようになりました。
linux-0.12(1992/01) linux-0.95(1992/03) linux-0.99.5(1993/03) linux-0.99.15(1994/02)
boot/ 28KB 28KB 36KB 44KB
drivers/ 2700KB
fs/ 128KB 152KB 585KB 1100KB
ibcs/ 8KB
include/ 172KB 184KB 436KB 768KB
init/ 16KB 8KB 12KB 16KB
ipc/ 56KB
kernel/ 280KB 308KB 1200KB 208KB
lib/ 56KB 56KB 60KB 64KB
mm/ 32KB 28KB 60KB 92KB
net/ 416KB 500KB
tools/ 8KB 8KB 16KB 12KB
zBoot/ 80KB
計 724KB 776KB 2800KB 5700KB
この結果を見ると、linux-0.95とlinux-0.99.5の間、日付けで言うと1992年3月から1993年3月の間の1年間 にかなり大きな変更が加えられているようです。
それぞれのディレクトリのサイズで見ると、0.99.5では0.95では対応していなかったTCP/IPネットワーク機能 が追加され(netディレクトリ) 、ファイルシステムもminix FSしか対応していなかった0.95に対して、0.99.5ではLinux用に開発された最初のファイルシステムであるext FS が追加されています。加えてDOS形式のメディアを読み書きするためのmsdos FS、CD-ROM用のisofs、リモートマウント用のNFSが追加され、fsディレクトリのサイズは4倍弱 に増加しています。
$ ls linux-0.95/fs
Makefile buffer.c exec.c file_table.c ioctl.c namei.c pipe.c select.c super.c
block_dev.c char_dev.c fcntl.c inode.c minix/ open.c read_write.c stat.c
$ ls linux-0.99.5/fs
Makefile buffer.c ext/ fifo.c filesystems.c ioctl.c locks.c msdos/ nfs/ pipe.c read_write.c stat.c
block_dev.c exec.c fcntl.c file_table.c inode.c isofs/ minix/ namei.c open.c proc/ select.c super.c
また、kernelディレクトリのサイズも4倍近く増加しており、0.95では対応していなかったSCSI HDD に対応し、主要なSCSIアダプタ用のドライバが追加されています。
$ ls linux-0.95/kernel/
Makefile blk_drv/ exit.c math/ panic.c ptrace.c signal.c sys_call.s vsprintf.c
asm.s chr_drv/ fork.c mktime.c printk.c sched.c sys.c traps.c
$ ls linux-0.95/kernel/blk_drv/
Makefile blk.h floppy.c hd.c ll_rw_blk.c ramdisk.c
$ ls linux-0.99.5/kernel/
FPU-emu/ blk_drv/ dma.c fork.c ioport.c itimer.c panic.c ptrace.c signal.c sys_call.S vsprintf.c
Makefile chr_drv/ exit.c info.c irq.c mktime.c printk.c sched.c sys.c traps.c
$ ls linux-0.99.5/kernel/blk_drv/
Makefile blk.h floppy.c genhd.c hd.c ll_rw_blk.c ramdisk.c scsi/
$ ls linux-0.99.5/kernel/blk_drv/scsi
Makefile aha1740.c fdomain.h scsi.c scsi_debug.h sd.c seagate.c sr.h st.h wd7000.c
aha1542.c aha1740.h hosts.c scsi.h scsi_ioctl.c sd.h seagate.h sr_ioctl.c ultrastor.c wd7000.h
aha1542.h fdomain.c hosts.h scsi_debug.c scsi_ioctl.h sd_ioctl.c sr.c st.c ultrastor.hls
キャラクタデバイスに関しても、当時は接続規格が複数あったマウスに対応すると共に、プリンタや仮想コンソール、サウンド機能にも対応しています。
$ ls linux-0.95/kernel/chr_drv/
Makefile console.c keyboard.S pty.c rs_io.s serial.c tty_io.c tty_ioctl.c
$ ls linux-0.99.5/kernel/chr_drv/
Makefile busmouse.c keyboard.c mem.c msbusmouse.c pty.c sound/ tty_ioctl.c vt_kern.h
atixlmouse.c console.c lp.c mouse.c psaux.c serial.c tty_io.c vt.c
もっとも、この段階ではサウンドカード用のドライバ類はカーネルのソースコードとは別配布になっていたようで、kernel/chr_drv/sound/以下にはドライバ用のスタブしかありませんでした。
$ ls linux-0.99.5/kernel/chr_drv/sound/
Makefile sound_stub.c
これら各種ドライバ類は0.99.5ではkernelディレクトリ中に収められていたものの、0.99.15になると独立したdriversディレクトリにまとめられ、カーネルの機能と周辺機器用ドライバの機能とが区別されるようになります。
linux-0.12から0.99.15までの各バージョンで、カーネルサイズに占める各ディレクトリの割合の変化を扇形グラフにまとめたのが図1 です。このグラフを見ると、0.99の世代の中でも周辺機器用ドライバの占める割合が急増しているのがわかります。
最初期のLinuxは「無いよりはあった方がまし」という方針で積極的に周辺機器用のドライバを追加していきました。その結果、対応している周辺機器が多いおかげでより多くの利用者が集まり、より多くの利用者がいるから開発にさらに拍車がかかる、というポジティブ・フィードバック・サイクルが成立しました。これがLinuxが成功した理由のひとつで、その特徴はこのグラフからも読み取れると思います。
図1 カーネルのソースコードで各ディレクトリが占める割合の変化
以上の表やグラフから見ると、Linusさんはlinux-0.01公開後の半年間ほど(0.95のころまで)は、Linuxをそれほど高機能化するつもりがなく、「 自分が使っているPC+αでコンソールが動けば十分」程度に考えていたようです。
しかしLinuxを支持するユーザが増え、彼らからのさまざまなフィードバックが集まってくるに連れ、当初の方針を変更してLinuxをPOSIX互換のきちんとしたカーネルにまで成長させようと決意しました。そして、1年近くかけて世界中の開発者と共にTCP/IPネットワークやSCSI機能、ウィンドウシステムを利用するために必須のマウス用ドライバなどを整備していき、0.99.xの世代でさらに1年かけてそれらを熟成させて最初の公式版である1.0を公開した、そのような歴史がlinux-1.0以前のソースコードから読み取れそうです。
0.99.xの世代は、まさに1.0をリリースするための「産みの苦しみ」の時期で、当初は0.99.1、0.99.2、0.99.3、と増えていったものの、0.99.12のころから数字だけでは足りなくなって0.99.12a、0.99.12b、0.99.12c、とアルファベットの識別子が付くようになりました。そして最終的には0.99.15jまでバージョンアップが続き、やっとlinux-1.0に辿りつくことになります。
Minixの作者であるA.Tanenbaum教授とLinusさんの"Linux is obsolete "な議論が行われたのがlinux-0.95を公開する直前の1992年1月末のことなので、この議論によってLinusさんがLinuxの存在意義を改めて認識し、より本格的なカーネルの開発へ舵を切った、と推測するのもあながち間違いでは無さそうです。
linux-1.0は、このような苦労を経て、PC互換機で動作するフリーなUNIX(POSIX)互換OSのカーネルとして世に出たものの、当時の商用UNIXと比べると見劣りする点や荒削りな点が多々ありました。次回は、そのような点を地道に改善していったlinux-1.xの世代を見てみようと思います。