openSUSE:共有ライブラリパッケージングポリシー

移動先: 案内, 検索


このガイドラインは、通常であれば /%_lib/usr/%_lib (%_libdir) にインストールされる共有ライブラリを含むパッケージについて、その命名規則を示しています。このガイドラインは、主に 2 つ以上の (互換性のない) バージョンの共有ライブラリ (例えば libfoo.so.1libfoo.so.2) を、 RPM の矛盾を生じることなく個別に選択して同時にインストール (かつ RPM で追跡できる) ような場合を想定しています。

根拠

この方法を利用することで、 RPM パッケージマネージャを利用して同じ名前で異なる SO バージョン (共有オブジェクトのバージョン) の共有ライブラリをインストールすることができるようになります。従来 (10.3 以前) はライブラリに対してただ 1 つのバージョンのみが構築され出荷されてきましたが、 SO のバージョンが変更された場合、それに依存するすべてのパッケージも更新する必要がありました。これは特に、ディストリビューションとは異なる場所で開発されているパッケージで、まだ新しいバージョンには対応できていないものがあったりすると、問題になっていました。

下記のような名前付けとパッケージングに関するガイドラインでは、それぞれのバージョンのライブラリは個別にインストールすることのできる実体として定義され、共存することができるようになります。

下記のガイドラインを遵守することで、他のバージョンの libfoo*.rpm をインストールした場合でも、ファイルの競合を発生させずに共存できるようになります。そのため、パッケージ内には lib*.so.* だけを含めることができることになります。また、共有ライブラリが勝手に変わってしまうようなことをなくすため、これらのルールに従っていないパッケージは、どのようなものであっても禁止しています。

実際のところ、このルールは共有ライブラリとそれ以外を分離するような仕組みになっていて、両方を含むパッケージが無いようにもしています。

バージョン番号の設定方法

バージョン番号は、互換性が維持されない方法で ABI が削除されたり変更されたりした場合に、異なる SONAME を付与する、というのが基本原則です。

$ readelf -a /usr/lib64/libHX.so | grep SONAME
0x000000000000000e (SONAME)             Library soname: [libHX.so.28]

SONAME の項目がない場合、ファイル名それ自身から SONAME の値を取り出します。

SO のバージョン (および一般的には SONAME の) 番号については、特に制限はありません。一般的には 1 つもしくは 3 つの整数を並べ、 libfoo.so.1libfoo.so.1.0.0 のような形式を採用しています。ただし、ソフトウエアの開発者は必ずしもこのようなやり方に従う必要はなく、技術的には任意の文字および表記法を利用することができます。

libtool の使用

多くのパッケージは libtool の考え方を採用していて、 libtool マニュアルページのバージョニングの項 にも示されているとおり、インターフェイス番号と呼ばれる仕組みを利用します。これらは Makefile 内の -version-info-release で指定されています。開発者やパッケージ作成者に対しては、プラットフォームごとに異なる方式でファイル名が付与されることに注意する必要があります:

-version-info c:r:a 最古のI/F 最新のI/F Linux FreeBSD Windows
7:0:0 7 7 libfoo.so.7.0.0 libfoo.so.7 libfoo-7.dll
8:0:1 7 8 libfoo.so.7.1.0 libfoo.so.8 libfoo-8.dll
9:0:2 7 9 libfoo.so.7.2.0 libfoo.so.9 libfoo-9.dll
9:0:1 8 9 libfoo.so.8.1.0 libfoo.so.9 libfoo-9.dll
9:0:0 9 9 libfoo.so.9.0.0 libfoo.so.9 libfoo-9.dll

このような仕組みであることから、 SO の番号を勝手に変更したり、 c:r:a の値を変えてしまったりしてはならないことになります。また、勝手に変更してしまうと、インターフェイス番号の考え方を無視していることにもなります。

手動による上書き

ごく少数ではありますが、ソースパッケージによっては SO の番号を直接指定したいような場合もあります。このような場合も libtool の -version-number を利用したいと考えるところですが、このような場合は 使用すべきではありません 。不明瞭な方法で c:r:a を設定したり変更したりしてしまうと、避けられないエラーが発生してしまうためです。

libtool のマニュアルでは、このような指定は推奨していません (引用: "New projects should use the -version-info flag instead." (新しいプロジェクトでは、代わりに -version-info フラグを使用すべきです)) 。このオプションが廃止予定というわけではありませんが、移植性を考慮して使用しないことをお勧めします。

