RPM で LSB 準拠プリンタドライバのパッケージを作ってみた (その2: 実践編)
えー、前回 (d:id:naruoga:20090706:1246858558) で長々と能書き&下準備を垂れましたので、次はいよいよ実践編。
とその前に書き忘れ。まあ大抵の人には今更のことですけど。
RPM 概略
RPM とは Redhat Package Manager の略だったんだけど、今は RPM Package Manager と名前が変わっております。
三つの材料、
- 元々のプログラムをビルドするためのソース
- それを特定環境のパッケージに併せるためのパッチ
- それらのビルドやインストール、前処理、後処理を記述した SPEC ファイル
を用意して、rpmbuild というソフトで加工するとうりゃっと出来上がるわけです。
しかしオイラ的には、
- SPEC ファイルが外部ファイルからのマクロ読みまくりなので環境依存しちゃってわけ分からん
つーところが何よりいやなのと、Debian の DEB みたいに
- 実態は単なる tarball なので解いて内容を確認するのが簡単
- 依存関係のミス、設定ファイルの書き間違いなどをチェックする機構を有している
- パッケージソースがそれで閉じているので誰が作っても同じパッケージになることが保証される
って筋がイイコを見てるともーヤんなるわけですよ。
つか SPEC ファイル最悪。説明なしでマクロとか使いすぎ*1。
それでも LSB の標準は RPM であって DEB ではないのです。
なんで? というと「RPM → DEB は alien で可能だけど、逆は不可能だから」って理由らしい。トホホ。
まあ愚痴っていてもしょうがないので RPM を作ってみましょうそうしましょう。
パッケージの準備……をしようと思ったら。
今回は Postscript の PPD だけという一番単純な作りにしましょう。
そうすると PPD とそれ以外に必要なのは COPYING と README ぐらいでしょう。
これをどんな風にすべきか……が……いかなるドキュメントを読んでもさっぱりわかりません ;><
オイラの頭が悪いんでしょうか?
ということでまずは見捨てて SPECS を書くことにします。
SPECS 書き書き
もちろん前述のドキュメントには SPECS の書き方はばっちり書いてあるのですが、こんなのパクった方がはえーよ、ということでドキュメントにもパクリ元が提示してあるのでありがたーくいただいておくことにする。
Postscript 用の PPD のみで構成されているパッケージであればまぁどれでもよいでしょうから、openprinting-ppds-postscript-xxx.specs というファイルをなんか適当に選んで、
$ mv openprinting-ppds.postscript-xxx.specs ~/tmp/my-ps-ppds.specs
とかなんとかしてください。
まずはプロローグ
さて元ネタがあればわかりが早い。
まずはプロローグ。
Summary: PPD files for hogehoge Postscript printers Name: hogehoge-ps-ppds version: 20090626 Release: 1lsb3.2 License: MIT Group: Applications/System URL: http://your.url/
ここは別に動き的にどーとかいう話じゃないので、自分のパッケージングルールにしたがって決めればいいと思います。
強いて言えば Group: の Applications/System はドライバパッケージの場合は決めうちです。
バージョンやリリースについてもやはりそれぞれの事情があると思いますが、対応 LSB バージョンはどこかに入れておいた方がよいと思います。私の例では Release に入れました (つかサンプルのパクリ)。
各種名称定義
お次は実際の処理のなかに出てくる文字列を定義します。
%define drivername hogehoge-ps %define extraversion %nil %define driverstr hogehoge-ps %define supplierstr hogehoge %define supplier hogehoge %define ppdnickname , %{driverstr} %{version}%{extraversion} (%{supplierstr} LSB 3.2)
注意すべきなのは、ここで出てくる supplier という文字列が最終的に ppd がインストールされる場所 /opt/
あと ppdnickname はまるぱくりで構わないと思います。DI-Package では PPD の *NickName をこの情報で上書きするようになっている。たとえば、
Original: 「Hogehoge PS B/W」
↓
Modified 「Hogehoge PS B W, Hogehoge-PS 20090626 (Hogehoge LSB 3.2)」
のように。この *NickName は CUPS やデスクトップが提供する PPD 選択画面で用いられます。ので、ここでも LSB バージョンは明記するようにしましょう。
パッケージ情報
パッケージの依存関係やパッケージの構成要素などなどの情報を書きます。さっき挫折したパッケージのコンテンツの格納方式がわかるかも?
BuildRequires: lsb-build-cc, lsb-build-c++, lsb-appchk BuildRequires: perl, gzip, cupsddk Requires: lsb >= 3.2 Source0: hogehoge-ps-ppds-%{version}.tar.gz Source1: hogehoge-ps-ppds-%{version}.README_ja.htm Source2: hogehoge-ps-ppds-%{version}.COPYING BuildRoot: %_tmppath/%name-%version-%release-root BuildArch: noarch
今回は繰り返すように ppd のみなので BuildArch が noarch なのがミソ。もしバイナリの場合はそれなりにかかないとダメです。コイツについては後日談があるのでそれは後ほど。
問題は……ここで Source0 に指定されている PPD の tar.gz ファイルのファイル構成がまるっきりこれっぽっちも分からないこと。どのドキュメント見てもわかんない。えーん (T_T)
ということでこれはまあ後回しということにして。←いいのか?
Source1、Source2 は COPYING と README ですが、これは各ドライバで違うでしょう。がまあ例なのでこれはこれで。
Description
これはパッケージがどういうものかの説明をするものなのでちゃんと書きましょう。一行目は最初の Summary と併せておいた方がいいと思います。
%description PPD files for hogehoge Postscript printers This packages includes PPDs for hogehoge Postscript Printers/MFPs, ...
以下ビルドプロセス
ここは結果的にはサンプルからのコピペですみました*3。
ミソは %install_into_opt で、これは下準備編で /etc/rpm/macros に記述したもの。これを書いておくとあら不思議、PPD やドキュメント類が先ほど定義した supplier にインストールされるというもの。Distribution Independent Package on LSB を作るときには必ず先頭に入れましょう。
パッケージ記述は次のようなセクションに分かれます。
セクション | 意味・注釈 |
%prep | ビルド前の下準備などなど。Source で指定されたソースを解いたり Patch を当てたり。ポイントは Source の指定を解決する %setup マクロ。こいつがすべて悪いのだ*4。 |
%build | ビルド。noarch な RPM の場合はビルドが発生しないのでからっぽ。 |
%install | ビルドでできたオブジェクトをインストールする。今回のパッケージの場合にはコメントにも書いてあるとおり %adjust_ppds というマクロの呼び出しが必須。なおドキュメント系は思い切り手書きで処理しております。 |
%pre | インストールの前処理の記述。ここでは /opt 以下に適切なディレクトリを掘るマクロ %create_opt_dirs を呼び出しているだけ。 |
%post | インストール後の処理。ここでは少し分かりにくい処理をしているので後述します。 |
%preun | アンインストールの前処理。このパッケージではやることがないのでセクションごと存在しない。 |
%postun | アンインストール後の処理。これも後述 |
%clean | rpmbuild でビルド環境を綺麗にするときに。 |
%files | パッケージにあるすべてのファイルのリストを記載する……ってことですが、サンプルからの丸コピで動いてますので多分それで大丈夫。 |
では各セクションごとに説明しましょう。
[%prep]
# Packaging settings %install_into_opt %prep # remove old directory rm -rf $RPM_BUILD_DIR/%{name}-%{version}%{extraversion} mkdir $RPM_BUILD_DIR/%{name}-%{version}%{extraversion} %setup -q -T -D -a 0 -n %{name}-%{version}%{extraversion}
%prep の前にある %install_into_opt というのは /etc/rpm/rpmmacros で定義されたマクロであり、一見ここで PPD の opt へのインストールを行うように見えますが、実際は後ほどのインストール処理でインストール先を /opt に向けるためのマクロです。
%prep の処理の rm と mkdir は特に問題ないが、%setup は特徴的なマクロなので紹介しておきます。
%setup は %prep でよく使われるマクロで、RPM 作成パッケージの一部として供給されています。以下 JF-Project のサイト http://www.linux.or.jp/JF/JFdocs/RPM-HOWTO-6.html より解説を引用します。
引数 | 意味 |
-n {name} | 列挙された name に作成ディレクトリの名前をセットします。デフォルトは $NAME-VERSION です。他の可能性として $NAME、 ${NAME}${VERION}、メインの tar ファイルが用いているものです。 (これらの "$" 変数は spec ファイル中の本当の変数でない事に注意して下さい。これらは参考のためにここで使われたものです。実際には変数ではなくパッケージ中の本当の名前とバージョンを使う必要があります。) |
-c | tar ファイルを解凍する前に名付けられたディレクトリを作りそこに cd します。 |
-b # | ディレクトリに cd する前に Source# を 解凍(untar)します。 (これは -c オプションと一緒に用いるのは意味がありません、しないで下さい。) これは複数のソースファイルがある時のみ役に立ちます。 |
-a # | ディレクトリに cd した後に Source# を解凍(untar)します。 |
-T | このオプションはソース解凍(untar)のデフォルト動作を無効にします。解凍(untar)されたメインのソースファイルを得るために -b 0 もしくは -a 0 を必要とします。2つめのソースがある時にこれを必要とします。 |
-D | 解凍する前にディレクトリを消去しません。これは setup マクロが複数ある時のみ有用です。最初の setup マクロの後の setup マクロでのみ使うべきです。(決して最初の setup マクロで使わないで下さい。) |
-q | ソース解凍時の経過表示を無効にします。 |
ということで、この指定は
「%{name}-%{version}%{extraversion} に CD して
Source0 だけを untar して
残りは手つかずで
解凍前にディレクトリは削除せず
untar の経過表示は行わない」
という意味になります。
[%build]
%build # Nothing to build
再三繰り返してきたとおり noarch の RPM ではビルド行程が存在しないので、単純にコメントでその旨を書いているだけです。
[%install]
%install rm -rf %{buildroot} # Make directories install -d %{buildroot}%{_cupsppd} install -d %{buildroot}%{_docdir}/ricoh-basic-ps-ppds cp -r ppds/* %{buildroot}%{_cupsppd}/ chmod -R u+rwX,go+rX %{buildroot}%{_cupsppd} # Rename PPDs appropriate to LSB agreements and compress the PPD files %adjust_ppds cat %{SOURCE1} > %{buildroot}%{_docdir}/ricoh-basic-ps-ppds/README_ja.htm cat %{SOURCE2} > %{buildroot}%{_docdir}/ricoh-basic-ps-ppds/COPYING
見たとおりの意味であるので細かい説明は省略しますが、%adjust_ppds は上記のコメントに書いてあるように、LSB 準拠に PPD 名称をリネームして、gzip するためのマクロでです。ここで必ず呼ばなければなりません。
なお末尾の二行の cat は単にドキュメントを作成しているだけでです (リネームしてコピーなので単に cp でも良いはずです)。
[%pre, %post, %postun]
%pre %create_opt_dirs %post %set_ppd_links %update_ppds_fast %restart_cups %postun %not_on_rpm_update %remove_ppd_links %restart_cups %end_not_on_rpm_update
%pre では %create_opt_dir マクロで /opt の下にディレクトリを作成します。
%post では次の三つの処理を行います。
- まず %set_ppd_links というマクロで %{_cupsppd} フォルダにインストールされた PPD から /opt にリンクを張ります。
- それから、%update_ppds_fast で、すでにプリントキューに使用されている PPD を上書きした場合、それを入れ替える処理を行います。
- 最後に、%restart_cups で cups デーモンをリスタートします。
%postun では %post の逆とも言える処理を行います。ただし、%postun は RPM のアップデートのときにも呼ばれるセクションですので、アップデート時には不要な処理をバイパスする %not_on_rpm_update / %end_not_on_rpm_update で囲ってあります。
- %remove_ppd_links というマクロで %set_ppd_links で張られたリンクを切ります。
- %restart_cups で cups デーモンをリスタートします。
[%clean]
%clean rm -rf %{buildroot}
名前の通り rpmbuild で clean を指定したときの処理です。
[%files]
%files %defattr(-,root,root) %if %{optinstall} %{_prefix} %else %{_cupsppd} %endif %docdir %{_docdir}
RPM パッケージを構成するファイルです。noarch の (PPD のみの) DI-Package では上記 (サンプルどおり) をそのままマネすれば大丈夫です。
Sources 再び
さてと SPECS は書けたっぽいので、今度こそ Sources に挑みましょう。
COPYING と README は単純にファイル名変えるだけなので、問題は PPD だ。
これを「PPD はこうやって配置するから、あなたは tar.gz をこう作って」ってドキュメントがどこにもねーのよ。あなた。いや私の目が節穴である可能性は否定しないけど。
それが素直にシェルスクリプトかなんかで書いてあればいいけど、わけの分からないマクロの山なので皆目わかりません。あーやだやだ。
ということで論理的アプローチをかなぐり捨てて試行錯誤だ。
まずは PPD そのままにするか、gz 圧縮をするかどうかですが、SPECS をぼーっと見てる限りでは gz 圧縮するのはやってくれるんじゃないかなーって気がしました。いや根拠レスです。
そうするとあとはディレクトリ構造ですが、
- 掘らない
- /opt 以下
- /opt/
以下
の三択かなと。で、わざわざ %install_into_opt なんてマクロ書いてくれてるぐらいだから*5 ディレクトリ掘らないで *.tar.gz 作ってみたさ。
さて実行! えい!
うむ。%build 直前まではうまく行く。しかし %install でコケる。
なんだかしかも %{buildroot} に x86_64 なんて文字があるじゃーないか。あれえっ? BuildArch 効いてない? じゃあ --target=noarch で。くそっ。だめだっ。なんでなんでなんで?
いろんな文献読み漁ったりぐぐったりすること2時間。
くたびれてエラーメッセージに戻ってきて、よくよく見ると……ん?
これ、%{buildroot} のパスに .../optppds/... 入れば万事解決じゃね?
ということで optppds/ 以下に PPD を配置する形で *.tar.gz を作ったら成功!
インストールもうまくいった!*6
alien による DEB パッケージの生成も大丈夫でした。
まとめ
苦労しましたが分かってしまえば簡単でした。
SPECS の書き方のなかで、OpenPrinting で定義したマクロについてはドキュメントがかなり丁寧に書いてあるので、noarch のパッケージの SPECS を書くのは特に難しくないと思います。
Sources の tarball はハマりました。%setup の説明ってどこかにちゃんとまとまってるんでしょうか ;>< 結局どのマクロがどういう動きをして最終的にファイルがどう配置されるのかとかそういうのが全然わからなくて(これはドキュメンテーションの問題も大きいと思う)そこがつらいなーと感じました。
ちょっと SPECS の %setup マクロについてはまた勉強しよ。
どうせ次には noarch じゃないパッケージを作るお稽古するんだし。