RPMパッケージ作成メモ |
LinuxのRPMパッケージを自分で作るためのノウハウ集です。
大抵のLinux OSのディストリビューションには含まれていますが、オプション扱いでインストールされていないこともあります。
# yum install rpmbuild :
RPMパッケージ作成はroot権限で作業するとエラー時に悲惨な目にあうので、必ず一般ユーザ権限で作業します。
ユーザのホームディレクトリに、RPMパッケージ作業用ディレクトリを作成します。
~$ mkdir -p rpm/{BUILD,RPMS,SOURCES,SPECS,SRPMS} ~$ ls rpm BUILD RPMS SOURCES SPECS SRPMS ~$
rpmbuildコマンド実行時に、上述のホームディレクトリに作った作業ディレクトリを使用するための設定ファイルを~/.rpmmacrosに記述します。
%_topdir /home/torutk/rpm %packager Toru Takahashi <torutk@example.org> %_sysconfdir /etc
注記)GPG鍵による署名については、本ページでは記載していませんが、インターネット上などで公開する場合は、思わぬ悪意から守るために署名をするべきです。
src.rpmを入手すれば、簡単にバイナリ・パッケージをビルドすることができます。
~$ rpmbuild --rebuild xyz-1.2.3-4.src.rpm :
~/rpm/RPMS/i386の下に、バイナリパッケージが生成されます。
エラーが発生する場合、大抵はspecファイルを調整することになります。
specファイルが提供されているtarballの場合、比較的簡単にRPMバイナリパッケージを生成することができます。
まず、tarballからspecファイルを取り出し、~/rpm/SPECSの下に置きます。
tarballを~/rpm/SOURCESの下に置きます。
~$ cd rpm/SPECS SPECS$ rpmbuild -ba xyz.spec :
rpmbuildコマンドの主要オプションは以下です。
-bp %prepセクションを実行 -bc %prepと%buildセクションを実行 -bi %prepと%buildと%installセクションを実行 -bb %prepと%buildと%installセクションとバイナリパッケージ作成を実行 -ba %prepと%buildと%installセクションとバイナリパッケージ作成とソースパッケージ作成を実行 -bl %filesセクションの検査を行う --short-circuit -bc %buildセクションを実行(%prepを飛ばして) --short-circuit -bi %installセクションを実行(%prepと%buildを飛ばして) --nobuild 何もビルドをせず、specファイルの検査を行うのに使う
specファイルを1から作成する点を除き、上記tarballからのビルドと一緒です。
名前 - バージョン - リリース . ディストリビューション . アーキテクチャ . rpm
- 名前
- ソフトウェア名を指定します。
- バージョン
- 数字とピリオドの組み合わせで、通常3桁で指定します。(例: 3.4.5)
- リリース
- RPMパッケージのリリース番号で、ソースコードは変更なくパッケージのビルド手順上の修正がある場合にリリース番号をインクリメントしていきます。
- ディストリビューション
- ディストリビューションを識別する文字列を指定することがあります。(例:fc10、el5)
- アーキテクチャ
- パッケージのバイナリが実行可能なアーキテクチャを指定します。(例: i386、i686、noarchなど)
RPMパッケージ最大の難関が、このspecファイルを作成することです。specファイルを極めることが、RPMパッケージ職人につながります。
specファイルの構成を簡単に記述すると以下になります。
イントロダクション セクション |
description セクション |
prep セクション |
build セクション |
install セクション |
clean セクション |
files セクション |
specファイルの先頭に記述します。
Name: xyz Version: 1.2.3 Release: 1%{?dist} Group: Utilities Vendor: Example Company URL: http://www.example.com/product/xyz Packager: Toru Takahashi <torutk@example.com> License: MIT Summary: Tools for doing something about xyz. Summary(ja): xyzについてなにかをするツール Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildArch: i386 Source: xyz-1.2.3.tar.gz Patch1: xyz-cvs.patch
Name、Version、Releaseは3大重要項目ですから、しっかり定義します。
Groupは、/usr/share/doc/rpm-4.1/GROUPSに定義されているものから選択するのがよいでしょう。
Summary(ja)は、日本語ロケールでのパッケージ概要を表示するために使われます。(省略可)
ソースファイル(アーカイブ)が複数あるときは、Source0, Source1, …とSourceに数値を連番で付けて指定します。
パッチファイルが複数あるときは、Patch0, Patch1, …とPatchに数値を連番で付けて指定します。
Source0: xyz-1.2.3.tar.gz Source1: abc-0.1.tar.gz Patch0: xyz-1.2.3-p3.patch Patch1: xyz-1.2.3.cvs.patch
これらソースファイルとパッチファイルは、パッケージ作成時はSOURCESディレクトリの中に置きます。
VendorとPackagerは、パッケージを作成する団体・作業者を記述します。
Licenseは、ソースコードのライセンスを記載します。
BuildArchには、このパッケージのアーキテクチャ(CPU種別)を指定します。x86 Linux(CentOS 5)では、この指定を省略した場合、i386が適用されます。コンパイルオプションでCPU限定の指定をする場合、i686のように限定するCPUアーキテクチャ名を記述します。CPU依存バイナリがないパッケージ(スクリプト言語等)は、noarchを指定してもよいでしょう。
Releaseはソースファイルには手を入れずに、ビルドに関する設定を修正したときにインクリメントします。ディストリビューション識別は共通のSPECファイルから複数ディストリビューション(バージョン)に対応できるよう、rpmbuildコマンドのコマンドラインオプションでdistマクロを指定したときに付与されるように記述しています。
※SPECファイルにdistを定義すると、ディストリビューション(バージョン)ごとにSPECファイルを修正しなくてはならないため
$ rpmbuild -ba --define="dist .el5" xyz.spec
Sourceには、URLでファイルを指定することができます。rpmbuild実行時にURLからファイルをダウンロードします。
specファイルで使用するマクロがあります。この値を知りたいときは、rpmコマンドの--evalオプションで確認できます。
$ rpm --eval %{_libdir} /usr/lib $
マクロ | 値 | 定義 | |
_prefix |
/usr | - | |
_exec_prefix |
/usr |
%{_prefix} |
|
_lib |
lib |
- |
|
_bindir | /usr/bin |
%{_exec_prefix}/bin |
|
_libdir | /usr/lib |
%{_exec_prefix}/%{_lib} |
|
_datadir | /usr/share |
%{_prefix}/share |
|
_includedir | /usr/include |
%{_prefix}/include |
|
_sysconfdir |
/etc |
- | |
_initrddir |
/etc/rc.d/init.d |
%{_sysconfdir}/rc.d/init.d |
※Fedora 9以降では非推奨となっている(代わりに%_initddirを使う) |
一覧するには、rpmbuildコマンドの--showrcオプションで可能です。
マクロ定義に_docdirはないが、specファイルで_docdirを使用しているものがあります。_docdirは実行時に確定するマクロで、事前に定義されているマクロ_defaultdocdirが適用されるようです。
パッケージ内容を詳細に記述するセクションです。
%description The xyz utilities are used for software development activities. The main activities are in construction and unit testing. : %description -l ja XYZユーティリティは、ソフトウェア開発作業に役立つツールを収めています。 特に、ソフトウェアのビルドおよび単体テスト作業に使うことを目的としています。 :
本記述は、rpmコマンドでパッケージ内容を調べるときに見ることになるので、丁寧に記載しましょう。記述量はおおむねコンソール画面で半分程度の量がいいのではないかと思います。(80桁で10行強)
ソースコードのアーカイブファイルを作業ディレクトリ(BUILD)に展開し、パッチファイルがあればパッチを適用する処理を記述するセクションです。
パッチファイルがなく、ソースコードのアーカイブがRPM命名習慣に則って作成されていれば、以下の記述だけで十分です。
%prep %setup -q
パッチがある場合、%patch を指定します。
%patch0 -p0 %patch1 -p0
%setupは、SOURCESディレクトリにあるソースコードアーカイブをBUILDディレクトリの下に展開します。そして、ソースコードのディレクトリ内にカレントディレクトリを移します。
たとえば、イントロダクション・セクションに以下の記述を行っていた場合、
Name: xyz Version: 1.2.3 Release: 1 Source: xyz-1.2.3.tar.gz
まず、BUILDディレクトリで、xyz-1.2.3.tar.gzを展開します。そして、BUILD/xyz-1.2.3へcdします。このcdするディレクトリは、%{name}-%{version}です。したがって、あらかじめソースコードアーカイブがこの命名に従って作られていないとエラーとなってしまいます。
しかし、いくつかのソースアーカイブはRPMの命名に従っていません。そのときは、%setupに-nオプションでcdするディレクトリ名を指定します。
%setup -q -n xyz_1_2_3
UNIXのpatchコマンドを呼び出します。パッチファイル作成時のディレクトリ指定によって適切な-pオプションを指定します。
%patchコマンドは、%setupコマンドでソースコードアーカイブが展開されそのディレクトリ内にcdした後に実行されるので、パッチファイル作成時にソースコードアーカイブのトップレベルディレクトリがパッチファイルに含まれていれば、-p 1でトップレベルディレクトリを除外します。
展開・パッチが適用されたソースコードをビルドします。
configure/makeでビルドするtarballの場合は以下の記述となります。
%build %configure make
%configureは、その実行しているマシン環境のデフォルト設定をコマンドラインオプションで展開します。以下はCentOS 5.2のx86マシン上での展開内容です。
$ rpm --eval "%configure" CFLAGS="${CFLAGS:--O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions \ -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic \ -fasynchronous-unwind-tables}" ; export CFLAGS ; CXXFLAGS="${CXXFLAGS:--O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions \ -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic \ -fasynchronous-unwind-tables}" ; export CXXFLAGS ; FFLAGS="${FFLAGS:--O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions \ -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic \ -fasynchronous-unwind-tables}" ; export FFLAGS ; for i in $(find . -name config.guess -o -name config.sub) ; do [ -f /usr/lib/rpm/redhat/$(basename $i) ] && /bin/rm -f $i && \ /bin/cp -fv /usr/lib/rpm/redhat/$(basename $i) $i ; done ; ./configure --build=i686-redhat-linux-gnu --host=i686-redhat-linux-gnu \ --target=i386-redhat-linux-gnu \ --program-prefix= \ --prefix=/usr \ --exec-prefix=/usr \ --bindir=/usr/bin \ --sbindir=/usr/sbin \ --sysconfdir=/etc \ --datadir=/usr/share \ --includedir=/usr/include \ --libdir=/usr/lib \ --libexecdir=/usr/libexec \ --localstatedir=/var \ --sharedstatedir=/usr/com \ --mandir=/usr/share/man \ --infodir=/usr/share/info
ビルド完了後、インストールを実行します。ここでのインストールは、RPMパッケージを作成するための作業用なので、本当のインストール先ではなく、作業用のインストール先を指定します。
configure/makeでビルドするtarballの場合は以下の記述となります。
%install make install PREFIX=$RPM_BUILD_ROOT/usr
make installが用意されていない場合、installコマンドやcpコマンド等を使ってファイルのコピーを行います。シェルスクリプトとほぼ同様に記述できます。
#ディレクトリを作成 install -m755 -d $RPM_BUILD_ROOT/usr/share/%name-%version/config #ファイルを1つコピー install -m755 README $RPM_BUILD_ROOT/usr/share/%name-%version/README #ファイル群を指定ディレクトリの下へコピー(再帰的にはコピーされない) install -m755 config/* $RPM_BUILD_ROOT/usr/share/%name-%version/config
最初%{name}-%{version}のように記述していたら、シェル実行時に{xyz}-{1.2.3}のように展開されたため、{}を除去しています(CentOS 5.2/rpmbuild 4.4.2)。
installコマンドでディレクトリを再帰的にコピーする方法が見当たらず、現状は都度記述しています。
サブディレクトリがあるディレクトリの中のファイルをワイルドカードで一括指定するとエラーとなります。
xyz-1.2.3 +-- config | +-- xyz_1st.dat | +-- xyz_2nd.dat | +-- templates | +-- xyz_template.dat | +-- xyz_template2.dat
ここで、以下記述をすると、templatesが複数回インストール処理されることになりエラーが発生します。
install -m755 config/* $RPM_BUILD_ROOT/etc/xyz/config install -m755 config/templates/* $RPM_BUILD_ROOT/etc/xyz/config/templates
面倒ですが、個別に指定するしかないようです。(あるいはinstallコマンドではなくcpコマンド等でサブディレクトリごと一括コピーする)
install -m755 config/xyz* $RPM_BUILD_ROOT/etc/xyz/config install -m755 config/templates/* $RPM_BUILD_ROOT/etc/xyz/config/templates
後のfilesセクションで指定するドキュメントファイルについては、このinstallセクションで記述していなくても、コピーされるようです。
%clean rm -rf $RPM_BUILD_ROOT
インストールするファイルを個別指定するのが基本形です。
%files /usr/bin/xyzd /usr/share/man/man1/xyz.1.gz
ワイルドカードを使って複数ファイルを指定することもできます。
/usr/share/man/man1/xyz.*
空のディレクトリを指定場所に作成する場合、%dirマクロを使います。
%dir /etc/xyz
中にファイルが存在するディレクトリを指定すると、サブディレクトリも含めてインストール対象となります。
/usr/share/xyz-1.2.3
注意)パッケージをアンインストールすると、この方法で指定したディレクトリは一括削除されます。例えば、/usr/bin といった指定はしてはいけません。ファイルを個別に指定するか、/usr/bin/* のようにワイルドカード指定します。
ドキュメントファイルとしてマークし、ドキュメント・ディレクトリを作成してインストールするファイルを%docマクロで指定します。
%doc README NEWS
ドキュメントファイルが複数ディレクトリに散在していても、ファイル指定すれば一箇所に集められます。
%doc docs/README news/NEWS changelogs/ChangeLog
これらは、%docdirの直下にファイルとして置かれます。
ドキュメント・ディレクトリを%docdirマクロで指定します。%docで指定したファイルはここに集められます。
%docdir /usr/share/man/man1
設定ファイルとしてマークします。アップデートや再インストール時、設定ファイルに変更が入っていれば、拡張子を変えて保存します。明示的に上書き禁止を指定することもできます。
%config /etc/rc.d/init.d/* %config(noreplace) /etc/xyz/xyz.conf
ファイルのパーミッションを設定する場合、%attrマクロを使います。
%attr(0644,root,root) /etc/xyz/xyz.conf
まとめて一括指定する方法もあります。こちらが一般的です。
%files %defattr(-,root,root) :
別なファイルにファイル一覧を記述しておき、取り込むことができます。
%files -f xyz_file.list
TODO:
%filesセクションに記述するmanファイルは、拡張子.gzを指定します。
%install install xzy/xyz.1 $RPM_BUILD_ROOT%{_mandir}/man1 %files /usr/share/man/man1/xyz.1.gz
ドキュメントファイルは、%docdirで指定したドキュメントディレクトリ直下にコピーされます。これは、%docでディレクトリ付き指定をしていた場合でも、ファイルが直下にコピーされるからです。一方、%docでディレクトリを指定した場合、ディレクトリとして%docdir直下にコピーされます。これは、rpmbuildの仕様なのか実装依存なのかは未確認です。
%docdir /usr/share/doc/xyz-1.2.3 %doc README LICENSE changelogs
changelogsがディレクトリだった場合、/usr/share/doc/xyz-1.2.3/changelogs/* としてインストールされます。
%post /sbin/chkconfig --add xyzd
アンインストール前に実行するスクリプトを%preunに、アンインストール後に実行するスクリプトを%postunに定義することができます。
%preun if [ "$1" = 0 ]; then /sbin/service xyzd stop > /dev/null 2>&1 /sbin/chkconfig --del xyzd fi exit 0 %postun if [ "$1" -ge 1 ]; then /sbin/service xyzd condrestart > /dev/null 2>&1 fi exit 0
%changelog * Fri July 4 2008 Toru Takahashi <torutk@example.com> - modify configure option
例えば、prepセクションで環境変数を定義しても、installセクションでは環境変数を参照しても未定義となってしまいます。セクション毎に別プロセスで実行されているように思います。
Emacsには、rpm-spec-modeがあり、specファイル編集支援機能を使うことができます。
書式
%{?評価するマクロ:式} 評価するマクロが存在(定義済み)であれば、式を展開する %{!?評価するマクロ:式} 評価するマクロが存在しない(未定義)であれば、式を展開する
%if %{hoge} 否定は%if ! %{hoge} 複数条件は%if %{hoge} && %{huga} なんちゃら %else かんちゃら %endif
--short-circuitオプションは、-bcと-biオプションにしか有効でないので、%installセクション実行は完了し、%filesセクションに基づきソース・バイナリパッケージを生成するときにエラーが発生すると、再度ソースの展開からやり直すことになります。
大規模なソースコードのビルドになるほど%filesセクション記述が複雑で誤りが発生しやすいので、その都度ソースからビルドし直すステップが走ると時間と労力の浪費です。
%installsセクションの完了後、%filesセクションの検査を実施しておけば、誤りを未然に発見・修正できます。
-bcと-biオプション以外でも--short-circuitが有効となるように、rpmのソースコードを修正してしまいます。
まず、CentOS 5のミラーサイト等(CD/DVDからでも可)から、rpm-4.4.2-48.el5.src.rpmを取得します。
%buildセクションや%installセクションで、ディレクトリを移動してスクリプトを実行する場合、以下のように記述します。
%build make (cd apps; make)
%prep セクションで環境変数を定義したのに、%buildセクションで環境変数を参照したら中身が空でまるで定義されていないかのようです。どうやら、セクションが異なると環境変数が引き継がれないように見えます。そこで、面倒ですが、各セクションで環境変数を定義します。
%build export PRJ_ROOT=/home/torutk/alfa : %install export PRJ_ROOT=/home/torutk/alfa :
シンボリックリンクを作成する場合、%post、%postunにシンボリックリンク作成・削除の記述をしてはなりません。RPMパッケージをアップデートするとき、RPMの処理としては、最初に新しいバージョンのインストール(rpm -i)を実行し、その後古いバージョンのアンインストール(rpm -e)を実行します。そのため、%postで作成したシンボリックリンクが%postunで消されてしまいます。
また、%postで作成したファイルはパッケージ管理下には含まれないという課題も解決することができます。
そこで、シンボリックリンクのファイルを%installで作成し、%filesにそのファイルを記述します。すなわち、通常のファイルと同じようにインストールされるようにします。
Linuxの初期化スクリプト(OS起動時にランレベルに応じて起動するスクリプト、/etc/rc.d/下に置かれるスクリプト)をインストール時に設定する場合の記述方法です。
Requires(post): chkconfig Requires(preun): chkconfig Requires(preun): initscripts Requires(postun): initscrpits %post /sbin/chkconfig --add hoged %preun if [ $1 = 0 ]; then /sbin/service hoged stop > /dev/null 2>&1 /sbin/chkconfig --del hoged fi %postun if [ $1 -ge 1 ]; then /sbin/service hoged condrestart > /dev/null 2>&1 fi
%preunで [ $1 = 0 ]を評価しているのは、パッケージがアップデートにより削除されるのではなく、真に削除されるときのみを判定するためです。
%postunで[ $1 -ge 1] を評価しているのは、パッケージがアップデートであることを判定するためです。
RPMバイナリパッケージのライブラリファイルはstripされるため、シンボル情報が欠落し、開発・デバッグに不便です。そのときは、RPMビルド時に生成されるdebuginfoパッケージをインストールします。debuginfoパッケージがインストールされていると、gdbは自動でデバッグ版ライブラリとソースコードを参照します。