コンピューターが使用されるようになったばかりの頃は、それぞれのソフトウェアは一体のものでした。マシンをブートするための ROM とオペレーティング・システムを除くと、実行に必要なすべてのライブラリーとコードを各アプリケーションが提供していました。この方法は適切なものでしたが、その主な理由は当時のコンピューターはマルチタスクの動作ができなかったためです。しかしもっと後になると、コンピューターは飛躍的に進歩し、複数のユーザーを同時にサポートすることも (タイムシェアリング)、複数のアプリケーションを同時にサポートすることもできるようになりました。多くのユーザーが同じアプリケーションを実行し、ファイルシステムや RAM などの同じシステム・リソースを共有するようになると、コードの共有は必須となり、またコードの共有によって最適化が行われるようになりました。
今日では、ほとんどすべてのオペレーティング・システムではライブラリー・コードをアプリケーション・コードとは分離しており、実行時にその 2 つを合体させます。しかし、共有ライブラリー (共有可能なコードを指す名前) には長所もあれば短所もあります。長所としては、各アプリケーションがすべて一体である必要がないため、アプリケーションのサイズが小さくなります。また、共通で使用される共有ライブラリーに対してバグ修正やパフォーマンス強化を行うと、その効果がすべてのアプリケーションに反映されます。ただしアプリケーション・コードとライブラリー・コードは、分離したと言っても手錠のようなものです。つまり共有ライブラリーはアプリケーションから利用できる状態になければならず、またアプリケーションと互換性を持つ必要があります。そうでないとアプリケーションを実行することができません。
アプリケーションとライブラリーとの結びつきは一種の依存関係です。ソース・コードを配布する場合、そのコードのコンパイルに必要なヘッダー・ファイル・セットも依存関係です。また、そのコードをコンパイルするためには、Bison や Yacc など、特定のツールが必要かもしれません。RPM としてソフトウェアを配布する場合には、すべての依存関係がターゲット・システムに用意されていることを確認してからコードのインストールを開始するようにしなければなりません。結局のところ、そのアプリケーションのインストールに適していないシステムに、アプリケーションをインストールする意味はほとんどありません。
この連載の「第 1 回」では、RPM を利用してソフトウェアを配布する方法を説明しました。「第 2 回」では、インストールとアンインストールのプロセスの詳細と、後になって補完パッケージをインストールする際のインストールする方法を説明しました。この記事は連載の最終回として、もう 1 つの重要なトピックであるソフトウェアの依存関係について、またソフトウェアのパッケージ化を制御およびカスタマイズする方法について説明します。
RPM パッケージを作成する際には、以下の 4 つのタイプの依存関係を宣言することができます。
- 作成するパッケージが、別のパッケージが提供する機能を必要とする場合には、必要なものを定義します (Requires)。
- 作成したソフトウェアの機能に、他のパッケージが依存している場合、あるいは最終的に依存する可能性がある場合には、そのソフトウェアの RPM パッケージが提供する機能を宣言します (Provides)。
- 作成したソフトウェア (あるいはその一部) が別のパッケージと共存できない場合には、競合を指定します (Conflicts)。
- 作成するパッケージによって、別のパッケージや、古いバージョンのソフトウェアが非推奨となる場合には、それらの古くなったものを定義します (Obsoletes)。パッケージの名前が変わる場合には、古くなった名前を Obsoletes に指定する必要があります。
各依存関係は RPM の spec ファイルの中に別々に列挙されます。その構文は Type: Capability です。Type は上記の 4 種類から連想されるタグ (Requires、Provides、Conflicts、Obsoletes) のうちの 1 つであり、Capability はオプションとしてのバージョン番号の名前です。複数の Capability を指定する場合には、すべての Capability を空白またはカンマで区切って同じ行に列挙します。
例えば作成したアプリケーションの実行に Perl が必要な場合には、以下のように指定します。
Requires: perl |
作成したアプリケーションに Perl と MySQL が必要な場合には、以下のように指定します。
Requires: perl, mysql |
アプリケーションが、あるパッケージの特定のバージョンや特定の主要リリースに依存することがよくあります。例えばバージョン 1.9 に準拠した Ruby コードを作成する場合には、そのバージョンのインタープリターに依存します。バージョンの依存関係を表現するためには、以下のように Capability にバージョン番号を追加します。
Requires: ruby >= 1.9 |
バージョン番号は、4 つのタイプの依存関係のどれに対しても同じ構文で指定することができます。例えば、作成したアプリケーションが、バージョン 2.0 よりも新しいバージョンの Bash シェルとは互換性がない場合には、以下のように指定します。
Conflicts: bash > 2.0 |
バージョン番号に関する比較演算子としては、以下の 6 種類があります。
package < revisionの場合には、指定されたpackageのバージョン番号はrevisionよりも小さくなければなりません。package > revisionの場合には、packageはrevisionよりも新しくなければなりません。package >= revisionの場合には、packageはrevisionよりも大きいか、あるいはrevisionと同じでなければなりません。package <= revisionの場合には、packageはrevisionよりも小さいか、あるいはrevisionと同じでなければなりません。package = revisionの場合には、指定されたrevisionでなければなりません。packageの場合には、指定されたpackageの任意のバージョンで構いません。
一般的に、Requires と Provides の情報はそれぞれ、RPM によるコードの分析と、spec ファイルの分析に基づいて自動的に生成されます。(Requires の場合に RPM によってどんな内容が生成されるかの概略は、ldd ユーティリティーを使うとわかります。) ただし必要な場合には、この 2 つのリストを修正することができます。Conflicts と Obsoletes は通常、ソフトウェア開発者が提供します。
多くの開発者が RPM を選択する理由は、RPM が使いやすく、広くサポートされているためです。しかし単純であるために、悪意のある人が RPM をインストールしてその内容を変更し、変更されたソフトウェアを正式なものとして再度パッケージ化して再配布することも容易にできてしまいます。ミラー・サイトや torrent によって、そうした「密造」は一層加速されます。自分自身を守るために、また自分が作成したソフトウェアを使用するという選択をした人達を守るために、その作成した RPM が正式なものである保証として RPM に独自の署名をします。署名することによって改ざんを防止することができます。つまりファイルに変更が加えられると署名も変更されるため、偽造されたことが判明するのです。
パッケージに署名する方法には、次の 3 通りがあります。パッケージをビルドする時にパッケージに署名する方法と、既に署名されたパッケージに再度署名する方法、そして署名のない既存の RPM に署名する方法があります。2 番目と 3 番目の方法は、最初の方法をベースにしているため、ここではビルドする時に署名する方法に焦点を絞ることにしましょう。
まず、GPG による秘密鍵と公開鍵のペアが必要です。そうしたペアがない場合にも、鍵の生成は簡単です。最初のステップとして、秘密鍵を処理する gpg-agent を起動します。(システムは通常、すべてのユーザーに対して 1 つの gpg-agent を実行します。gpg-agent を起動するステップが必要かどうか、システム管理者に確認してください。システムが既に gpg-agent を実行している場合には、gpg-agent に接続する方法を尋ねてください。)
$ gpg-agent --daemon --enable-ssh-support \
--write-env-file "${HOME}/.gpg-agent-info"
|
gpg-agent によって、自分のホーム・ディレクトリーに .gpg-agent-info ファイルが作成されます。このファイルには、実行中の gpg-agent に接続するために必要なシェル環境設定が含まれています。その情報を以下のコマンドを使ってロードします。(プロンプトでコマンド全体を入力するか、あるいはもっと便利な方法としては、このコマンド全体をシェルの起動ファイルに追加します。)
$ if [ -f "${HOME}/.gpg-agent-info" ]; then
. "${HOME}/.gpg-agent-info"
export GPG_AGENT_INFO
export SSH_AUTH_SOCK
export SSH_AGENT_PID
fi
|
最後に、現在使用している端末機器を指す追加の変数を設定します。(この場合も、以下の 2 行をシェルの起動ファイルに追加すると、これらの変数をすべての対話型セッションで利用できるようになります。)
$ GPG_TTY=$(tty) $ export GPG_TTY |
これで、鍵を生成する準備が整いました。gpg --gen-key コマンドを実行し、表示される質問に答えます。鍵生成セッションの例をリスト 1 に示します。データを入力する部分は太字にしてあります。
リスト 1. 鍵生成セッションの例
$ gpg --gen-key
gpg (GnuPG) 1.4.9; Copyright (C) 2008 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Please select what kind of key you want:
(1) DSA and Elgamal (default)
(2) DSA (sign only)
(5) RSA (sign only)
Your selection? 1
DSA keypair will have 1024 bits.
ELG-E keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 1024
Requested keysize is 1024 bits
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
Real name: Martin Streicher
Email address: martin.streicher@example.com
Comment: Example key for RPM
You selected this USER-ID:
"Martin Streicher (Example key for RPM) <martin.streicher@example.com>"
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.
Enter passphrase: ******
Retype passphrase: ******
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
+++++++++++++++++++.+++++.++++++++++++++++++++.+++++>.+++++.+++++..>+++++.+++++
|
最初に表示される質問で鍵のタイプを選択します (デフォルトが推奨オプションになっています)。次に表示される質問では、鍵のサイズをビット数で設定します。この場合、ビット数は多いほど良いのですが、ビット数が多くなると鍵の生成に時間がかかります。必要な場合には、次に表示される質問で鍵の有効期限を設定することができます。その次の 3 つの質問では、この鍵を識別するための情報が要求されます。通常は、公開鍵を得るための連絡先として作成者の名前と E メール・アドレスを入力します。最後に、パスフレーズの入力が 2 回促されます。これにより、セキュリティー・レイヤーが追加され、適切なパスフレーズを知らない限り、作成者の鍵を使って RPM に署名することは誰にもできません。システムの動作の状態により、鍵の生成には数秒で終わる場合もあれば、数分かかる場合もあります。
鍵の生成が完了すると、鍵の生成処理によって $HOME/.gnupg という新しいディレクトリーが作成され、秘密鍵と公開鍵を表すファイル群がそこに追加されます。利用可能な鍵を表示するためには、gpg --list-key を実行します。すると、RPM に署名する際に使用する鍵の名前が uid の値に含まれて表示されるので、この値をメモします。
$ gpg --list-key /home/strike/.gnupg/pubring.gpg ------------------------------- pub 1024D/1811A3E4 2009-11-23 uid Martin Streicher (Example key for RPM) <martin.streicher@example.com> sub 1024g/15BBCF06 2009-11-23 |
この先を続けるためには、パッケージに署名するための RPM のオプションを設定する必要があります。$HOME/.rpmmacros ファイルを作成するか (既に存在する場合は) 開き、以下の 3 行を追加します。
%_signature gpg %_gpg_path /home/strike/.gnupg %_gpg_name Martin Streicher (Example key for RPM) <martin.streicher@example.com> |
%_signature 行で署名のタイプを選択します。ここでは署名のタイプを gpg に設定しています。%_gpg_name は署名に使用する鍵の ID を指定します。鍵を生成する際に、名前を Martin Streicher (Example key for RPM) <martin.streicher@example.com> に設定しました (上記でのユーザー ID [UID] の値)。そこで、ここでもその名前を使います。最後に、%_gpg_path は鍵へのパスを定義しています。
鍵と構成を用意できましたが、RPM に署名するためには、さらにもう 1 つのオプションである --sign が必要です。
$ rpmbuild -v --sign -bb --clean SPECS/wget.spec Enter pass phrase: Pass phrase is good. Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.46786 + umask 022 ... |
上記の rpmbuild コマンドは「第 1 回」で使用した rpmbuild コマンドと同じですが、--sign が追加されている点のみが異なります。パスワードの入力を要求されたら、鍵を生成する際に入力したパスフレーズと同じパスフレーズを入力します。RPM のビルドが続行され、ビルドされたパッケージは RPM によって署名されます。
署名を検証し、そのパッケージが正式なものであることを確認します。RPM の署名を検証するためには、RPM ファイルそのものに対して rpm -K を実行します。
$ rpm -K wget-1.12-1.i386.rpm wget-1.12-1.i386.rpm: (SHA1) DSA sha1 md5 (GPG) OK |
このコマンドによって OK が表示されれば、このファイルは正式なものです。皆さんが別の開発者の RPM をダウンロードする際には、そのパッケージをインストールする前に検証を行うことを検討してください。
パッケージ化をするために RPM を頻繁に使っていると、spec ファイルを作成するのは訳無い作業になってきます。とは言え、以下のように多種多様なツールがあり、これらを利用することで spec ファイルを容易に作成できるようになります (「参考文献」には各ツールへのリンクを挙げてあります。)
rpmlintを使うと RPM ファイルを検証することができます。このツールによって、かなりの数の誤りを検出することができます。例えば、/etc にバイナリー・ファイルをインストールし、構成ファイルを /usr にインストールしてしまう、という 2 つのよくある間違いをrpmlintによって検出することができ、またカスタム・モジュールを使って rpmlint を拡張することもできます。rpmlintは Python で作成されており、その機能を実行するためには、いくつかのライブラリーが必要です。- Easy RPM Builder はパッケージを組み立てるための KDE (K Desktop Environment) ベースのツールです。このツールには、RPM の作成を補助するテンプレートがいくつも用意されており、またspec ファイルの一部に利用できる GUI (graphical user interface) も用意されています。Easy RPM Builder は
rpmbuildを置き換えるものではありません。Easy RPM Builder を効果的に使用するためには、ある程度 RPM を理解している必要があります。 - KDE を使用していない場合や、sepc ファイルを直接操作したい場合には、Vim と Emacs を拡張して特別な spec モードを含めることで、spec ファイルの構文を強調表示したり、spec ファイルの作成や保守を補助したりすることもできます。
- いわゆるツールではありませんが、Fedora プロジェクトの RPM ガイドラインのページには、ベスト・プラクティスの膨大なリストが用意されています。実際、Fedora 用にソフトウェアを配布するつもりであれば、新しいパッケージに対する要件に特に注意する必要があります。また、これらのガイドラインには、いくつかの一般的なプラットフォーム (Eclipse、Perl、Ruby など) をベースにアプリケーションをパッケージ化する方法も説明されています。特定のインタープリター用にソフトウェアをパッケージ化する作業は特に複雑です。パッケージ化されたソフトウェアにはスクリプトやバイナリー、そしてソースが含まれ、インストール中にそれらをターゲット・マシン上で直接再ビルドする必要があるからです。例えば、Perl モジュールは一部が Perl コードで一部は
Cコードかもしれません。Fedora のサイトには、RPM に関する正式なソフトウェア・ガイドも用意されています (下記の「参考文献」にリンクがあります)。
RPM のインストールや管理を支援するツールは他にもあります。一般的に、これらのツールはシステム管理者用ですが、インストールの検証や自分が使っている開発システムのソフトウェアの管理にも役立ちます。テスト用に独自の開発システムを使用している場合には、これらのツールは不要となったパッケージの削除に便利かもしれません。
RPM はアクティブに保守が行われています。その作業については RPM プロジェクトの新しいホームページで追跡することができます (「参考文献」を参照)。Debian を含め、大部分の Linux ディストリビューションには RPM ツールが用意されています。RPM の最新バージョンは 2009年 7月にリリースされた 5.2.0 です。RPM プロジェクトの目標は昔から変わっておらず、「システムへのパッケージの追加や削除を容易にすること。パッケージが適切にインストールされたことを容易に検証できるようにすること。パッケージ作成者にとって使いやすいものにすること。オリジナルのソース・コードから開始できること。多様なコンピューター・アーキテクチャーで動作するようにすること」です。
RPM の作成は複雑ですが、それはソフトウェアのインストールが同じように複雑なためです。この連載で説明した内容は、RPM の作成に関するごく一部にすぎません。Web を探せば、RPM の作成に関して豊富な情報を得ることができます。RPM の話題に特化したチュートリアルやフォーラム、さらには IRC チャンネルもあります (Freenode の #rpm.org を訪れてみてください。) さらに Web 上には、何千とまではいきませんが何百という RPM があります。極めて困難な問題に直面した場合には、同様の機能を持つ別の RPM パッケージを探し、その spec ファイルを調べることで解決方法を見つけることができます。
皆さんがソフトウェア開発者またはシステム管理者である場合には、アプリケーションをパッケージとして提供することで、インストールやアップグレード、そして保守がはるかに容易になります。繰り返しになりますが、RPM を使ってアプリケーションをビルドし、パッケージ化すれば、必ず期待どおりの結果を得ることができます。
学ぶために
- この、RPM Package Manager 関する 3 回連載の記事をすべて読んでください (developerWorks、2010年1月)。
- ウィキペディアで RPM Package Manager の概要を読んでください。
- RPM の公式サイトを訪れ、Linux でのパッケージ管理に関する情報を入手してください。
- Red Hat Linux での RPM について学んでください。
- RPM に関する Fedora のガイドラインを調べてください。
- Martin が developerWorks に寄稿した他の記事を読んでください。
- developerWorks の Linux ゾーンには Linux 開発者のためのリソースが他にも豊富に用意されています。また最も人気の高かった記事とチュートリアルの一覧もご覧ください。
- developerWorks に掲載されているすべての「Linux のヒント」シリーズの記事と Linux チュートリアルを参照してください。
- developerWorks の Technical events and Webcasts で最新情報を入手してください。
製品や技術を入手するために
rpmlintについて学び、また rpmlint をダウンロードしてください。- Easy RPM Builder について学び、また Easy RPM Builder をダウンロードしてください。
- developerWorks から直接ダウンロードできる IBM ソフトウェアの試用版を使用して、皆さんの次期 Linux プロジェクトを革新してください。
議論するために
- My developerWorks コミュニティーに参加してください。開発者向けのブログ、フォーラム、グループ、ウィキなどを利用しながら、他の developerWorks ユーザーとつながりを持ってください。

Martin Streicher はフリーランスの Ruby on Rails 開発者であり、以前は Linux Magazine の編集責任者でした。彼は Purdue University でコンピューター・サイエンスの修士号を取得しており、1986年以来 UNIX ライクなシステムのプログラミングをしてきました。彼は美術品やおもちゃを収集しています。