GoboLinuxのレシピでパッケージ管理を楽にする
GoboLinuxがよく知られているのは、その一風変わったファイルシステム階層によってだろう。プログラムに付随するファイルが/etc、/usr/bin、/usr/shareなどいくつかの場所に散らばっているLinuxの従来のファイルシステム階層とは異なり、GoboLinuxでは各プログラムが独自のディレクトリツリーを持つ。
言うまでもなく、こうした階層はパッケージ管理を楽にしてくれる。ユーザは、1つのプログラムまたはシステムライブラリについて複数のバージョンをインストールして使うことができる。実際、GoboLinuxがGNU Compiler Collection(GCC)のバージョン3に移行したあとも、このファイルシステムであれば複数のバージョンのライブラリを何の問題もなく共存させられるため、以前のバージョンを実行することが可能になっている。また、アンインストールの際にも該当するプログラムのディレクトリを削除するだけで済む。
しかし、このような先進的なディレクトリ構造のもとでアプリケーションは一体どのようにインストールされるのだろうか。
ソースコードだけで十分
GoboLinuxの開発者たちには、最初からRPMやDebianパッケージのような別のパッケージ形式を加えるつもりがなかったという。そのうえ、RPMやDebianといったパッケージ形式は、アプリケーションの人気に応じて提供されたりされなかったりすることがある。しかし、どんなアプリケーションでもソースを圧縮したtarballは入手できるはずだ。
GoboLinuxをAndré Detsch氏と共に開発したHisham H. Muhammad氏は、tarballなら簡単に展開でき「configure、make、make install」という3つのコマンドを使ってインストールできる、と説明する。
依存関係がconfigureコマンドによって(解決はされないが)チェックされ、プログラムはシステム上に存在する適切なライブラリと不整合なくリンクされる。ソースのtarballをうまい具合にまとめていくつかのGNUの慣習に従ったものにすれば、どんなLinuxディストリビューションでも動作するに違いない、とGoboLinuxの開発者たちは考えた。そうなれば、理論的にはtarballさえあれば他の配布形式は一切必要なくなるはずである。また、GNUのビルドシステムなど標準のビルド環境を使ってアプリケーションをまとめれば、インストールの自動化も可能になる。
しかし、誰もがGNUのビルドシステムを使ってソースのtarballをまとめているわけではない。そこで、登場するのがGoboLinuxのCompileツールである。このCompileは、ソースがいくつかの標準的な方法で配布され、宣言によって特定可能な多数のマイナー・バリエーションが存在するという前提で動作する。そうした配布方法のそれぞれが「実行モデル」であり、それらをサポートするしくみが別々に実装されている。GoboLinuxには、主要な実行モデルが3つある。configureベースのファイルを対象とする「compileprogram」、configureなしのmake/make-installプロジェクトを対象とする「makefile」、Xのimakeツールに基づいたアプリケーションを対象とする「xmkmf」である。
ソースのtarballのダウンロード、展開、コンパイル、インストールのすべてを1つのコマンドで実行するのがCompileツールの役割だ。Compileでは、アプリケーションのコンパイル方法を記述した「レシピ(recipe)」と呼ばれる簡単なファイルが利用される。
Compileが動作するしくみ
Compileの優れている点は、ソースを取得するためにあらゆるプロジェクトのダウンロード・サイトを利用することだ。GoboLinuxのリポジトリは、レシピをダウンロードするためだけに使われる。レシピのダウンロードはGetRecipeコマンドを使って明示的に行なうこともできるが、Compileを実行すればコンパイルが必要になったときにその場で行われる。
例えば、Compileを使ってテキストエディタJoeをダウンロードするには、単純にCompile joe
と実行する。これにより、まずはjoe(大文字と小文字の区別あり)という名のレシピの検索が行われる。特定のバージョンを指定したい場合はCompile joe 3.1
のようにすれば、Joeのバージョン3.1用のレシピを探してくれる。レシピは圧縮されたtarballになっており、joeのレシピであればJoe-3.1-r2-recipe.tar.bz2というファイルがこれにあたる。
Compileがこのtarballを展開すると、RecipeというファイルとResourcesというディレクトリができる。Recipeファイルの内容は次のようになっている。
# Recipe (MakeRecipe) for Joe by roko, <ro.ko@mcnon.com>, on Wed Oct 27 03:01:32 BRST 2004
# Recipe for version 3.1 by roko, <ro.ko@mcnon.com>, on Wed Oct 27 03:01:32 BRST 2004
compile_version=1.8.0
url="$httpSourceforge/joe-editor/joe-3.1.tar.gz"
file_size=381201
file_md5=2a6ef018870fca9b7df85401994fb0e0
recipe_type=configure
続いて、Compileは上記のURLを参照し、このプロジェクトのホームページからソースのtarballをダウンロードする。上記のrecipe_typeオプションは、そのプログラムに必要なコンパイルの種類(この場合は./configure、make、make installという一般的な手順)を示している。同じく上記のファイルサイズとMD5シグネチャは、Compileがダウンロードしたパッケージの検証を行うのに用いられる。
次に、Compileが目を向けるのはResourcesディレクトリである。このディレクトリには2つのファイルが入っている。1つは、Joeについて簡単に説明したDescriptionファイル、もう1つはこのアプリケーションが依存するすべてのライブラリを列挙したDependenciesファイルである。Dependenciesファイルに記されたライブラリがそのシステムにない場合、足りないライブラリの取得とインストールを行うかどうかもCompileが確認してくる。
アプリケーションのダウンロードと検証、依存関係の解決が終わると、Compileはアプリケーションの設定とインストールの作業に移る。Compileには「–configure-options」という特別なフラグがある。これを使えば、追加のパラメータをCompileから設定スクリプトに渡すことができる。例えば、Compile --configure-options="--enable-debug" joe
のように用いる。
プログラムのコンパイルが完了すると、/Programsの下にそのアプリケーション専用のディレクトリができる。Joeの場合は/Programs/Joe/3.1である。さらに、CompileはjoeレシピのResourcesディレクトリを/Programs/Joe/3.1/の下にコピーし、そのディレクトリの中に以下の4つのファイルを新たに作成する。
パッケージのコンパイルを行ったアーキテクチャの種類を示すArchitectureファイル、パッケージのコンパイル後にldd(動的な依存関係を列挙するアプリケーション)によって追跡した依存関係を記録するBuildInformationファイル、パッケージ内の各ファイルのmd4sumを記録するFileHashファイル、FileHashのPGPシグネチャを記したFileHash.sigファイルである。GoboLinuxの主たる開発者の1人Lucas Villa氏の説明によると、誰がどのパッケージを作ったかがインストール時にわかるように、すべての貢献者に公開鍵の「リング」をリストしてもらったことからこのアイデアが生まれたという。
すべてのファイルおよびディレクトリの作成と配置が終わると、Compileがシステムで必要になるリンクのすべてを作成し、アプリケーションが使えるようになる。現在、GoboLinuxのリポジトリにはプログラム1,709種類のレシピ5,376件が収められているとVilla氏は言う。
レシピの自作
CompileがJoeのインストールを進めていくのを座って見ているうちに、どうすればレシピが作れるのだろうかという点が気になった。Joeのレシピはバージョン3.1用のものだったので、最新のバージョン3.5のものを自分で作ってみようと決意したのだが、実際にやってみるとレシピの作成があまりに簡単なのに驚いた。
レシピを作成するには2つの方法がある。後述するMakeRecipeによる方法は、まだレシピのないアプリケーションのためにレシピを作るもの、一方のNewVersionによる方法では、既存の旧バージョンのレシピに基づいて新バージョンのレシピを作成する。
NewVersionの実行には、パラメータとしてパッケージの名前とバージョン番号が必要になる。今回はNewVersion joe 3.5
とすると、/Files/Compile/Recipes/の下にある既存のレシピに基づいて新しいレシピ用のテンプレートが作成される。また、ダウンロード先URLも変更されるが、これはURLパス中の旧バージョン番号を新しいバージョン番号に置き換えているだけである。アプリケーションの置かれている場所が変わっている場合は、NewVersionの実行時に新しいURLをパラメータとして渡すことができる。例えば、NewVersion joe 3.5 http://jaist.dl.sourceforge.net/sourceforge/joe-editor/joe-3.5.tar.gz
とすれば、元のレシピに記されたURLの代わりに指定したものが使われる。なお、ローカルで作られたレシピはすべて/Files/Compile/LocalRecipes/の下に保管される。
新たに作成したレシピは次のようになっている。
# Recipe for version 3.5 by Mayank Sharma, on Mon Jan 29 16:49:14 IST 2007
# Recipe (MakeRecipe) for Joe by roko, <ro.ko@mcnon.com>, on Wed Oct 27 03:01:32 BRST 2004
compile_version=1.7.1
url="$httpSourceforge/joe-editor/joe-3.5.tar.gz"
recipe_type=configure
レシピの内容が正しいことを確認するには、実際にインストールしてみるのが一番である。/Files/Compile/LocalRecipesの下に新しいレシピができているなら、再びCompileを実行してJoeのインストールを行ってみよう。今回Compileはローカル環境に用意されたバージョン3.5用のレシピを利用して新しいtarballのダウンロードを行うが、これにより、レシピに記されたURLに間違いがないことを確認できる。ダウンロード後、サンドボックス環境でJoeの設定とインストールが行われる。サンドボックス環境を使えば、ベースシステムに影響を与えることなくアプリケーションをテストできる。どこにも問題がなく、全実行ファイルが利用可能ですべてのパスが適切にマップされていることを確認したうえで、Compileは各ファイルを/Programs以下の該当ディレクトリにコピーしてシステムパスの更新を行う。最後に、新しいレシピの圧縮済みtarballが作成され、GoboLinuxリポジトリへの送信に備えて/Files/Compile/Storeディレクトリに保管される。
レシピの検証をもっと手っとり早く行いたければ、GenRecipeStoreスクリプトを使ってテストすればよい。このスクリプトは、レシピの構造とURLを確認し、基本的な構文チェックを行ってくれる。また、/System/Variable/tmpの下にテンポラリのレポートを生成し、/Files/Compile/Storeに圧縮されたレシピのtarballを作成する。
今度は、レシピのないFooというアプリケーションのレシピを新たに作ることを考えよう。MakeRecipe http://unc.dl.sourceforge.net/sourceforge/foo-app/foo-1.0.tar.gz
とすると、アプリケーションがダウンロードされるだけでなく、その名前とバージョンがダウンロード先URLから抽出されて新しいレシピが作成される。
続いてMakeRecipeは、Autoconfのような標準のツールチェーンを使ってソースがアセンブルされているかどうかを教えてくれる。標準のツールを使ってビルドされていればCompileを使ったコンパイルが可能なため、Compileによってアプリケーションがインストールされ、圧縮されたレシピが作成されることになる。
依存関係の解決とバイナリパッケージの作成
アプリケーションFooがシステム上にないライブラリに依存している場合、Compileによるインストールが行えない。この場合は、自らの手でDependenciesファイルを作成する必要がある。この困難を克服するために、最近GoboLinuxの開発者たちが取り組んでいるのがChrootCompileというツールだ、とVilla氏は話す。「このツールは、基本的には蓄積されたレシピから抽出した‘クリーン’なパッケージだけで構成されるchroot環境だ。GoboLinuxによるすべてのインストール環境に存在すると思われるパッケージ群の基本セットがchroot環境に自動的にマージされ、chroot環境の作成スクリプトの実行が終わると、そのrootファイルシステム内からCompileが呼び出される。ただし、こうしたパッケージの基本セットでカバーされない依存関係はすべてDependenciesファイルに明示的に書き出す必要があり、このリストはchroot環境を作成するスクリプトによって読み取られる」
Villa氏は、依存関係を範囲で指定できるようになったことにも触れている。例えば、「GTK+ > 2.8.0」は、アプリケーションがGTKのバージョン2.8以降との依存関係があることを示し、「GLib < 1.2.10」は、GLibの1.2.10より前のバージョンが必要なことを示す。
また、クロスコンパイル時にのみ必要になる依存関係を明示するために、クロスコンパイルのためのサポートも追加される。つまり、「Autoconf 2.59 [cross]」はパッケージのクロスコンパイルのためにAutoconfが必要になることを、「X.org [!cross]」はクロスコンパイル以外でのみX.orgが必要になることを意味する。
パッケージのインストールが正常に完了したら、既存のレシピまたは自作のレシピのいずれかをもとにしてバイナリパッケージを作成することもできる。バイナリパッケージは事前にコンパイルされているため、すぐにインストールが終わる。自分用のバイナリパッケージを作成したり、ソースからのインストールは行いたくないというユーザのためにバイナリパッケージを配布したりもできる。
バイナリパッケージを作成するには、そのアプリケーションを自分のシステムにインストールしておく必要がある。今回はテキストエディタJoeのバージョンが2種類インストールされているので、バージョン3.5のバイナリパッケージを作成する場合はCreatePackage joe 3.5
を実行する。
このCreatePackageは、サブディレクトリ/Programs/Joe/Settingsの設定内容を破棄したうえで/Programs/Joe/3.5ディレクトリの圧縮を行うだけである。この設定内容は、/Programs/Joe/3.5/Resources内に保管されているデフォルト設定で置き換えられる。なお、デフォルトの設定はレシピのtarballからコピーされたもので、そこには前述の4つの追加ファイルが含まれている。
バイナリパッケージのインストールの詳細については、GoboLinuxのWikiを参照していただきたい。また、ソースまたはバイナリのどちらの方法でインストールしたパッケージでも、アンインストールにはRemoveProgramツールを使用する。
まとめ
GoboLinuxは興味深いディストリビューションであると同時に学習の面でもためになるツールである。私の場合、レイアウトや各種パッケージ管理ツール、その操作方法を理解するのに少し時間がかかったが、そこをクリアしさえすれば、自分で初めてレシピを作成する場合にもほとんど時間がかからなかった。
GoboLinuxに含まれるパッケージは他の著名なディストリビューションほど多くはないが、標準のツールチェーンを使ってビルドされるアプリケーションがますます増えるにつれ、この点は大幅に改善されるだろう。MakeRecipeスクリプトを実行するだけでレシピが作成できるので、GoboLinuxでパッケージ管理に煩わされることはなくなるはずだ。