バージョン定義を含む共有オブジェクトに対して動的オブジェクトを作成する場合、リンカーに対して、特定のバージョン定義への結合を制限するように指示することができます。リンカーを使用すると、特定インタフェースへのオブジェクトの結合を効果的に制御することができます。
オブジェクトの結合要件は、「ファイル制御指令」によって制御できます。この指令は、リンカーの -M オプションと関連の mapfile を使用して提供されます。ファイル制御指令には、次の構文を使用します。
name - version [ version ... ] [ $ADDVERS=version ]; |
name — 共有オブジェクト依存関係の名前を表します。この名前は、リンカーによって使用される共有オブジェクトのコンパイル環境名と一致しなければなりません。「ライブラリの命名規約」を 参照してください。
version – 結合に使用可能でなければならない共有オブジェクト内のバージョン定義名を表します。複数のバージョン定義を指定できます。
バージョン結合の制御は、次のような場合に役立ちます。
共有オブジェクトが一意の独立したバージョンを定義するとき。このバージョン管理は、異なる標準インタフェースを定義するときに使用できます。結合制御でオブジェクトを構築することによって、そのオブジェクトが特定のインタフェースだけに結合することを保証できます。
複数世代のソフトウェアリリースにまたがって、共有オブジェクトをバージョン管理するとき。結合制御でオブジェクトを構築することによって、以前のソフトウェアリリースで利用可能だったインタフェースだけに結合するように制限できます。したがって、最新リリースの共有オブジェクトを使用して構築したオブジェクトでも、古いリリースの共有オブジェクトを使用して実行できます。
次に、バージョン制御メカニズムの使用例を示します。この例では、次のバージョンインタフェース定義を含む共有オブジェクト libfoo.so.1 を使用しています。
$ pvs -dsv libfoo.so.1 libfoo.so.1: _end; _GLOBAL_OFFSET_TABLE_; _DYNAMIC; _edata; _PROCEDURE_LINKAGE_TABLE_; _etext; SUNW_1.1: foo1; foo2; SUNW_1.1; SUNW_1.2: {SUNW_1.1}: bar; |
バージョン定義 SUNW_1.1 および SUNW_1.2 は、ソフトウェア Release X および Release X+1 で使用可能な libfoo.so.1 内のインタフェースをそれぞれ表します。
アプリケーションは、次のバージョン制御 mapfile 指令を使用して、Release X で使用可能なインタフェースだけに結合するように構築できます。
$ cat mapfile libfoo.so - SUNW_1.1; |
たとえば、Release X 上で動作するアプリケーション prog を開発するとします。アプリケーションでは、Release X で使用可能なインタフェース以外は使用できません。シンボル bar を間違えて参照すると、アプリケーションは要求されるインタフェースに準拠しなくなります。リンカーはこの状態を未定義のシンボルエラーとして通知します。
$ cat prog.c extern void foo1(); extern void bar(); main() { foo1(); bar(); } $ cc -o prog prog.c -M mapfile -L. -R. -lfoo Undefined first referenced symbol in file bar prog.o (symbol belongs to unavailable \ version ./libfoo.so (SUNW_1.2)) ld: fatal: Symbol referencing errors. No output written to prog |
SUNW_1.1 インタフェースに準拠するには、bar への参照を削除する必要があります。これは、アプリケーションを再処理して bar に対する要件を削除するか、または bar の実装をアプリケーションの作成に追加することによって行います。
デフォルトでは、リンク編集の一部として検出された共有オブジェクト依存関係も、すべてのファイル制御指令に対して確認されます。環境変数 LD_NOVERSION を使用して、共有オブジェクト依存関係のバージョン検査を抑制します。
通常のオブジェクトシンボル結合から作成されるバージョン依存関係に、追加のバージョン依存関係を記録するには、$ADDVERS ファイル制御指令を使用します。次の節では、この追加結合が役に立ついくつかのシナリオについて説明します。
1 つのシナリオは、ISV 固有のインタフェースを公開標準インタフェースで使用します。
libfoo.so.1 の例に続いて、Release X+2 において、バージョン定義 SUNW_1.1 が 2 つの標準リリース STAND_A と STAND_B に分割される場合を想定します。互換性を維持するには、SUNW_1.1 バージョン定義を維持する必要があります。次の例では、このバージョン定義は 2 つの標準定義を継承するものとして表されています。
$ pvs -dsv libfoo.so.1 libfoo.so.1: _end; _GLOBAL_OFFSET_TABLE_; _DYNAMIC; _edata; _PROCEDURE_LINKAGE_TABLE_; _etext; SUNW_1.1: {STAND_A, STAND_B}: SUNW_1.1; SUNW_1.2: {SUNW_1.1}: bar; STAND_A: foo1; STAND_A; STAND_B: foo2; STAND_B; |
アプリケーション prog の唯一の要件がインタフェースシンボル foo1 である場合、このアプリケーションはバージョン定義 STAND_A に対して単一の依存関係を持ちます。このことは、libfoo.so.1 が Release X+2 よりも小さいシステムでの prog の実行を阻害します。以前のリリースでは、インタフェース foo1 が存在する場合でも、バージョン定義 STAND_A は存在しませんでした。
アプリケーション prog は、SUNW_1.1 に対する依存関係を作成することによって、その要件を以前のリリースに合わせて構築できます。
$ cat mapfile libfoo.so - SUNW_1.1 $ADDVERS=SUNW_1.1; $ cat prog extern void foo1(); main() { foo1(); } $ cc -M mapfile -o prog prog.c -L. -R. -lfoo $ pvs -r prog libfoo.so.1 (SUNW_1.1); |
この明示的な依存関係は、真の依存関係の要件をカプセル化するのに十分です。この依存関係は古いリリースとの互換性も保ちます。
「ウィークバージョン定義の作成」では、ウィークバージョン定義を使用して、内部実装の変更をマークする方法について説明しました。これらのバージョン定義は、オブジェクトに対して行われたバグ修正と性能の改善に適しています。ウィークバージョンの存在が必要である場合、ウィークバージョン定義への明示的な依存関係を作成できます。オブジェクトを正しく機能させるためにバグ修正や性能の改善が重要な場合、このような依存関係の作成も重要になります。
上記の libfoo.so.1 の例で、バグ修正がウィークバージョン定義 SUNW_1.2.1 としてソフトウェア Release X+3 に組み込まれている場合を想定します。
$ pvs -dsv libfoo.so.1 libfoo.so.1: _end; _GLOBAL_OFFSET_TABLE_; _DYNAMIC; _edata; _PROCEDURE_LINKAGE_TABLE_; _etext; SUNW_1.1: {STAND_A, STAND_B}: SUNW_1.1; SUNW_1.2: {SUNW_1.1}: bar; STAND_A: foo1; STAND_A; STAND_B: foo2; STAND_B; SUNW_1.2.1 [WEAK]: {SUNW_1.2}: SUNW_1.2.1; |
通常、アプリケーションは、この libfoo.so.1 に対して構築されている場合、バージョン定義 SUNW_1.2.1 に対する弱い依存関係を記録します。この依存関係は情報提供だけを目的とします。実行時に使用される libfoo.so.1 の実装にバージョン定義が見つからなくても、この依存関係によってアプリケーションが強制終了されることはありません。
ファイル制御指令 $ADDVERS を使用すると、バージョン定義に対する明示的な依存関係を生成できます。この定義がウィークである場合、この明示的参照によって、バージョン定義が強い依存関係に高められます。
アプリケーション prog は、次のファイル制御指令を使用して、SUNW_1.2.1 インタフェースを実行時に使用できるという要件を実施するように構築できます。
$ cat mapfile libfoo.so - SUNW_1.1 $ADDVERS=SUNW_1.2.1; $ cat prog extern void foo1(); main() { foo1(); } $ cc -M mapfile -o prog prog.c -L. -R. -lfoo $ pvs -r prog libfoo.so.1 (SUNW_1.2.1); |
prog には、インタフェース STAND_A に対する明示的な依存関係があります。バージョン定義 SUNW_1.2.1 は、強いバージョンに高められているため、依存関係 STAND_A によって正規化されます。実行時にバージョン定義 SUNW_1.2.1 が見つからないと、重大なエラーが生成されます。
依存関係が少ない場合、リンカーの -u オプションを使用して、バージョン定義に明示的に結合できます。このオプションで、バージョン定義シンボルを参照します。ただし、シンボル参照は非選択的です。類似の名前を持つ複数のバージョン定義を含む可能性がある複数の依存関係を処理する場合は、この手法で明示的な結合を作成できないことがあります。