openSUSE:Spec ファイルのガイドライン

移動先: 案内, 検索
RPM それ自身は非常に制限が少なく、やりたいことのほとんどに対応することができます。そのため、 spec ファイルは複雑化させることもできてしまいます (もちろん、これは他の利用者への配慮が欠けてしまうため、すべきではありません) 。このガイドラインでは、それぞれの領域に対して複雑性を排除し、 spec ファイルのメンテナンス性を向上するための方法を説明しています。

一般的なルール

すべての spec ファイルは可読性に優れるものでなければなりません。他のパッケージ作成者が spec ファイルを読むことができないと、レビューを実施することができず、対話的にパッケージを開発することができなくなってしまうためです。

spec ファイルのテンプレート

何もない状態からパッケージを作成する場合は、 spec ファイルのテンプレートをベースにして作成すべきです (rpmdevtools をご覧ください) 。 MYPACK という名前のパッケージを作成する場合は、下記のようにして作成します。まずは:

[1] osc-plugin-install devel:tools rpmdevtools

もしくは

sudo zypper -p http://download.opensuse.org/repositories/devel:/tools/openSUSE_13.2/ -v in osc rpmdevtools (お使いの openSUSE のバージョンにあわせて変更してください)

を実行し、その後下記を実行します:

cd .../MYPROJECT
osc mkpac MYPACK
cd MYPACK
wget http://upstream.example.org/source/.../MYPACK-1.0.tar.gz
rpmdev-newspec -t lib MYPACK
osc vc
vi MYPACK.spec

あとは、下記のように実行します:

osc build
osc ci
osc in

spec ファイルの書式や構成は必要に応じて変更していただいてかまいませんが、できる限りテンプレートの書式に合わせて記述するようにしてください。テンプレートが spec ファイルを作成するための唯一の正しい方法というわけではありませんが、テンプレートに従って記述することで、 QA (品質保証) チームなどが素早く内容を理解して、問題点を指摘することができるようになるためです。

特定の言語向けの spec ファイルを作成する場合は、 cpanspecgem2rpm-opensuse などのように、専用のツールが用意されている場合もあります。

spec ファイルのエンコーディング

ASCII 以外の文字を利用したい場合、エンコーディングをどれにするのかを気にする必要はありません。非 ASCII 文字を利用する場合は、 spec ファイルを UTF-8 形式で保存してください。 ASCII に属する文字であるかどうかは、 ASCII 文字の一覧図 をご覧ください。

spec ファイルのライセンス表記

法律上の理由により、 spec ファイルにはライセンスヘッダを付けなければなりません。下記のようなテンプレートをお使いください:

#
# spec file for package python-$FOO
#
# Copyright (c) $CURRENT_YEAR $YOUR_NAME_WITH_MAIL_ADDRESS
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.

# Please submit bugfixes or comments via http://bugs.opensuse.org/
#

マクロ

ディレクトリ名は直接記述する (ハードコードする) のではなく、マクロを使用して記述してください (パッケージング規約 RPM マクロ もお読みください) 。なお、 Source:Patch: の行内でのマクロの使用は任意です。マクロを使用しなければ読みやすくなりますし、マクロを使用すればバージョン番号の書き換えなどを一括で行なうことができます。いずれの場合でも、 spec ファイル内ではどちらか一方を採用して一貫性を保つようにし、記述した URL なども正しくなっていることを確認してください。マクロを使用している spec ファイルでマクロの変換結果を得たい場合は、 rpm コマンドで実施することができます。たとえば Source: 行の場合は、下記のようになります:

rpm -q --specfile foo.spec --qf "$(grep -i ^Source foo.spec)\n"

注意: 上記のコマンドは %{name}%{version} などに対しては動作しますが、ユーザ定義のマクロに対しては動作しません。

マクロと RPM 変数

spec ファイルでビルドルートと最適化フラグを指定する場合、下記の 2 種類の方法があります。

マクロを使用した場合 変数を使用した場合
ビルドルート  %{buildroot} $RPM_BUILD_ROOT
最適化フラグ  %{optflags} $RPM_OPT_FLAGS

いずれの値もすべての場合で常に同じ値となるため、どちらを採用するのかは非常に小さな問題です。 spec ファイル全体を通してどちらを使用するのかを決めて、どちらかに統一してください。両方を混在させても問題なく動作しますが、 QA (品質保証) や利用可能性の観点からすると、 openSUSE パッケージで使用すべきではありません。

RPM マクロは、セクションを構成するシェルスクリプトが実行されるよりも前に展開されます。よく知られているとおり、 sh の動作は遅いので、 % で始まるマクロを使用したほうがより高速に動作します。また、 %{_bindir} などのマクロに相当する変数はありませんので、その観点でもマクロの使用をお勧めします。

条件分岐 (古い形式)

User-away-extended.png この記事はバージョン 'このセクションは、 openSUSE で利用している Open Build Service と大きく異なる Koji ビルドシステムを使用した、 Fedora からコピーした内容です。 Koji では spec ファイルと SRPM をアップロードする必要がありますが、 Open Build Service では不要です。そのため openSUSE では本章の意味はありません。' に基づくものであり、現在では内容が古くなっています。
詳細はこの記事のノートを参照してください。