バージョンがない場合

ソースパッケージによっては、下記のような理由でバージョン番号を付与しない場合があります:

  1. ソースコード側では共有ライブラリの構築に関するサポートが全く行なわれておらず、ディストリビューションのパッケージ作成者が独自に付与しなければならない場合
  2. 提供元がバージョン番号について注意を払っておらず、異なるリリースで ABI 側に変更があるにもかかわらず、同じ SONAME を (もしくは SONAME の指定なしで) 生成するように作られている場合
  3. 提供元が特定のリリースで番号を更新し忘れたような場合

このような場合は、 libtool のマニュアルにも記述されていますが、名前の中にパッケージバージョンを追加してしまうのが最も安全な方法となります (libtool を使用してもしなくてもかまいません) 。たとえば libfoo.so というファイル名であった場合は、 libfoo-2.5.0.so (パッケージバージョン 2.5.0 の場合) のようになります。このような方法で付与されている著名な例としては、 bintuils の libbfd (/usr/lib(64)/libbfd*.so) などがあります。

このような方法を利用する場合、可搬性を維持するための他者との調整は不要です。

パッケージの名前付け

ライブラリの名前、特に SONAME は、 バージョン番号付きのパッケージ名 を作成するためのベースとして使われ、複数のパーツから構成するのが一般的です (もちろんすべてが必須というわけではありません) 。たとえばすべての要素を含んでいる libfoo-bar-2.5.so.8.2.1 という例では、下記のパーツに分解することができます:

  • 一般的なシステム接頭辞: lib
  • ライブラリの名前: foo-bar
  • パッケージバージョン (任意): -2.5
  • 共有ライブラリに対する一般的なシステム接尾辞: .so
  • SO バージョン (任意): 8.2.1

ディストリビューションのパッケージ名は、上記のパーツを組み合わせて構築します:

  • lib 接頭辞に続いて、ライブラリの名称をつなげる (名称にドットを含む場合は、アンダースコアに置き換える)
  • 提供元でバージョン番号が付与されている場合は、バージョン番号をつなげる (ドットはアンダースコアに置き換える)
  • さらに番号が続くので、混乱を防ぐためにダッシュ (-) をつなげる
  • SONAME から SO のバージョン番号を取り出してつなげる (ファイル名よりも短い場合がある。ドットはアンダースコアに置き換える)

下記に openSUSE におけるパッケージ名の例を示します:

説明 SONAME ディストリビューションにおけるバージョン付きパッケージ名
なにもない場合 libdsocks.so (共有ライブラリのパッケージングポリシー適用範囲外)
パッケージバージョンがある場合 libdb-4.8.so libdb-4_8
SO のバージョンがある場合 libblkid.so.1 libblkid1
名前自身に番号がついていて、 SO のバージョンもある場合 libbz2.so.1 libbz2-1
バージョンと SO バージョンの両方がある場合 libzziplib-0.so.13 libzziplib-0-13
全部が含まれている場合 libgame2-1.9.so.10.0.0 libgame2-1_9-10_0_0

注意: 洞察力のある方であれば、上記は一対一にならないルールであることに気が付くでしょう。たとえば、ファイル名が libgame3.so.1 であった場合は libgame3-1 というパッケージ名になりますが、 libgame3-1.so であった場合も、これと同じパッケージ名 libgame3-1 になってしまいます。本ポリシーでは、このような矛盾を解決する方法を提供しておりませんが、現実問題として発生する可能性がありえます。このような事態に陥ってしまった場合は、矛盾を解決するため、 libgame3-1.so ではなく libgame3-1.so.0 のようなファイル名を生成するように修正し、対応を行なうのがよいでしょう。

バージョン無しパッケージ

バージョン番号のあるパッケージの場合は、そのパッケージ名にバージョンの一部または全部を含めますが、本文書で記述していることのほとんどが適用されない バージョン無し パッケージを作成する方法もあります。このようなパッケージの例としては bind-libscups-libs などがあります。共有ライブラリのパッケージングポリシーが策定されて以降、一般的にはバージョン無しパッケージを作らないように努力する方法を模索しているのですが、バージョン番号が無いほうが便利である場合もありますので、現状はまだそれらを残している状態です。

spec ファイルのレイアウト

インストールされる共有ライブラリは、 .spec ファイル内では一般にサブパッケージとして定義します。 Build Service のパッケージ名と .spec ファイルのファイル名は、いずれも tar ボールのファイル名から命名します。たとえば SDL2_image や libHX では、下記のようになっています:

