リンカーとライブラリ

外部バージョン管理

共有オブジェクトへの実行時参照は、常にバージョン管理ファイル名を参照するべきです。通常、バージョン管理ファイル名は、バージョン番号が接尾辞として付いたファイル名として表されます。

共有オブジェクトのインタフェースが互換性のない方法で変更すると、その変更によって古いアプリケーションが破壊される可能性があります。このような場合は、新しい共有オブジェクトを新しいバージョン管理ファイル名によって配布するべきです。また、元のバージョン管理ファイル名も配布して、古いアプリケーションで必要なインタフェースを提供する必要があります。

一連のソフトウェアリリースに対してアプリケーションを構築しているときは、実行時環境内に共有オブジェクトを個別のバージョンファイル名で提供する必要があります。このようにすれば、アプリケーションを構築するときに基にしたインタフェースが、実行中に結合するアプリケーションで利用できることを保証できます。

次の節では、コンパイル環境と実行時環境間でのインタフェースの結合を同期する方法について説明します。

バージョン管理ファイル名の管理

リンク編集では、一般的にリンカーの-l オプションを使用して共有オブジェクトの依存関係を参照します。このオプションは、リンカーのライブラリ検索メカニズムを使用して接頭辞 lib と接尾辞 .so が付いた共有オブジェクトを探します。

ただし、実行時に、共有オブジェクト依存関係は、バージョン管理ファイル名として存在していなければなりません。2 つの命名規約に従う 2 つの異なる共有オブジェクトを維持するのではなく、2 つのファイル名間にファイルシステムリンクを作成します。

たとえば、シンボリックリンクを使用すれば、共有オブジェクト libfoo.so.1 をコンパイル環境で利用できるようにすることができます。コンパイルファイル名は、実行時ファイル名へのシンボリックリンクになります。


$ cc -o libfoo.so.1 -G -K pic foo.c
$ ln -s libfoo.so.1 libfoo.so
$ ls -l libfoo*
lrwxrwxrwx  1 usr grp          11 1991 libfoo.so -> libfoo.so.1
-rwxrwxr-x  1 usr grp        3136 1991 libfoo.so.1

シンボリックリンクまたはハードリンクを使用できます。ただし記述および診断目的としては、シンボリックリンクの方が有効です。

共有オブジェクト libfoo.so.1 は、実行時環境用に生成されています。シンボリックリンク libfoo.so は、コンパイル環境でのこのファイルの使用も有効にしています。


$ cc -o prog main.o -L. -lfoo

リンカーは、シンボリックリンク libfoo.so を追って見つける共有オブジェクト libfoo.so.1 によって記述されたインタフェースを使用して、再配置可能オブジェクト main.o を処理します。

一連のソフトウェアリリースにわたって、libfoo.so の新しいバージョンをインタフェースを変更して配布できます。シンボリックリンクを変更することによって、適用可能なインタフェースを使用するよう、コンパイル環境を構築することができます。


$ ls -l libfoo*
lrwxrwxrwx  1 usr grp          11 1993 libfoo.so -> libfoo.so.3
-rwxrwxr-x  1 usr grp        3136 1991 libfoo.so.1
-rwxrwxr-x  1 usr grp        3237 1992 libfoo.so.2
-rwxrwxr-x  1 usr grp        3554 1993 libfoo.so.3

この例では、共有オブジェクトの 3 つの主要バージョンが使用できます。libfoo.so.1libfoo.so.2 の 2 つのバージョンは、既存アプリケーションに対する依存関係を提供します。libfoo.so.3 は、新しいアプリケーションを作成して実行するための最新主要リリースを提供します。

このシンボリックリンクのメカニズムを使用するだけでは、コンパイル環境での共有オブジェクトが実行時バージョン管理ファイル名と同期をとることができません。例が示しているように、リンカーは、動的実行可能ファイル prog に、リンカーが処理した共有オブジェクトのファイル名を記録します。この場合、リンカーで表示されるファイル名はコンパイル環境のファイルです。


$ dump -Lv prog

prog:
 **** DYNAMIC SECTION INFORMATION ****
.dynamic:
[INDEX] Tag      Value
[1]     NEEDED   libfoo.so
.........

アプリケーション prog が実行されると、実行時リンカーは、依存関係 libfoo.so を検索します。prog は、このシンボリックリンクが指すすべてのファイルに結合されます。

正しい実行時名を依存関係として記録するには、共有オブジェクト libfoo.so.1 を「soname」定義によって構築する必要があります。この定義は、共有オブジェクトの実行時名を識別します。この名前は、共有オブジェクトに対してリンクするすべてのオブジェクトによって、依存関係名として使用されます。この定義は、共有オブジェクトの作成中に -h オプションを使用して与えることができます。


$ cc -o libfoo.so.1 -G -K pic -h libfoo.so.1 foo.c
$ ln -s libfoo.so.1 libfoo.so
$ cc -o prog main.o -L. -lfoo
$ dump -Lv prog

prog:
 **** DYNAMIC SECTION INFORMATION ****
.dynamic:
[INDEX] Tag      Value
[1]     NEEDED   libfoo.so.1
.........

このシンボリックリンクと「soname」メカニズムは、コンパイル環境と実行時環境の共有オブジェクト命名規約の間に強固な同期を確立します。リンク編集中に処理されたインタフェースは、生成された出力ファイルに正確に記録されます。この記録によって、意図したインタフェースが実行時に提供されます。

同じプロセス内の複数の外部バージョン管理ファイル

外部的にバージョン管理された新しい共有オブジェクトを作成することは、大きな変更です。外部的にバージョン管理された一連の共有オブジェクトのメンバーを使用するすべてのプロセスの依存関係を、完全に理解している必要があります。

たとえば、あるアプリケーションが、libfoo.so.1 および外部から記述されたオブジェクト libISV.so.1 と依存関係があるとします。この後者のオブジェクトは libfoo.so.1 とも依存関係があるとします。新しいインタフェース libfoo.so.2 を使用するように、アプリケーションを再設計する可能性があります。ただし、アプリケーションが外部オブジェクト libISV.so.1 を使用することは変更しない可能性があります。実行時に読み込まれる libfoo.so 実装の可視性のスコープに応じて、主要なバージョンのファイルが両方とも実行プロセスに含まれます。libfoo.so のバージョンを変更する理由は、互換性のない変更をマークすることだけです。つまり、プロセス内にオブジェクトの両方のバージョンを持つことは、不正なシンボル結合が発生する原因となり、そのために望ましくない相互作用を引き起こすことがあります。

インタフェースに互換性のない変更を行うことは避けるようにしてください。互換性のない変更は、インタフェース定義およびインタフェース定義を参照するすべてのオブジェクトを完全に制御できる場合に限って検討することをお勧めします。