C++ ユーザーズガイド |
第 6 章
ライブラリの構築
ライブラリとは
ライブラリには 2 つの利点があります。まず、ライブラリを使えば、コードをいくつかのアプリケーションで共有できます。共有したいコードがある場合は、そのコードを含むライブラリを作成し、コードを必要とするアプリケーションとリンクできます。次に、ライブラリを使えば、非常に大きなアプリケーションの複雑さを軽減できます。アプリケーションの中の、比較的独立した部分をライブラリとして構築および保守することで、プログラマは他の部分の作業により専念できるようになるためです。
ライブラリの構築とは、
.o
ファイルを作成し (コードを-c
オプションでコンパイルし)、これらの.o
ファイルをCC
コマンドでライブラリに結合することです。ライブラリには、静的 (アーカイブ) ライブラリと動的 (共有) ライブラリがあります。静的 (アーカイブ) ライブラリの場合は、ライブラリのオブジェクトがリンク時にプログラムの実行可能ファイルにリンクされます。アプリケーションにとって必要な
.o
ファイルだけがライブラリから実行可能ファイルにリンクされます。静的 (アーカイブ) ライブラリの名前には、通常、接尾辞.a
が付きます。動的 (共有) ライブラリの場合は、ライブラリのオブジェクトはプログラムの実行可能ファイルにリンクされません。その代わりに、プログラムがこのライブラリに依存することをリンカーが実行可能ファイルに記録します。プログラムが実行されるとき、システムは、プログラムに必要な動的ライブラリを読み込みます。同じ動的ライブラリを使用する 2 つのプログラムが同時に実行されると、ライブラリはこれらのプログラムによって共有されます。動的 (共有) ライブラリの名前には、接尾辞として
.so
が付きます。共有ライブラリを動的にリンクすることは、アーカイブライブラリを静的にリンクすることに比べていくつかの利点があります。
- 実行可能ファイルのサイズが小さくなる
- 実行時にコードのかなりの部分をプログラム間で共有できるため、メモリーの使用量が少なくなる
- ライブラリを実行時に置き換える場合でも、アプリケーションとリンクし直す必要がない (プログラムの再リンクや再配布をしなくても、Solaris 環境でプログラムが新しい機能を使用できるのは、主にこの仕組みのためです)
dlopen()
関数呼び出しを使えば、共有ライブラリを実行時に読み込むことが
できる
- 実行時のリンクに時間がかかる
- 動的ライブラリを使用するプログラムを配布する場合には、それらのライブラリも同時に配布しなければならないことがある
- 共有ライブラリを別の場所に移動すると、システムがライブラリを検索できずに、プログラムを実行できなくなることがある (環境変数
LD_LIBRARY_PATH
を使えば、この問題は解決できます)静的 (アーカイブ) ライブラリの構築
静的 (アーカイブ) ライブラリを構築する仕組みは、実行可能ファイルを構築することに似ています。一連のオブジェクト (
.o
) ファイルは、CC
で-xar
オプションを使うことで 1 つのライブラリに結合できます。静的 (アーカイブ) ライブラリを構築する場合は、
ar
コマンドを直接使用せずにCC
-xar
を使用してください。C++ 言語では一般に、従来の.o
ファイルに収容できる情報より多くの情報 (特に、テンプレートインスタンス) をコンパイラが持たなければなりません。-xar
オプションを使用すると、テンプレートインスタンスを含め、すべての必要な情報がライブラリに組み込まれます。make
ではどのテンプレートファイルが実際に作成され、参照されているのかがわからないため、通常のプログラミング環境でこのようにすることは困難です。CC -xar
を指定しないと、参照に必要なテンプレートインスタンスがライブラリに組み込まれないことがあります。構築の例を次に示します。
%CC -c foo.cc
#main
を含むファイルをコンパイルし、テンプレート オブジェクトを作成する%CC -xar -o foo.a foo.o
# すべてのオブジェクトを1つのライブラリに集める
-xar
フラグによって、CC
が静的 (アーカイブ) ライブラリを作成します。-o
命令は、新しく作成するライブラリの名前を指定するために必要です。コンパイラは、コマンド行のオブジェクトファイルを調べ、これらのオブジェクトファイルと、テンプレートレポジトリで認識されているオブジェクトファイルとを相互参照します。そして、ユーザーのオブジェクトファイルに必要なテンプレートを (本体のオブジェクトファイルとともに) アーカイブに追加します。
注 --xar
フラグは既存のアーカイブの作成や更新のためのもので、保守には使用できません。-xar
オプションはar -cr
を実行するのと同じことです。
1 つの
.o
ファイルには 1 つの関数を入れることをお勧めします。アーカイブとリンクする場合、特定の.o
ファイルのシンボルが必要になると、.o
ファイル全体がアーカイブからアプリケーションにリンクされます。.o
ファイルに 1 つの関数を入れておけば、アプリケーションにとって必要なシンボルだけがアーカイブからリンクされます。動的 (共有) ライブラリの構築
動的 (共有) ライブラリの構築方法は、コマンド行に
-xar
の代わりに-G
を指定することを除けば、静的 (アーカイブ) ライブラリの場合と同じです。
ld
は直接使用しないでください。静的ライブラリの場合と同じように、CC
コマンドを使用すると、必要なすべてのテンプレートインスタンスがテンプレートレポジトリからライブラリに組み込まれます (テンプレートを使用している場合)。さらに、CC
コンパイラは、大域変数がライブラリに定義されている場合、動的ライブラリが正しく構築されていないと大域変数を初期化しません。アプリケーションにリンクされている動的ライブラリでは、すべての静的コンストラクタはmain()
が実行される前に呼び出され、すべての静的デストラクタはmain()
が終了した後に呼び出されます。dlopen()
で共有ライブラリを開いた場合、すべての静的コンストラクタはdlopen()
で実行され、すべての静的デストラクタはdlclose()
で実行されます。CC
-G
コマンドを使用して動的ライブラリを構築しないと、例外が機能しないことがあります。動的 (共有) ライブラリを構築するには、
CC
の-Kpic
や-KPIC
オプションで各オブジェクトをコンパイルして、再配置可能なオブジェクトファイルを作成する必要があります。次に、これらの再配置可能オブジェクトファイルから動的ライブラリを構築します。原因不明のリンクエラーがいくつも出る場合は、-Kpic
や-KPIC
でコンパイルしていないオブジェクトがある可能性があります。ソースファイル
lsrc1.cc
とlsrc2.cc
から作成するオブジェクトファイルから C++ 動的ライブラリlibgoo.so.1
を構築するには、次のようにします。
%CC -G -o libfoo.so -h libfoo.so -Kpic lsrc1.cc lsrc2.cc
-G
オプションは動的ライブラリの構築を指定し、-o
オプションはライブラリのファイル名を指定します。-h
オプションは、共有ライブラリの名前を指定しています。-Kpic
オプションは、オブジェクトファイルが位置に依存しないことを指定しています。
注 -CC -G
コマンドは-l
オプションをld
に渡しません。共有ライブラリに他の共有ライブラリとの依存関係を持たせたい場合、必要な-l
オプションをコマンド行に指定する必要があります。たとえば、共有ライブラリにlibCrun.so
との依存関係を持たせたい場合、-lCrun
をコマンド行に指定する必要があります。
例外を含む共有ライブラリの構築
dlopen()
で共有ライブラリを開く場合、例外が機能するようにするには、RTLD_GLOBAL
を使用する必要があります。
注 - 例外を含む共有ライブラリを構築するとき、ld
に-Bsymbolic
オプションを渡さないでください。必要な例外が捕獲されなくなる可能性があります。
非公開ライブラリの構築
ある組織の内部でしか使用しないライブラリを構築する場合には、一般的な使用には適さないオプションを使ってライブラリを構築することもできます。具体的には、ライブラリはシステムのアプリケーションバイナリインタフェース (ABI) に準拠していなくてもかまいません。たとえば、ライブラリを
-fast
オプションでコンパイルして、特定のアーキテクチャ上でのパフォーマンスを向上させることができます。同じように、-xregs=float
オプションでコンパイルして、パフォーマンスを向上させることもできます。公開ライブラリの構築
他の組織からも使用できるライブラリを構築する場合は、ライブラリの管理やプラットフォームの汎用性などの問題が重要になります。ライブラリを公開にするかどうかを決める簡単な基準は、アプリケーションのプログラマがライブラリを簡単に再コンパイルできるかどうかということです。公開ライブラリは、システムの ABI に準拠して構築しなければなりません。一般に、これはプロセッサ固有のオプションを使用しないということを意味します (たとえば、
-fast
や-xtarget
は使用しないなど)。SPARC ABI では、いくつかのレジスタがアプリケーション専用で使用されます。V7 と V8 では、これらのレジスタは
%g2
、%g3
、%g4
です。V9 では、これらのレジスタは%g2
と%g3
です。ほとんどのコンパイルはアプリケーション用に行われるので、C++ コンパイラは、デフォルトでこれらのレジスタを一時レジスタに使用して、プログラムのパフォーマンスを向上しようとします。しかし、公開ライブラリでこれらのレジスタを使用することは、SPARC ABI に適合しないことになります。公開ライブラリを構築するときには、アプリケーションレジスタを使用しないようにするために、すべてのオブジェクトを-xregs=no%appl
オプションでコンパイルしてください。C API を持つライブラリの構築
C++ で作成されたライブラリを C プログラムから使用できるようにするには、C API を作成する必要があります。そのためには、エクスポートされるすべての関数を
extern
"C"
にします。ただし、これができるのは大域関数だけで、メンバー関数にはできません。さらに、C++ 実行時ライブラリにもまったく依存しないようにするには、ライブラリソースに対して次のコーディング規則を適用する必要があります。
- どのような形式の
new
またはdelete
も使用しない (独自のnew
またはdelete
を定義する場合は除く)- 例外を使用しない
- 実行時型特定機構 (RunTime Type Information、RTTI) を使用しない
dlopen
を使って C プログラムから C++ ライブラリにアクセスするC プログラムから
dlopen
で C++ 共有ライブラリを開く場合は、共有ライブラリが適切な C++ 実行時ライブラリ (-compat=4
の場合はlibC.so.5
、-compat=5
の場合はlibCrun.so.1
) に依存していなければなりません。そのためには、共有ライブラリを構築するときに、
-compat=4
の場合は-lc
、-compat=5
の場合は-lCrun
を次のようにコマンド行に追加します。
example%CC -G -compat=4 ... -lC
example%CC -G -compat=5 ... -lCrun
共有ライブラリが例外を使用している場合には、ライブラリが C++ 共有ライブラリに依存していないと、C プログラムが正しく動作しないことがあります。
注 - 共有ライブラリをdlopen()
で開く場合は、RTLD_GLOBAL
を使用しないと、例外は機能しません。
マルチスレッド化されたプログラムの構築
サン・マイクロシステムズ株式会社 Copyright information. All rights reserved. |
ホーム | 目次 | 前ページへ | 次ページへ | 索引 |