Name: SDL2_image
...
%package -n libSDL2_image-2_0-0
...
%package devel
...
Name: libHX
...
%package -n libHX28
...
%package devel
...

パッケージングポリシーの適用可否について

  • 共有ライブラリがプラグインである場合 (libtool の用語では "モジュール" と言います) 、本ポリシーは適用せず、 プラグイン のセクションのみをヒントとして読むものとします。
  • 共有ライブラリに対応する -devel パッケージが存在しない場合、ライブラリはメインの RPM と同じパッケージ内に含めるものとし、こちらの場合も本ポリシーは適用しないものとします (例: openSUSE 12.1 における encfs パッケージ)

パッケージの中身

  • 一般的には、バージョン番号付きのパッケージには共有ライブラリ以外のものを含めるべきではありません。具体的にはヘッダや開発用の .so シンボリックリンク、設定ファイルやドキュメンテーションなどがそれにあたります。
    • ただし、必要であればライセンスファイルを含めることはできますが、バージョン番号付きのディレクトリに配置しなければなりません (spec ファイルの files セクションで "%doc LICENSE" のように指定することで、バージョン番号付きのディレクトリに配置されるようになります) 。
    • また、特別な理由 (もちろん許可が必要です) があれば、バージョン番号付きの共有ライブラリに共有ライブラリ以外のものを含めることができます。ただし、それらのファイルは本ポリシーと矛盾することのないよう、バージョン付きのディレクトリに配置するか、もしくはファイル名にバージョン番号を付与します (例: libnl3-200 パッケージには /usr/lib64/libnl3-200 というディレクトリがあります) 。
    • なお、 (よりシンプルな) 代替案として、共有ライブラリ側から他の (バージョン番号のない) パッケージに対して Require を設定することもできます。
  • バージョン番号付きのパッケージには、複数のライブラリファイルを含めることができます。ただし、これらのライブラリは同じバージョン番号でなければなりません (例: libqt4 パッケージには libQtCore.so.4, libQtNetwork.so.4 などのライブラリが含まれています) 。
    • 含まれているライブラリ間で依存関係を全く持たない場合、もしくはほとんど持たない場合は、これらのライブラリを 1 つの RPM にまとめず、それぞれを個別の RPM にすることをお勧めします。これは、インストール時のサイズを小さくするための考え方です。
  • lib* で始まり、接尾辞のないパッケージの場合は、数字で終わる必要があります。
    • 接尾辞には、たとえば -devel-debuginfo などがあります。
  • 名前が -devel で終わるパッケージの場合、一般的には数字の部分を省略して設定します。これは、バージョンが異なっていてもヘッダファイルなどの配置は同じ場所であり、ファイルが競合するためです。詳しくは 例外 の (4a) および (4b) をお読みください。
  • lib(名前)(数字).rpm に含まれる共有ライブラリを利用して、プログラムを開発する際に必要なファイルは -devel パッケージ (このパッケージにバージョン番号を付与する必要がある場合については、 (4a) および (4b) をお読みください) に含めてください。これにはたとえば、 lib*.solib*.la のほか、すべてのヘッダファイルが該当します。なお、他のツールやドキュメンテーションも含まれている場合は、 (名前).rpm 内に含めていてもかまいません。ただし、 *-devel.rpm パッケージがある場合は、 lib*.so, lib*.la やヘッダファイルなどをこちらに含めてください。また、 -devel パッケージは、ライセンスファイルの配置場所としても適切です。
  • lib(名前)(番号).rpm には、ユーザが手作業でインストールしなければならないものを含めるべきではありません。また、共有ライブラリのパッケージには、 System/Libraries という RPM グループを指定してください。

ベストプラクティス