spec ファイル内に、 rpmbuild--with(out) foo のようなパラメータを指定する 条件付きの依存関係 が存在する場合、ソース RPM の構築にあたっては既定のオプションを指定して (つまり rpmbuild に何もオプションを指定しないで) 構築されるべきです。これはなぜなら、これらの要件は直列化されて (条件を指定せずに) 出力 RPM に書き出されるためです。

条件分岐 (新しい形式)

openSUSE:RPM_条件付きビルド をお読みください。

前書き部分

spec ファイルの前書き部分にも、いくつかのルールがあります。

名前/バージョン

パッケージ命名ガイドライン をお読みください。

メタデータのタグ

  • spec ファイルでは Packager タグは使用してはなりません。 RPM パッケージを別のユーザが再構築する際、このタグを書き換えることのないまま実施してしまうことが考えられ、誰に連絡したらよいのかがわからなくなってしまうためです。パッケージ作成者の情報は、 changelog セクション内に記載してください。
  • 同様の理由から、 Vendor タグも使用してはなりません。 Build Service ではこれを自動的に設定しますが、上書きしたい場合は prjconf-level %define を使用してください。
  • Copyright タグは古い形式です。その代わりに License タグを使用してください (詳しくは openSUSE:パッケージングガイドライン#ライセンス をお読みください) 。
  • Source タグで存在しない URL を指定してしまうと、たとえそのファイルがローカルに置いてあったとしても、構築が失敗してしまいます。そのため、ダウンロード用のディレクトリやページについての説明は、コメント欄に記載することをお勧めします。
  • Group タグでは、 openSUSE:パッケージグループガイドライン にあるパッケージグループのみを記載すべきです。
  • BuildRoot タグは、新しい RPM では自動的に上書きされるものの、必ず指定しておくべきです。推奨値は %{_tmppath}/%{name}-%{version}-build です。
  • AutoReqProv タグは既定で on (有効) になっています。そのため、明示的に無効化したい場合にのみ指定する必要があります。

概要 (Summary)

  • 概要はピリオドで終わるべきではありません。文法的な観点ではピリオドを打ちたいところではありますが、ご了解のほどをお願いいたします。
  • 概要はパッケージを短く簡潔に説明するためのものです。 1 行あたり 80 文字で改行されます。
  • 概要はすべての状況下に当てはまるものであるべきで、特殊な場合にのみ当てはまるものを記述すべきではありません。
  • 概要はそれ単独でよくわかるものであるべきです。これはパッケージをアルファベット順に並べた場合であっても、そうでない場合であってもそうあるべきです。
  • 概要はパッケージの主な機能や特長を説明したものであるべきで、これらを読むことで、ユーザ側で類似のパッケージを比較検討できるものであるべきです。たとえば "Web Browser" (Web ブラウザ) の 2 単語だけではなく、追加の形容詞 (例えば "minimalistic" (最小限の機能に絞った), "text-based" (テキストベースの), "fast" (高速な) など) を指定して、パッケージの特色を示してください。

説明 (Description)

説明は概要をより詳しく記述したものです。説明はマニュアルではありませんので、文章内にはインストールの手順を含めてはなりません。対象のパッケージを使用するのに手作業による設定が必要である場合や、ユーザに対して何か特別な手順を示す必要がある場合は、パッケージ内に文書 (たとえば README.SUSE など) を追加して、必要な内容を記載してください。

行の長さは 70 文字まで (テキストモードの YaST における説明ウインドウの横幅) としていた制限は撤廃されています。 Qt のようなフロントエンドと同様に、 yast2-ncurses でパッケージを選択すると、テキストで書かれた説明文からシンプルな HTML が生成され、生成された HTML が表示されるようになっています (これは 2012 年 3 月以降の Factory で修正されています) 。

HTML の特性に注意してください:

空行を記述すると、それは段落として表示されます。箇条書きの場合は、空行はその一覧を終わらせる意味になります。また、改行は 1 文字の空白に変換され、改行の効果はなくなります。それ以外にも、アスタリスク (*) やマイナス (-) 記号と空白で行を始めると、それは箇条書きに変換されます。また、行頭に 2 文字の空白を入れると、箇条書きの続きを記述することができます。

ただし、説明文は適切な分量にとどめてください。特に理由がない限り、 20 行未満に収めてください。

パッケージの説明文は、ユーザが他の類似パッケージをテストすることなく、目的のパッケージを見つけることができるようにするためのものであるべきです。言い換えれば、ユーザに対してパッケージの機能を簡潔に示すための場所であるとも言えます。また機能や他のパッケージとの差異のほか、パッケージの比較などの情報を含むべきです。また、パッケージをインストールすることでユーザの環境に危険を及ぼす可能性がある場合は、潜在的なリスクや副次的な効果も含めて明示的に説明しておくべきです。

概要と説明文については、個人的な好みで記述を決めたりせず、アメリカ英語の言い回しやスペルを利用するようにしてください。また、概要と説明には英語版のみを含めるものとし、 RPM のデータベースを小さくするようにしてください。概要や説明などの翻訳は、 YaST 側で実施します。

従来は説明文の末尾に記していた作者の一覧は、現時点では含むべきではありません (2011 年夏以降) 。作者への敬意を示したい場合は、 AUTHORS ファイルを追加して、その中に記述してください。アップストリーム (提供元) のパッケージに含まれていない場合は、新しく作成して下記のようにして追加します:

Source2:        AUTHORS
...
%setup
cp %{S:2} .
...
%files
%doc AUTHORS

概要や説明における商標の使い方

パッケージ作成者は、概要や説明の文章における商標の使用方法について、注意を払ってください。下記に従うべきルールを示します:

  • "(TM)" や "(R)" のほか、 Unicode で同等の意味を持つ ™, ® などは使用してはなりません。これらを適切に使用するには非常に難しい規約が存在するため、全く使用しないようにするのが最良です。
  • 紛らわしい商標の使い方をしてはなりません。具体的には、 "similar to" (~に似た) や "like" (~のような) などの表現は避けてください。それぞれ悪い例と良い例を示します:
  • 悪い例: It is similar to Adobe Photoshop. (Adobe Photoshop のようなソフトウエアです)
  • 良い例: It supports Adobe Photoshop PSD files, ... (Adobe Photoshop PSD ファイルに対応しています)
  • 悪い例: A Linux version of Microsoft Office (Microsoft Office の Linux 版です)
  • 良い例: A word-processor with support for Microsoft Office DOC files (Microsoft Office の DOC ファイルに対応したワードプロセッサです)

どのような表現を使用すればよいのかわからない場合は、まず自分自身で記述したものを読み直してみてください。誤解を招いたり、パッケージが商標登録済みの商品であると勘違いさせたりする可能性がないか、ご確認ください。何か疑問の部分があれば、商標の表現そのものを削除してください。

依存関係

Requires

RPM には、自動的にライブラリや Perl モジュールなどの依存関係を検出するための、非常に良い機能が用意されています。言い換えれば、車輪の再発明になることはせず、 RPM にお任せください、ということです。たとえば Requires: libqt4 などの形で明示的に依存関係を示す必要はなく、 RPM 側で自動的に共有ライブラリを検出し、依存関係を構築させてください。

なお、お使いのパッケージをサブパッケージに分割したような場合は、 Requires: %{name} = %{version} のように記述して、ベースとなるパッケージをバージョン限定で指定してください。

また、 -devel サブパッケージでは、 devel パッケージがリンクする共有ライブラリとの依存関係を、明示的に記述する必要があります。たとえば libfoobar-devel パッケージの場合、 Requires: libfoo2 = %{version}, libbar5 = %{version} のように指定します。

PreReq

PreReq はインストールの実行時に必要なパッケージを指定します。 pre (事前), post (事後) のインストールスクリプトで必要なものを指定してください。

BuildArch

一般的な用途としては、下記のようなものがあります:

BuildArch: noarch

上記の指定は、パッケージ内のすべてのファイルがアーキテクチャに依存していない場合に行なうべきものです。

なお、メインパッケージが noarch の場合、すべてのサブパッケージも noarch でなければなりません。

BuildRequires

Requires とは異なり、 BuildRequires には自動的に依存関係を抽出する機能がありません。構築を正常に終了させるためには、必要なパッケージを明示的に指定しなければなりません。 BuildRequires を適切に設定することで、開発者やテスターが必要なパッケージを手作業で探す必要がなくなるため、かかる時間を削減することができます。また、これにより、構築処理の再現性を確かなものにできるほか、機能面でも同じものを得ることができるようになります。これはたとえば configure スクリプトなどで、ビルドシステム内に libpng が存在しているかどうかをチェックして、存在していなければその機能を除外するように設定してしまうことがありうるためです。 BuildRequires: libpng-devel (openSUSE 11.4 以降の場合は BuildRequires: pkgconfig(libpng14) を指定することで、 libpng が存在していない場合にエラーとして扱うようにすることができます。

OBS での注意事項

条件付きの BuildRequires は、シンプルな変数に限られます。 RPM では通常の方式として、 %if 表現などで複雑な構築方法を指定することができます:

%if 0%(test "%something" = "enabled" && echo 1)

ただし、 BuildRequires を解釈するにあたって、 Build Service の RPM パーサーはサブシェルの展開が無効化された状態で実行されるため、下記のような警告メッセージが現れることになります:

Warning: spec file parser line 109: can't expand %(...)

%lua スクリプトについても、ディスパッチャは処理を行なわず、警告メッセージも生成されません。

下記は BuildRequires: に条件を指定する場合のシンプルな例です:

%if ! %{with own_mpfr}
BuildRequires: mpfr-devel
%endif
例外

下記のパッケージは非常によく使われるものであることから、 BuildRequires にはこれらのパッケージやこれらが必要としているパッケージを記述する必要はありません。下記は最小限のビルド環境と考えられているためです。

例外パッケージの一覧は、下記のコマンドでも取得することができます:

osc meta prjconf openSUSE:Factory | egrep '^(Preinstall:|Support:|Required:)'


Preinstall: aaa_base acl attr bash coreutils diffutils
Preinstall: filesystem fillup glibc grep insserv libacl libattr
Preinstall: libbz2-1 libgcc%{gcc_version} libxcrypt m4 libncurses5 pam
Preinstall: permissions libreadline6 rpm sed tar zlib libselinux1
Preinstall: liblzma5 libcap2 libpcre0
Preinstall: libpopt0 libelf1 liblua5_1
Required: gcc gcc%{gcc_version} glibc perl rpm tar patch
Support: autoconf automake binutils bzip2 gcc gcc%{gcc_version}
Support: gettext-runtime glibc libtool perl rpm zlib
Support: libncurses5
Support: libaudit1 cpio cpp cpp%{gcc_version} cracklib cvs
Support: file findutils gawk gdbm gettext-tools
Support: glibc-devel glibc-locale groff gzip info less
Support: libbz2-devel libdb-4_8
Support: libstdc++%{gcc_version}
Support: udev
Support: libxcrypt libzio
Support: linux-glibc-devel make man netcfg
Support: net-tools pam-modules patch perl-base sysvinit-tools
Support: texinfo timezone util-linux libmount1 login
Support: libgomp%{gcc_version} libuuid1 psmisc
Support: terminfo-base update-alternatives pwdutils build-mkbaselibs
Support: brp-check-suse post-build-checks rpmlint-Factory
Support: build-compare
Support: libunwind libunwind-devel

Conflicts

openSUSE のパッケージでは、可能な限り互いに矛盾しないようにすべきです。ただし、残念ながらこれは必ず達成できるというものではありません。 openSUSE の矛盾関係ポリシーについては、 openSUSE:パッケージの矛盾関係 をお読みください。

Recommends

SUSE の RPM では Recommends (推奨) タグに対応していますが、ごく最近までこの機能はアップストリーム (つまり RPM の開発元) では提供されていませんでした。そのため、たとえば Fedora_18, RHEL_6, CentOS_6 などに対しては、 Recommends タグを指定するとエラーになってしまいます。下記のようにして、 SUSE 以外のターゲットでは Recommends タグを使用しないようにしてください:

%if 0%{?suse_version}
Recommends: foo
%endif

上記の方法以外にも、 RPM Recommends に対応していないシステムで、 Recommends タグを Requires タグに変換してインストールするように設定することもできます:

%if 0%{?suse_version}
Recommends: foo
%else
Requires: foo
%endif

なお、 openSUSE:Build Service で複数のディストリビューションのパッケージを扱うための手順 もお読みください。

ファイルの依存関係

RPM では、パッケージではなくファイルに対して依存関係を設定することもできますが、 /etc, /bin, /sbin, /usr/bin, /usr/sbin 以外のディレクトリにあるファイルに対しては、依存関係を設定すべきではありません。これらのディレクトリ以外に対してファイルの依存関係を設定してしまうと、 yum (もしくは repomd 形式を使用するその他の依存関係解決ソフトウエア) は巨大な XML ファイルを読み込んで、依存関係を解決しなければならなくなってしまいます。これらの依存関係解決ソフトウエアでは、ファイルではなくパッケージに対して依存関係を設定して、我々およびエンドユーザ側での処理時間を削減しています。また、これ以外にも重要な技術的考慮事項がある場合もあります。よくある例としては、 %{_libdir}/mozilla/plugins 内にインストールを行なうパッケージがあります。この場合、お使いのパッケージ内で特定のブラウザがそのディレクトリを所有するようにすることで、不要なパッケージまでも引き出す結果になってしまいます。依存関係の解決にあたっては、ディレクトリのみを必要とするのがよりよい選択です。

修正 (パッチ)

openSUSE の spec ファイル内での修正 (パッチ) には、直前の行にその状態をコメント形式で記述する べき です。詳しくは パッケージング修正ガイドライン をお読みください。

準備セクション (%prep)

spec ファイルの準備セクションに対しては、下記のようなルールがあります。

%setup での出力抑制

%setup マクロを使用する際には、 -q を指定すべきです。これにより、多数のファイルを抽出するような構築で、ログファイルのサイズを大きく減らすことができるためです。

構築セクション (%build)

spec ファイルの構築セクションに対しては、下記のようなルールがあります。

コンパイラフラグ

パッケージを構築する際のコンパイラでは、システムの RPM 設定に従って適切なコンパイラフラグを設定するようにすべきです。具体的には C, C++, Fortran 言語の場合 %{optflags} (変数では $RPM_OPT_FLAGS) を指定すべきです。システムの RPM 設定に従うとは、パッケージの構築時に使用されるフラグに対して、システム側が指定するものを基本とするということです。もちろん何か良い理由があれば、これらのフラグを追加/上書き/削除してもかまいませんが、そのような場合は spec ファイル内にその理由を記述して、レビューを実施してもらうべきです。

並列処理による make

可能な限り make は下記のように指定します:

%make_build

%make_build は rpm-4.12 またはそれ以降のバージョンで用意されるようになったマクロで、下記のように展開されます:

make %{?_smp_mflags}

rpm 4.12 以前のバージョンで構築しようとしている場合は、上記を直接指定してください (現時点では、 openSUSE 13.2 を含め、ほとんどの場合で上記のようになるはずです) 。

これにより、一般に SMP (対称型マルチプロセッサ) 環境で構築処理を高速化することができます。以前は -jN のようにハードコードするのではなく、 make %{?jobs:-j%jobs} などの形で処理を高速化していたりしていましたが、現在は左記のように指定するのが適切です。ただし、並列処理で構築する仕組みに対応していなかったり、並列処理で構築することで依存関係が壊れてしまったりする場合もありますので、この方法でパッケージが正しく構築できたかどうかはよくご確認ください。

なお、ソースパッケージ側で並列処理で構築する仕組みに対応していない場合は、明示的に -j1 を指定して、そのようなパッケージであることを探しやすくしておくことをお勧めします。また、 -j1 を指定する理由としては、これを指定しないとメモリを大量に使用してしまうという問題もあります (たとえば MINGW 向けに Boost を構築する場合などが該当します) 。 2013 年 9 月の時点では、 build.opensuse.org の汎用ワーカーには 2GB のメモリしか割り当てられていないからです。いずれの場合であっても、 -j1 がどのような意図 (例: 依存関係を壊してしまう、メモリの使用量の問題など) で追加されたものであるのかをコメントとして記述しておくとよいでしょう。

インストールセクション (%install)

spec ファイルのインストールセクションに対しては、下記のようなルールがあります。

rpmbuild は非特権ユーザで動作することから、 `make install` ではファイルの所有権を変更しようとしてはなりません (これは chown を直接実行する場合も、 `install -o root...` でインストールする場合も同様です。ファイルの所有権は、 %files セクションで後から指定してください。

%make_install は rpm-4.10 で利用できるようになったマクロです。これは `make install DESTDIR="%{?buildroot}"` に等価なマクロで、古い rpm (SLE_11 などが当てはまります) では、展開したほうのコマンドをそのまま記述する必要があります。

もう 1 つの方法としては、非常によく似ていて混乱をきたしがちな %makeinstall というマクロがあります (注: アンダースコアのないマクロです) 。こちらの使用は おやめください 。このマクロは、正しくない設定をしているソフトウエアで使用してしまうと、 %buildroot にすべての変数とパスを指定してしまうような非常に長いコマンドを生成してしまうばかりか、 DESTDIR 自身を設定しないため、そのようなソフトウエアではエラーになってしまいます。

たとえば xapian-core-1.2.17 では、下記のように記述されています:

# configure.ac contains:
incdir=$includedir
AC_SUBST(incdir)
# include/Makefile.mk contains:
inc_HEADERS = include/xapian.h

このような環境で %makeinstall の展開を使用すると、 "make install ... includedir=/buildroot/usr/include" のように展開されてしまい、 Makefile は incdir を必要としているにもかかわらず、 includedir にその値を設定してしまい、結果として 意味のない 展開が発生してしまいます。また、 %makeinstall は DESTDIR を設定しないため、 xapian-core は xapian.h を既定の場所 (/buildroot/usr/include ではなく /usr/include) にインストールしようとしてしまいます。もちろんこれもエラーになってしまいます。

SUSE の rpm では、 /usr/lib/rpm/suse_macros で %makeinstall を再定義し、 %make_install と同じ値になるようにしていますが、他のディストリビューションでも同じ spec ファイルを使いまわすことを考えると、 %makeinstall は使用せずに %make_install だけを使用したほうが最適です。

buildroot の削除

openSUSE では、たとえば下記のように %installrm -rf %{buildroot} (または rm -rf $RPM_BUILD_ROOT) を実行するのは 悪いコーディングスタイル であると規定しています:

%install
rm -Rf "%buildroot"
mkdir -p "%buildroot/%_prefix/..." 

or

%install
rm -Rf "%buildroot"
make install

これはなぜでしょうか?

通常、 %{buildroot} は /var/tmp 内に存在するため、このようにしてしまうと、お使いのマシン内に攻撃者が潜んでいる場合、アカウントを奪取するために競合を発生させることができてしまいます (root で構築していれば root を奪取することもできてしまいます) 。 %install 内では、 `rm -rf %{buildroot}` を全く使用しないほうがよいでしょう (%clean でそれを行なったほうがよいでしょう) 。

どうしても内容を削除したい場合は、下記のようにするのがより適切です:

%install
rm -Rf "%buildroot";
mkdir "%buildroot";
mkdir -p "%buildroot/%_prefix/..."

もしくは、下記のようにします:

%install
rm -Rf "%buildroot";
mkdir "%buildroot";
make install

この場合、攻撃者がシンボリックリンクなどで buildroot を置き換えようとすると、 `mkdir %buildroot` は失敗し、構築処理は中断されます。

重要: RPM では、この方法の後始末を自動的に実施できる、ということを覚えておいてください。上記の方法は、手作業で実施しなければならない場合にのみ追記すべきもので、可能であれば完全に削除してしまったほうがよいでしょう。

後始末のセクション (%clean)

%clean セクションを設定すると、これらの処理はバイナリとソースの各 RPM の生成後に実行されます。 Open Build Service では構築時に使用していた chroot 環境や VM 環境を、このセクションの設定とは無関係に削除するようになっているため、このセクションを設定する必要はありません。何もない環境から構築を開始することのできないパッケージは、通常 openSUSE のパッケージとしてはサポートしていません (bnc#176528 の comment 4 をお読みください) 。

rpm-4.7/openSUSE_11.3 またはそれ以降のバージョンでは、 spec ファイル内に %clean セクションが全く存在しない場合、 "%clean: rm -Rf %{buildroot}" が設定されます。

また、ずっと昔の話ではありますが、パッケージによっては %clean%{buildroot}/ であるかどうかを確認し、そうでない場合にのみ削除するようになっていましたが、現在の openSUSE ではこのような仕組みを作る必要はありません。

スクリプトレット (%post* / %pre*)

spec ファイルのスクリプトレットのセクションについてもルールがあります。スクリプトレットを使用するにあたっては、特に注意を払ってください。スクリプトレットを使用した場合、それらは良識のあるものでなければなりません。一般的なスクリプトレットについては、 openSUSE:パッケージングスクリプトレット例 をお読みください。

スクリプトレットの要件

spec ファイル内では、スクリプトレットを実行するのに必要なパッケージをすべて記述する必要があります。それぞれ下記のようにして指定してください:

Requires(pre): ...
Requires(post): ...

スクリプトレットからアクセスできるディレクトリ

パッケージの構築スクリプト (%prep, %build, %install, %check, %clean) は、 %buildroot 以下や %_builddir 以下、および /tmp, /var/tmp (または rpmbuild のプロセスが設定する $TMPDIR or %_tmppath) にあるファイルのみを書き換える (作成/修正/削除) ことができます。下記の表をご覧ください:

/tmp, /var/tmp, $TMPDIR, %_tmppath  %_builddir  %buildroot
%prep はい はい いいえ
%build はい はい いいえ
%install はい はい はい
%check はい はい いいえ
%clean はい はい はい

注意: 構築者の uid とは関係なく上記のとおりになります。

ファイルセクション (%files)

spec ファイルのファイルセクションにもルールがあります。 openSUSE ではファイルシステムのレイアウトについて、 Filesystem Hierarchy Standard に従うことにしています。 FHS ではシステム内のどの場所にどのファイルを配置するのかを規定しています。 FHS から逸脱するファイルについては、 spec ファイル内にコメントで理由を説明してください。

所有権

パッケージを作成する際は、 %install の処理でインストールされるすべてのファイルを所有するように設定すべきです。また、他のパッケージが所有しているファイルを所有してはなりません (もしも他のパッケージとファイル名が競合する場合は、 Conflict: タグを指定すべきです) 。大雑把にいうと、インストールすべき最初のパッケージが、他のパッケージから必要とされるファイルを所有すべき、ということです。他のパッケージがファイルなどを所有したほうがより適切であるとお考えの場合は、パッケージのレビューの時点でその旨をお知らせください。

ディレクトリの所有権は、ファイルの所有権よりも少し複雑です。ですが、大雑把なルールは同じで、パッケージが作成するディレクトリすべてを所有すべきではあるが、依存しているパッケージのディレクトリは所有しない、ということです。複数のパッケージがディレクトリを所有する場合の例としては、以下のようなものがあります:

  1. ディレクトリを提供するための依存パッケージが、将来のバージョンで異なるディレクトリを所有するようにすることがあり、その将来のバージョンは、お使いのパッケージを修正することなく動作するものとします。よくある例としては Perl のモジュールがあります。 perl-A-Bperl-A に依存していて、 /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi/A/B というディレクトリにファイルをインストールします。ベースとなる Perl のパッケージは、バージョンが 5.8.8 である限りは /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi を所有していることが保証されますが、将来のアップグレードでは、 perl-A/usr/lib/perl5/vendor_perl/5.9.0/i386-linux-thread-multi/A にファイルをインストールし、所有するようになる場合が考えられます。その場合、 perl-A-B は適切な所有権を維持するため、 /usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi/A/usr/lib/perl5/vendor_perl/5.8.8/i386-linux-thread-multi/A/B の両方を所有する必要があります。
  2. また、複数のパッケージに汎用的なディレクトリがあるものの、いずれもそれらを必要としていない場合。たとえば下記のような場合が考えられます:
Foo-Animal-Emu が /usr/share/Foo/Animal/Emu にファイルを配置し、
Foo-Animal-Llama が /usr/share/Foo/Animal/Llama にファイルを配置する場合。

いずれのパッケージもお互いに依存した関係ではなく、いずれのパッケージも /usr/share/Foo/Animal を所有しているパッケージに依存していないものとした場合、両方のパッケージが /usr/share/Foo/Animal ディレクトリを所有しなければなりません。

いずれの場合であっても、システム内に誰も所有していないディレクトリが残らないように管理されています。詳しくは パッケージング/誰も所有していないディレクトリ をお読みください。

また、 openSUSE では %files 内に記載したファイルが重複してはなりません。これは 1 つのファイルが 2 つ以上のパッケージ (サブパッケージを含む) に書かれていてはならないという意味のほか、内容についても重複していてはなりません。 %fdupes %buildroot (BuildRequires: fdupes を追加する必要があります) を実行することで、内容が重複するファイルを検索し、必要であればハードリンクに置き換える処理を行なうことができます。

パーミッション (アクセス許可)

ファイルのパーミッションは適切に設定しなければなりません。たとえば実行ファイルには実行可能なパーミッションを設定すべきですし、 %files セクションには %defattr(...) の行を含めなければなりません。たとえば下記のような既定値があります:

%files
%defattr(-,root,root)

上記のルールを逸脱するのに十分な理由がある場合を除いて、 spec ファイル内のすべての %files セクションで %defattr(-,root,root) を指定しておくべきです。なお、たとえば展開時に umask が厳しく設定されすぎているような場合は、 %defattr(-,root,root,0755) のように指定すると、ディレクトリの問題を修正することができます。

SUID ビット

openSUSE では、セキュリティ関連のパーミッションを /etc/permissions* で制御します。 基本的な仕組みについては、 /etc/permissions* にあるファイルをお読みください。

suid ビット付きのファイルがあるパッケージを作成したい場合は、下記のルールに従ってください:

  • まずは何よりも、本当に suid ビットが必要かどうかを検討してください。通常、 setuid ビットを設定するとセキュリティ面での危険が増すことになりますので、よく考え抜いて設計し、設定する必要があります。
  • spec ファイル内に Requires(post): permissions というヘッダを追加してください。
  • %files セクションでは、 permissions.secure 内で設定するのと同じパーミッションを設定してください。また、 rpmverify で所有権やパーミッションをチェック しない ようにしてください。
  • %post スクリプトレット内では、システムのセキュリティレベルに合わせてパッケージのパーミッションを設定するようにしてください。
  • %verifyscript スクリプトレット内でも、同様にシステムのセキュリティレベルに合わせてパッケージのパーミッションを設定するようにしてください。


上記の説明では理解しやすいとは言えませんので、下記に例を示します:

[...]
PreReq:         permissions
[...]

%if 0%{?suse_version} >= 1120
%verifyscript
%verify_permissions -e %_bindir/mysuidprogram
%endif

%post
%if 0%{?set_permissions:1}
    %set_permissions %name
%else
    %run_permissions
%endif

%files
%defattr(-,root,root)
[...]
%verify(not user group mode) %attr(0711,root,root) %_bindir/mysuidprogram
[...]

新しく setuid ビットを設定するプログラムを作成し、 openSUSE ディストリビューション内に含めてもらいたいとお考えの場合は、パッケージを SUSE セキュリティチーム にレビューしてもらわなければなりません。 security-team@suse.de を割り当ててバグ報告を行なうか、もしくは security@suse.de 宛にメールでご連絡ください。


home プロジェクト内で一時的にビルドしたい場合は、下記を実施してください:

  • /etc/permissions.d/ 内にファイルをインストールするようにし、そのファイル内でパッケージ固有のパーミッションを設定してください。
  • お使いのパッケージに合わせて permissions{,.easy,.secure,.paranoid} ファイルを作成してください。 permissions ファイルは、システムの現在のセキュリティ設定に合致する permissions.* ファイルが存在しない場合に使用されます。大雑把にいうと、 permissions.easy には make install でインストールされるものと同じパーミッションを、 permissions.paranoid にはすべての suid ビットを削除したパーミッション (機能性を損なう場合でも構わず削除してください) を、 permissions.secure にはそれらの中間的なパーミッションをそれぞれ設定すべきです。
  • これらのパーミッションファイルを spec ファイルのソースとして含め、 %install では %buildroot/%_sysconfdir/permissions.d/パッケージ名[.接尾辞] にインストールするように指定してください。
  • rpmlint からパーミッションファイルが禁止されている旨のエラーメッセージが表示されないようにするため、 パッケージ名-rpmlintrc というファイルを作成して、 setBadness('permissions-unauthorized-file', 333) のような行を記入したあと、 spec ファイル内で Source に指定してください (パーミッションファイルが 3 つではない場合は、 "333" を適宜修正してください) 。

これらの回避策は、 openSUSE ディストリビューションに送信する前に実施しておいてください。

ドキュメンテーションファイル

ソースコード内に同梱され、関連するドキュメンテーションは、いかなるものであってもパッケージ内に含めるべきです。一般的な構築手順が示されている INSTALL ファイルなどや、 Linux 以外のシステム向けのドキュメンテーションである README.MSDOS などは、いずれも関連しないものになります。また、サブパッケージに分割するような場合は、どのサブパッケージに含めるべきかも注意してください。たとえば API のドキュメンテーションなどは、メインのパッケージではなく -devel パッケージ内に含めるべきです。また、ドキュメンテーションが多数存在するような場合は、ドキュメンテーションだけのパッケージに分割するようにしてください。この場合、サブパッケージの名前は *-doc とし、 Group タグには Documentation を指定しておくことをお勧めします。

また、 spec ファイル内に %doc が書かれているファイルがある場合は、これらのファイルはアプリケーションの実行に影響してはなりません。言い換えれば、 %doc に書かれたファイルが存在していなくても、プログラムは正しく動作さなければなりません。

設定ファイル

設定ファイルはパッケージ内で適切にマーキングされなければなりません。大雑把にルールを説明すると、何か特別な理由がある場合を除いて、単に %config と指定するだけではなく、 %config(noreplace) を使用して指定してください。このように指定することで、パッケージのアップグレード時に設定ファイルを上書きしてしまう問題を解決することができるためです。 noreplace を指定 しない 特別な理由としては、たとえばパッケージ作成者の設定ファイルが変更され、新しいパッケージリビジョンでは以前のパッケージリビジョンのものが動作しない場合などがあります。いずれの場合であっても、 %config (noreplace 無し) を指定する場合は、 spec ファイル内で理由を説明してください。

また、 /usr 以下のディレクトリのファイルに対して %config%config(noreplace) を指定してはなりません。これは openSUSE において、 /usr は設定ファイルを配置する場所ではないためです。

開発用ファイル

パッケージ内に含まれているファイルのうち、もっぱら開発目的で使用するファイルについては、それらを -devel サブパッケージに含めるようにしてください。 -devel サブパッケージに含めるべきファイルとしては、たとえば下記のようなものがあります:

  • ヘッダファイル (.h ファイル)
  • バージョン番号無しの共有ライブラリ (例: libfoo.so) 。バージョン番号のついた共有ライブラリ (例: libfoo.so.3, libfoo.so.3.0.0) については、 -devel パッケージに含めるべきではありません。
  • pkgconfig ファイル。パッケージ自身が開発ツールである場合 (例: gcc, gdb など) は、例外としてメインパッケージに含めてください。

pkgconfig (.pc) ファイルを含むパッケージでは、 BuildRequires: pkg-config を指定しなければなりません。これにより、適切なランタイム依存関係 Requires: pkg-config が追加されます。

言語ファイル

openSUSE では、 %find_lang と呼ばれる rpm マクロが用意されています。このマクロは、パッケージに属するすべての言語ファイルを検出して、その一覧をファイルに書き込むことができます。これにより、すべての言語をまとめることができます。 %find_lang は spec ファイルの %install セクション内において、 buildroot 内にすべての言語ファイルをインストールしたあとに実行すべきものです。 %find_lang マクロを使用することで spec ファイルをシンプルにまとめることができるほか、パッケージ作成時のミスを防ぐことにもつながります。

  • すべての言語ファイルを一括で指定する目的で %_datadir/* を使用してしまうと、言語ディレクトリそのものの所有権も握ってしまいます。これは許可されていない方法です。
  • 多くのパッケージが多数の言語に対応していますが、下記のように指定するのではなく、 %find_lang と書いたほうが、 spec ファイルをシンプルにすることができます:
%_datadir/locale/ar/LC_MESSAGES/%name.mo
%_datadir/locale/be/LC_MESSAGES/%name.mo
%_datadir/locale/cs/LC_MESSAGES/%name.mo
%_datadir/locale/de/LC_MESSAGES/%name.mo
%_datadir/locale/es/LC_MESSAGES/%name.mo
...
  • パッケージのリビジョンが新しくなって新しい言語が追加された場合でも、 %find_lang は実行時に自動的にそれらを含むようにすることができます。そのため、 spec ファイルを修正する必要はありません。
  • %find_lang で検出した言語ファイルをパッケージに含めるには、 %files セクションで -f %{name}.lang オプションを指定します。セクションヘッダは下記のようになります: %files -f %{name}.lang

ASCII 以外の文字を利用するファイル名について

ファイル名に ASCII 以外の文字を含めたい場合は、それらを UTF-8 でエンコードする必要があります。ファイル名そのもののエンコーディングを記述する方法は無いので、ユーザ側でファイル名を正しく表示させるためには、すべてのファイル名で同じエンコーディングを使用するのが適切であるためです。アップストリーム (提供元) が UTF-8 以外の方法でエンコードしている場合は、 convmv (パッケージ名: convmv) のようなユーティリティを利用して、 %install セクション内でファイル名を変換してください。

libexecdir

GNU ビルドシステム (autotools) では "libexecdir" 変数/オプション を提供していて、 "ユーザではなく、他のプログラムが実行するプログラムをインストールする" 場所を指定することができます。場合によっては、パッケージ側の判断により、 Automake ファイル内で ${pkglibexecdir} という便利な事前定義変数で使用するため、 libexecdir 内にサブディレクトリを作成することがあります。パッケージによっては、 Makefile.am 内で "pkglibexec_PROGRAMS = myhelper" のように指定している場合もあります。

ただし、 Filesystem Hierarchy Standard では libexecdir に対する規定はなく、 (open)SUSE では、 rpm パッケージからの %_libexecdir 指定は、 /usr/libexec ではなく /usr/lib に展開されるようになっています。

Changelog セクション (%changelog)

詳しくは 良い changes の書き方 をお読みください。zh:openSUSE:Specfile_guidelines