Toolchain 技術情報

この節では、全体的な構築方法の背景となっている論理的根拠と、技術的な詳細のいくつかを説明しようと考えています。 ここですべてをすぐに理解しなければならないというわけではありません。 それらの大半は、一度実際に構築を行なえば理解できるでしょう。いつでもここを参照しに戻って来て下さい。

第 5 章の目的は、chroot で入れる健全で暫定的な環境を提供することです。 そうすれば、そのような環境はクリーンですから、第 6 章で目的の LFS システムについて問題を起こさない構築を行えます。 これを行なう上で、可能な限りホストシステムから分離しようとし、必要なものが揃っていて独立で動かせる toolchain を構築します。 構築の過程が、新しい読者にとって危険が最小限になると同時に、最大限の教育的価値を持つように考えられてきたということを記しておくべきですね。 言いかえると、より進んだ技術がシステムを構築するのに使われたということです。

Important: 先に行く前に、しばしば target triplet (ターゲットを示す三語)と言われるプラットフォームの名称を確認しておいたほうがよいでしょう。 一般的に、この「target triplet」とは、たとえば i686-pc-linux-gnu のようなものです。 お使いの「target triplet」を確定する簡単な方法は、多くのパッケージと一緒になっている config.guess スクリプトを実行することでしょう。 Binutils のソースを解凍し、スクリプト ./config.guess を実行してその結果をメモしておきましょう。

また、動的ローダーとして言及されるプラットフォームの動的リンカの名前も、Binutils の一部であるスタンダードリンカ ld と混同しないために確認しておかなければいけません。 動的リンカは Glibc によって提供され、プログラムによって必要とされる共有ライブラリを探してロードするという仕事をし、プログラムが走るように準備してから実行します。 大半の人にとっては動的リンカの名前は ld-linux.so.2 となるでしょう。 あまり普及していないプラットフォームでは、その名前は ld.so.1 か、もしくは新しい 64 ビットのプラットフォームでは全く異なったものになるかもしれません。 ホストシステムの /lib ディレクトリの中を調べて、お使いのプラットフォームの動的リンカの名前を確認しておくべきです。 絶対に確実な方法は、ホストシステムから適当にバイナリを選んで、'readelf -l <バイナリの名前> | grep interpreter' を実行してその結果を見ることです。 すべてのプラットフォームを含む信頼できる参考事項は Glibc ソースツリーのルートにある shlib-バージョン のファイルの中です。

第 5 章の構築方法がどのように行なわれるかについて、いくつかの技術的要点

Binutils は最初にインストールされます。 なぜなら、アセンブラとリンカそれぞれのどの機能を有効にするか、無効にするかを決定するために ./configure を実行している間、GCC と Glibc は共に様々な機能のテストを行なうからです。 これは人が最初に気がつくよりもより重要なことです。 不正確に設定されてしまった GCC と Glibc は、微妙に壊れた toolchain になり、そのような破損の影響はディストリビューション全体の構築が終りに近づくまであらわれないかもしれません。 ありがたいことに、通常は時間を浪費する前に(破損箇所があれば)テストスイートの失敗が警告してくれます。

Binutils はそのアセンブラとリンカを、/tools/bin/tools/$TARGET_TRIPLET/bin の 2 ヶ所にインストールします。実際には、一つの場所のツールはもう一つへのハードリンクになっています。 リンカの重要な一面は、そのライブラリ検索の規則です。詳細な情報は ld--verbose フラグを渡すことで得られます。 たとえば 'ld --verbose | grep SERCH' と実行すれば、現在の検索パスとその規則を表示します。 --verbose スイッチを渡してダミープログラムをコンパイルすることで、どのファイルが実際に ld によってリンクされるかを知ることができます。 たとえばえば 'gcc dummy.c -Wl, --verbose 2>&1 | grep succeeded' と実行すればリンクの間に開くことに成功したファイルを表示します。

次にインストールされるパッケージは GCC で、その ./configure を実行すると、たとえば次のようなメッセージがあります。

checking what assembler to use... /tools/i686-pc-linux-gnu/bin/as
checking what linker to use... /tools/i686-pc-linux-gnu/bin/ld

これは上述した理由で重要です。これはまた、GCC の設定スクリプトはどのツールを使うかを探すために $PATH ディレクトリを検索しないことも示しています。 しかし、gcc 自身の実際の操作の間、その同じ検索パスは必ずしも使われません。 gcc がどのスタンダードリンカを使うかは 'gcc -print-prog-name=ld' を実行してみれば分るでしょう。 詳細な情報は gcc-v フラグを渡してダミープログラムをコンパイルすれば得られます。 たとえば 'gcc -v dummy.c' を実行すれば、gcc のインクルードの検索パスとその規則を含んだ、プリプロセッサとコンパイル、アセンブルの段階についての詳細な情報を表示します。