ライブラリのパッケージを作成する際の一般的なガイドラインは下記のとおりです:

  • 静的 (スタティック) ライブラリはパッケージに含めないでください。 configure 時のオプションに --disable-static を追加するか、どうしても構築されてしまうような場合は make install 後に削除してください。詳しくはお尋ねください。
  • 共有ライブラリに加えて静的ライブラリもパッケージに含めたい場合、静的ライブラリは -fPIC 付きで構築す べきではありません
  • 静的ライブラリに対応する共有ライブラリ 無しで パッケージを構築したい場合、静的ライブラリは -fPIC を付けて構築され なければなりません 。 configure を使用しているライブラリであれば、 --with-pic オプションで設定することができます。
  • libtool の設定ファイル (.la ファイル) については、パッケージに含めないでください。静的ライブラリをパッケージに含めない場合で、共有ライブラリを標準の検索ディレクトリ (例えば %_lib/usr/%_lib など) 内に配置するような場合、これらのファイルは不要です。ただし、何らかの理由で /opt/package/lib/libfoo.so.7 などの場所にライブラリを配置するような場合は libfoo.la ファイルが必要と なります 。これは、このファイルが存在しないと libfoo.so.7 にリンクする際、 libtool が正しいパスを検出できなくなってしまうためです。
  • 何か質問があれば、ご連絡ください。
  • 通常、共有ライブラリは単独では実行できてはなりません (例外は libc.so.6 および ld-linux.so.2) が、一般に +x ビットは設定しておいてください。

例外

  • (2) 本ポリシーの適用を除外するパッケージは、下記の一覧のとおりとします: (明示的に許可された場合にのみ、パッケージが追加されるものとします)
    • glibc
    • pam
  • (4a) 単一のソースリポジトリ内で複数のバージョンのライブラリが提供されるような場合、 -devel パッケージについても接尾辞を付与して、全く同じパッケージ名で複数のパッケージが生成されることがないようにしてください。なお、この場合は適切な競合関係を別途設定する必要があります。
  • (4b) 複数のバージョンの -devel パッケージを同時にインストールできるようにする場合 (たとえばヘッダファイルがバージョン番号付きのディレクトリにインストールされ、共有ライブラリにも libgtk1.so.1 のようにバージョン番号がついているような場合) は、 -devel パッケージについても番号の接尾辞を付けるものとし、ライブラリのバージョン番号を識別できるようにしてください (通常は共有ライブラリの接尾辞と同じ番号にします) 。このような形態で -devel パッケージの名前を設定すると、 lib(名前)(バージョン番号)-devel のようになります。

プラグイン

プラグインとは共有ライブラリの一形態ですが、これらはプログラム名から設定した適切な %_libdir 以下のサブディレクトリに配置します (例: %_libdir/apache2/mod_alias.so) 。

このような目的に対応するため、 automake (バージョン 0.25 以降) では、 ${pkglibdir} という変数を利用することができるようになっています。既定では ${libdir}/${PACKAGE} というディレクトリになっていますが、プログラムのメインのソースとは別にプラグインが公開されているような場合は、別の値を設定することもできます。

実行ファイルの形態のプラグインの場合は、 %_libexecdir 内にプログラムを配置してください (例: %_libexecdir/cups/filter/pdftops) 。

また、 automake (バージョン 1.10b 以降) では、 ${pkglibexecdir} という変数も用意されています。

ヒント

このポリシーに準拠するには、下記の要件をご確認ください:

  • -devel パッケージには、複数の共有ライブラリパッケージに対する開発用ファイルを含める理由はありません。
  • ソースパッケージの名前と同じバイナリパッケージを用意する必要はありません。事実、ソースリポジトリ内には 1 つのバージョンのみを配置することを選択し、異なるバージョンのソースパッケージに対する名前変更を回避している事例があります。
  • 共有ライブラリパッケージに対する依存関係は、共有ライブラリに対して RPM が作成した自動的な依存関係処理から生成するもののほか、 -devel パッケージから生成するものもあります。こちらの場合は、共有ライブラリのバージョンを限定するようにすべきです。
  • このポリシーとその施行は、共有ライブラリパッケージと /%_lib/usr/%_lib に配置される共有ライブラリに対してのみ適用されます。その他の箇所に対するルールの適用は任意ですが、他の箇所で規定されていることもあります。

最もシンプルな例は、共有ライブラリと開発用ファイルが 1 つずつ生成されるというものです (例えば zlib パッケージがそれに当てはまります) 。ソースパッケージの名前はアップストリームの tar ボールをそのまま利用する (例えば zlib; 詳しくは パッケージ命名ガイドライン および spec ファイルのレイアウト をお読みください) ものとすると、バイナリパッケージの名前は libz1zlib-devel (もしくは libz-devel でもかまいません) という名前になります。メインパッケージに対しては %files セクションを省略することができますが、この場合は zlib.rpm というパッケージは生成されなくなります。

zlib.spec:

Name: zlib
...
%package -n libz1
%package devel
下記のような内容物になります (ファイルは一部省略しています):

libz1:

/lib/libz.so.1
/lib/libz.so.1.2.3

