ブートストラップ問題とは
ブートストラップ問題(Bootstrap problem)は、コンピュータ科学、特に
プログラミング言語の処理系開発において発生する、「鶏と卵」にも例えられる再帰的な依存関係の問題を指します。最も典型的なのは、
コンパイラを、その
コンパイラ自身が処理対象とする
プログラミング言語で記述した場合に直面する困難です。
例えば、新しい
プログラミング言語Xを開発し、その言語Xで書かれた
コンパイラを作成したとします。この言語Xの
コンパイラを実行するためには、当然ながら言語Xの
コンパイラが必要です。しかし、その
コンパイラ自体が言語Xで書かれているため、最初にそのソースコードを機械が理解できる形式に変換する(コンパイルする)には、別の言語Xの
コンパイラが必要になる、という状況に陥ります。
このような、自身で自身を処理する環境(セルフホスティング環境)の最初の起動や構築に関する問題を、ブートストラップ問題と呼びます。そして、この困難を乗り越え、何とかして最初の完全に機能する環境、特に最初の
コンパイラや
インタプリタを構築するプロセス全体を「ブートストラッピング」と呼びます。
名称については、靴紐(bootstraps)を持って自身を持ち上げるという、物理的には不可能な行為に由来するとされており、自力で環境を立ち上げる困難さを比喩的に表現しています。
ブートストラッピングの主な手法
自身で自身をコンパイルする必要があるようなブートストラップ問題を解決するために、いくつかの確立された手法が存在します。以下にその主なものを挙げます。
別の言語で最初の処理系を作成する:
目的とする言語Xの
コンパイラや
インタプリタのごく基本的なバージョンを、既に利用可能な別の言語(例えば、FORTRAN、C、アセンブリ言語など)で記述します。ニクラウス・ヴィルトが最初の
PascalコンパイラをFORTRANで書いたのはこの手法の典型例です。この最初の処理系を用いて、言語Xで書かれた本格的な
コンパイラのソースコードをコンパイルします。
既存の処理系を利用する:
目的とする言語Xの
インタプリタや
コンパイラが、たとえ別の言語で書かれたものであっても、既にどこかに存在する場合は、それを利用して言語Xで書かれた
コンパイラ自身をコンパイルできます。これは
Schemeなどの言語処理系でしばしば用いられるアプローチです。
言語のサブセットを利用する:
まずは、目的の言語Xの機能の小さな部分(サブセット)のみを扱える
コンパイラを作成します。このサブセット
コンパイラは、既存の別の言語で書くか、ハンドコンパイルなどの手法で作成します。次に、このサブセット
コンパイラを使って、言語X全体の機能を備えた
コンパイラ自身を、言語Xのサブセットの範囲で記述・コンパイルしていきます。例えば、
Javaの拡張言語や初期の
Free Pascal、一部の
Haskellコンパイラなどで採用された方法です。
クロスコンパイルを利用する:
言語Xの
コンパイラが既に利用可能な環境(ホスト環境)で、開発対象の異なる環境(ターゲット環境)向けの実行コードを生成する言語Xの
コンパイラ、すなわち
クロスコンパイラを構築します。ホスト環境でこの
クロスコンパイラをコンパイルし、次にこの
クロスコンパイラを用いて、ターゲット環境で動作する言語Xの
コンパイラ自身のソースコードをコンパイルします。これにより、ターゲット環境用の
コンパイラが得られます。新しいアーキテクチャに
C言語コンパイラを移植する際によく用いられる手法です。
インタプリタ上でコンパイルを実行する:
目的とする言語Xのソースコードを直接実行できる
インタプリタが存在する場合、その
インタプリタ上で、言語Xで書かれた
コンパイラのソースコードを実行し、コンパイル処理を行わせることができます。UCSD
PascalのP-Codeベースのシステムにおけるトランク
コンパイラ(特定の機能がコメント化されている基本的な
コンパイラ)を、
インタプリタ上で動作させて利用するケースなどがこれに該当します。
ハンドコンパイル:
極めて原始的な方法ですが、言語Xで書かれた
コンパイラのソースコードを、開発者自身が手作業で解釈し、ターゲットとなる機械語や中間コードに変換していく手法です。
ドナルド・クヌースが
文芸的プログラミングシステムWEBの開発初期に用いたことで知られています。
*
移植用バイナリの提供:
コンパイラをソースコードとして配布する際に、移植が比較的容易な中間形式(
バイトコードなど)で表現された
コンパイラ自身の実行可能形式を同時に配布する方法です。これにより、利用者はまずこの中間形式の
コンパイラを実行し、その上で本格的なネイティブコード
コンパイラを自身の手元の環境でビルドできます。
OCamlなどがこの方式を採用しています(
OCamlはネイティブコード
コンパイラのソースと
バイトコード版を配布しています)。
歴史と現代
ブートストラッピングが行われた最初の著名な実装の一つは、
ALGOLの方言であるNELIACでした。商用
ソフトウェアとしては、初期の
PL/I|PL_Iの実装がブートストラップ手法を用いた例として挙げられます。
現代の言語処理系、特に
C言語のように低レベルなシステム記述に適した言語では、処理系自体がその言語自身で書かれていることが一般的です。そのため、全く新しい環境でゼロから開発を行う際には、ブートストラッピングが必要になる場合があります。しかし、多くの場合、既にあるプラットフォームのバイナリディストリビューションを利用したり、より開発が進んだ環境でクロスコンパイルを行ったりすることで、ブートストラップの複雑なプロセスを回避することが可能です。
現代の有名な例としては、前述の
OCamlや、
Haskellで書かれているGlasgow
Haskell Compiler (GHC) があります。GHCは、ブートストラッピングのために、中間言語として
C言語コードを生成するオプションを利用し、既存のC
コンパイラでコンパイル可能なブートストラップ用コードを提供しています。
言語処理系の開発に関連して、
パーサジェネレータのように、プログラムを生成するプログラム自体を開発する場合にも、似たような再帰的な依存関係の問題が生じることがあります。