次にインストールされるパッケージは Glibc です。Glibc を構築する上でもっとも重要な考慮すべきことは、コンパイラとバイナリツール、カーネルヘッダーです。 コンパイラは、一般的には Glibc がいつも $PATH ディレクトリにみつける gcc を使うので問題ありません。 バイナリツールとカーネルヘッダーはそれよりもすこし厄介です。ですから、危険がないように、正しい選択をするように利用できる設定スイッチを使います。 ./configure の実行のあとで、重要な細かい点すべてについて glibc-build ディレクトリにある config.make ファイルの内容をチェックできます。 どのバイナリツールを使用するかを管理するための CC="gcc -B/tools/bin" の使用といったようなものや、コンパイラのインクルード検索パスを管理するための -nostdinc-isystem フラグの使用といった興味深い項目をメモしておきましょう。 これらの項目は Glibc パッケージの重要な面を強調するのに役立ちます。 このパッケージは、構築の手続きの点で非常に独立性が高く、一般的には toolchain のデフォルトを当てにしません。

Glibc のインストール後、検索とリンクが /tools プリフィックスの中だけで行なわれるようにいくつかの調整をします。 検索パスを /tools/lib だけに強く限るように調整した ld をインストールします。 それから gcc のスペックファイルを /tools/lib の中の新しい動的リンカを指すように修正します。 この最後のステップはプロセス全体の中で非常に重要です。上述のように、動的リンカヘの強いパスの制限は実行ファイルで共有するすべての ELF に組み込まれます。 'readelf -l <バイナリの名前> | grep interpreter' を実行することでこれを検査することが出来ます。 gcc のスペックファイルを修正することで、第 5 章の最期までここでコンパイルされたすべてのプログラムが /tools/lib にある新しい動的リンカを使うことを確実にしています。

新しい動的リンカを使う必要性はまた、GCC の第 2 段階でスペックファイルのパッチをあてるためです。 これに失敗すると、ホストシステムの /lib ディレクトリにある動的リンカの名前を GCC プログラムがそれ自身の中に組み込んだ状態となり、ホストから離しておくという目的を駄目にしてしまいます。

Binutils の第 2 段階の間、ld のライブラリ検索パスをコントロールするために --with-lib-path という設定スイッチを利用することができます。 第 5 章の残りのパッケージのすべては /tools にある新しい Glibc に対して構築します。

第 6 章の chroot 環境に入ってから最初にインストールするメジャーパッケージは、上述したようなその独立的な性質から Glibc となります。 一度この Glibc が /usr にインストールされれば、すばやく toolchain のデフォルトを転換し、第 6 章のターゲットとなる実際の LFS システムの残りの構築へ続きます。

静的リンクについての注意

ほとんどのプログラムはその目的とする処理以外にも、非常に多くの作業を行う必要があります。これらは共通作業だったり、ごく細かい作業だったりします。 たとえばメモリ配置やディレクトリ検索、ファイルの読み書き、文字列操作、パターンマッチング計算、そしてそのほかの多くの仕事があります。 それぞれのプログラムに再び車輪を発明させるような(訳注:車輪は便利な発明の象徴)義務を課す代わりに、 GNU システムがこれらすべての基本的な関数を、すでにでき上がったライブラリとして提供します。 あらゆる Linux システムでの主要なライブラリは Glibc です。

プログラムが使うライブラリの機能をリンクするには、基本的に静的、または動的の二つの方法があります。 プログラムが静的にリンクされた時には使われる関数のコードは実行ファイルに含まれ、結果として大きくてかさばるプログラムとなります。 プログラムが動的にリンクされた時には、含まれるものは動的リンカへの参照となるライブラリと関数の名前で、より小さな実行ファイルとなります。 ( 3 番目の方法は動的リンカのプログラミングインターフェイスを使うことです。より詳しい情報は dlopen の man ページを見て下さい。)

動的リンクは Linux でデフォルトになっていて、静的リンクに対して主に三つのメリットがあります。 第一には、プログラムの様々な集まり全体の中に含まれる同じコードの多くのコピーを持つ変わりに、ハードディスク上に実行可能なライブラリのたった一つのコピーがあればいいので、ディスクスペースを節約します。 第二に、いくつかのプログラムが同じライブラリの機能を同時に使う時に、その機能のコード一つだけがコアに必要とされるということで、メモリの節約になります。 第三に、ライブラリの機能がバグフィックスされるか、または改善されると、その改善された機能を使うプログラムすべてをコンパイルしなおす代わりに、 このライブラリただ一つだけをコンパイルすれば良いということです。

動的リンクがいくつかのメリットを持っているとすると、それではなぜこの章で初めの二つのパッケージを静的リンクにしたのでしょうか? 歴史的、教育的、そして技術的な三つの理由があります。 歴史的な理由は、以前のバージョンの LFS ではこの章ですべてのプログラムを静的にリンクしていたからです。 教育的な理由は、その違いを知るということは有益であるからです。 技術的な理由は、そうすることでホストから独立した要素を得て、それらのプログラムはホストから独立して使えることを意味します。 しかし、初めの二つのパッケージが動的にリンクされたときに、全体的に成功した LFS システムが構築されるという点では、あまり価値がありません。