zlib-devel:

/usr/lib/libz.so
/usr/lib/libz.a
/usr/include/zlib.h
/usr/share/man/man3/zlib.3.gz
/usr/share/doc/packages/zlib/algorithm.txt

より複雑な例としては、ライブラリと開発用ファイルからは離れますが、実行ファイルとドキュメンテーションの例があります (たとえば bzip2 などが該当します) 。これは 4 種類のパッケージから構成されます (ファイルは一部省略しています):

libbz2-1:

/lib/libbz2.so.1
/lib/libbz2.so.1.0.0

libbz2-devel:

/usr/include/bzlib.h
/usr/lib/libbz2.so
/usr/lib/libbz2.a

bzip2:

/usr/bin/bzip2
/usr/share/man/man1/bzip2.1.gz

bzip2-doc:

/usr/share/doc/packages/bzip2-doc/manual.ps.gz

ドキュメンテーションについてはバイナリパッケージ bzip2 内、もしくは開発用パッケージ libbz2-devel のいずれかに統合することができます。もちろんドキュメンテーションがそれほど大きなサイズではなく、バイナリや開発に関連するものである場合です。

その他の例としては、ライブラリの他のバージョンと共有することのできる設定ファイルや、データファイルなどに依存するライブラリがあります。たとえば curl パッケージなどがそれに該当しますが、このパッケージの場合は設定ファイルやデータファイルが個別のパッケージとして提供されていて、共有ライブラリ側からは Require: で必須と位置付けています。たとえば curl には 4 種類のパッケージ libcurl4, libcurl-devel, curl, curl-ca-bundle (libcurl4 で必要となる CA の証明書) があります。

Windows/MinGW パッケージ

上記までに説明してきたことは、ダイナミックリンクライブラリ (Windows では共有ライブラリをこのように表記します) に対しても当てはめることができます。これは主に、 build.opensuse.org で "windows" を基本にしているプロジェクト向けの話です。主な点は下記のとおりです:

  • DLL は /usr/プラットフォーム/sys-root/mingw/bin に配置する。
  • ライブラリの SONAME は通常、 libfoo-2.dll のように設定する。それぞれパーツに分解すると、下記のようになる:
    • 一般的なシステム接頭辞 lib
    • ライブラリの名前 foo-bar
    • パッケージバージョン (任意): -2.5
    • SO バージョン (任意): -8
    • 共有ライブラリに対する一般的なシステム接尾辞 (必須): .dll
  • BSD プラットフォームと同様に、 Windows DLL に対する libtool の命名には、メジャー番号のみを含めるものとします (下記の表をご覧ください) 。

名前の変換ルールは下記のとおりです:

説明 SONAME ディストリビューションにおけるバージョン付きパッケージ名
なにもない場合 libdsocks.dll (共有ライブラリのパッケージングポリシー適用範囲外)
パッケージバージョンがある場合 libdb-4.8.dll libdb-4_8
SO のバージョンがある場合 libblkid-1.dll libblkid1
名前自身に番号がついていて、 SO のバージョンもある場合 libbz2-1.dll libbz2-1
バージョンと SO バージョンの両方がある場合 libzziplib-0-13.dll libzziplib-0-13
全部が含まれている場合 libgame2-1.9-10.0.0.dll libgame2-1_9-10_0_0

プロジェクトによっては、パッケージ名に mingw{32,64} のような識別子を追加して、ネイティブパッケージとの競合を防いでいる場合もあります。この場合は、たとえば mingw64-libHX28 のような名前になります。

ライブラリによっては libtool を使用せずに構築されている場合もあります。このような場合は、 -release (リリース) 番号と -version-info (バージョン情報) から構成されることになるので、わかりにくいことになる場合があります。たとえば下記のような例があります:

  • libmwaw-0.1.dll (Linux では libmwaw-0.1.so.1); Linux での名前から "libmwaw-0.1" がベース名であることがわかりますが、 DLL にはバージョン番号がありません。パッケージ名は libmwaw-0_1 のようになります。
  • libnettle-4-6.dll (Linux では libnettle.so.4); SONAME には技術的にダッシュ (-) が入る場合がありますが、実際にはありません。 SO 番号に対しては /-(\d+).dll/ の形式で設定するものとし、 "libnettle-4" をベース名にします。パッケージ名は libnettle4-6 ではなく、 libnettle-4-6 のようになります。zh:openSUSE:Shared library packaging policy