2.2. GCC でのライブラリーの使用
コード内でのライブラリーの使用について説明します。
2.2.1. ライブラリーの命名規則
特別なファイルの命名規則をライブラリーに使用します。foo として知られるライブラリーは、libfoo.so
ファイルまたは libfoo.a
ファイルとして存在する必要があります。この規則は、リンクする GCC の入力オプションでは自動的に理解されますが、出力オプションでは理解されません。
ライブラリーにリンクする場合は、
-lfoo
のように、-l
オプションと foo の名前でしか、ライブラリーを指定することができません。$ gcc ... -lfoo ...
-
ライブラリーの作成時には、
libfoo.so
、libfoo.a
など、完全なファイル名を指定する必要があります。
関連情報
2.2.2. 静的リンクおよび動的リンク
開発者は、完全にコンパイルされた言語でアプリケーションを構築する際に、静的リンクまたは動的リンクを使用できます。特に Red Hat Enterprise Linux で C および C++ 言語を使用するコンテキストでは、静的リンクと動的リンクの違いを理解することが重要です。Red Hat は、Red Hat Enterprise Linux のアプリケーションで静的リンクを使用することは推奨していません。
静的リンクおよび動的リンクの比較
静的リンクは、作成される実行可能ファイルのライブラリーの一部になります。動的リンクは、これらのライブラリーを別々のファイルとして保持します。
動的リンクおよび静的リンクは、いくつかの点で異なります。
- リソースの使用
静的リンクにより、より多くのコードが含まれるより大きな実行可能ファイルが生成されます。ライブラリーからのこの追加コードはシステムのプログラム間で共有できないため、ランタイム時にファイルシステムの使用量とメモリーの使用量が増加します。静的にリンクされた同じプログラムを実行している複数のプロセスは依然としてコードを共有します。
一方、静的アプリケーションは、必要なランタイムの再配置も少なくなるため、起動時間が短縮します。また、必要なプライベートの RSS (homeal Set Size) メモリーも少なくなります。静的リンク用に生成されたコードは、PIC (位置独立コード) により発生するオーバーヘッドにより、動的リンクよりも効率が良くなります。
- セキュリティー
- ABI 互換性を提供する動的にリンクされたライブラリーは、それらのライブラリーに依存する実行可能ファイルを変更せずに更新できます。これは、特に、Red Hat Enterprise Linux の一部として提供され、Red Hat がセキュリティー更新を提供するライブラリーで重要になります。このようなライブラリーには、静的リンクを使用しないことが強く推奨されます。
- 互換性
静的リンクは、オペレーティングシステムが提供するライブラリーのバージョンに依存しない実行可能ファイルを提供しているように見えます。ただし、ほとんどのライブラリーは他のライブラリーに依存しています。静的リンクを使用すると、依存関係に柔軟性がなくなり、前方互換性と後方互換性が失われます。静的リンクは、実行ファイルが構築されたシステムでのみ機能します。
警告GNU C ライブラリー (glibc) から静的ライブラリーをリンクするアプリケーションでは、引き続き glibc が動的ライブラリーとしてシステムに存在する必要があります。さらに、アプリケーションのランタイム時に利用できる glibc の動的ライブラリーバリアントは、アプリケーションのリンク時に表示されるものとビット単位で同じバージョンである必要があります。したがって、静的リンクは、実行ファイルが構築されたシステムでのみ機能することが保証されます。
- サポート範囲
- Red Hat が提供するほとんどの静的ライブラリーは CodeReady Linux Builder チャンネルにあり、Red Hat ではサポートされていません。
- 機能
いくつかのライブラリー (特に GNU C ライブラリー (glibc)) は、静的にリンクすると提供する機能が少なくなります。
たとえば、静的にリンクすると、glibc はスレッドや、同じプログラム内の
dlopen()
関数に対する呼び出しの形式をサポートしません。
上述のデメリットにより、静的リンクは、特にアプリケーション全体、glibc ライブラリー、および libstdc++ ライブラリーに対しては、使用しないようにしてください。
静的リンクの場合
静的リンクは、次のようないくつかのケースでは合理的な選択が可能です。
- 動的リンクが使用できないライブラリーを使用している
-
空の chroot 環境またはコンテナーでコードを実行するには、完全に静的なリンクが必要です。ただし、
glibc-static
パッケージを使用した静的リンクは、Red Hat ではサポートされません。
関連情報
2.2.3. GCC でのライブラリーの使用
ライブラリーは、プログラムで再利用可能なコードのパッケージです。C または C++ のライブラリーは、以下の 2 つの部分で設定されます。
- ライブラリーコード
- ヘッダーファイル
ライブラリーを使用するコードのコンパイル
ヘッダーファイルでは、ライブラリーで提供する関数や変数など、ライブラリーのインターフェイスを記述します。コードをコンパイルする場合に、ヘッダーファイルの情報が必要です。
通常、ライブラリーのヘッダーファイルは、アプリケーションのコードとは別のディレクトリーに配置されます。ヘッダーファイルの場所を GCC に指示するには、-I
オプションを使用します。
$ gcc ... -Iinclude_path ...
include_path は、ヘッダーファイルのディレクトリーのパスに置き換えます。
-I
オプションは、複数回使用して、ヘッダーファイルを含むディレクトリーを複数追加できます。ヘッダーファイルを検索する場合は、-I
オプションで表示順に、これらのディレクトリーが検索されます。
ライブラリーを使用するコードのリンク
実行ファイルをリンクする場合には、アプリケーションのオブジェクトコードと、ライブラリーのバイナリーコードの両方が利用できる状態でなければなりません。静的ライブラリーおよび動的ライブラリーのコードは、形式が異なります。
-
静的なライブラリーは、アーカイブファイルとして利用できます。静的なライブラリーには、一連のオブジェクトファイルが含まれます。アーカイブファイルのファイル名の拡張子は
.a
になります。 -
動的なライブラリーは共有オブジェクトとして利用できます。実行ファイルの形式です。共有オブジェクトのファイル名の拡張子は
.so
になります。
ライブラリーのアーカイブファイルまたは共有オブジェクトファイルの場所を GCC に渡すには、-L
オプションを使用します。
$ gcc ... -Llibrary_path -lfoo ...
library_path は、ライブラリーのディレクトリーのパスに置き換えます。
-I
オプションは複数回使用して、ディレクトリーを複数追加できます。ライブラリーを検索する場合は、-L
オプションで表示順に、このディレクトリーが検索されます。
オプションの指定順は重要です。対象のライブラリーがディレクトリーにリンクされていることが分からないと、GCC は、ライブラリー foo をリンクできません。そのため、-L
オプションを使用して先にライブラリーディレクトリーを指定してから、-l
オプションでライブラリーをリンクするようにしてください。
1 つの手順でライブラリーを使用するコードをコンパイルおよびリンクする方法
1 つの gcc
コマンドでコードをコンパイルおよびリンクできる場合は、上記のオプションを一度に使用します。
関連情報
- GNU コンパイラーコレクション (GCC) の使用: Options for Directory Search
- GNU コンパイラーコレクション (GCC) の使用: Options for Linking
2.2.4. GCC での静的ライブラリーの使用
静的なライブラリーは、オブジェクトファイルを含むアーカイブとして利用できます。リンクを行うと、作成された実行ファイルの一部となります。
Red Hat は、セキュリティー上の理由から、静的リンクを使用することは推奨していません。「静的リンクおよび動的リンク」 を参照してください。静的リンクは、特に Red Hat が提供するライブラリーに対して、必要な場合に限り使用してください。
前提条件
- GCC がシステムにインストールされている。
- 静的リンクおよび動的リンクを理解している。
- 有効なプログラムを設定するソースまたはオブジェクトのファイルセット。静的ライブラリー foo だけが必要です。
-
foo ライブラリーは
libfoo.a
ファイルとして利用でき、動的リンクにはlibfoo.so
ファイルがありません。
Red Hat Enterprise Linux に含まれるライブラリーのほとんどは、動的リンク用としてのみサポートされています。次の手順は、動的リンクに 無効の ライブラリーに対してのみ有効です。「静的リンクおよび動的リンク」 を参照してください。
手順
ソースとオブジェクトファイルからプログラムをリンクするには、静的にリンクされたライブラリー foo (libfoo.a
として検索可能) を追加します。
- コードが含まれるディレクトリーに移動します。
foo ライブラリーのヘッダーで、プログラムソースファイルをコンパイルします。
$ gcc ... -Iheader_path -c ...
header_path を、foo ライブラリーのヘッダーファイルを含むディレクトリーのパスに置き換えます。
プログラムを foo ライブラリーにリンクします。
$ gcc ... -Llibrary_path -lfoo ...
library_path を、
libfoo.a
ファイルを含むディレクトリーのパスに置き換えます。あとでプログラムを実行するには、次のコマンドを実行します。
$ ./program
静的リンクに関連する GCC オプション -static
は、すべての動的リンクを禁止します。代わりに -Wl,-Bstatic
オプションおよび -Wl,-Bdynamic
オプションを使用して、リンカーの動作をより正確に制御します。「GCC で静的ライブラリーおよび動的ライブラリーの両方を使用」 を参照してください。
2.2.5. GCC での動的ライブラリーの使用
動的ライブラリーは、スタンドアロンの実行ファイルとして提供します。このファイルは、リンク時およびランタイム時に必要です。このファイルは、アプリケーションの実行可能ファイルからは独立しています。
前提条件
- GCC がシステムにインストールされている。
- 有効なプログラムを設定するソースまたはオブジェクトファイルセットがある。動的ライブラリー foo だけが必要になります。
- foo ライブラリーが libfoo.so ファイルとして利用できる。
プログラムの動的ライブラリーへのリンク
動的ライブラリー foo にプログラムをリンクするには、次のコマンドを実行します。
$ gcc ... -Llibrary_path -lfoo ...
プログラムを動的ライブラリーにリンクすると、作成されるプログラムは常にランタイム時にライブラリーを読み込む必要があります。ライブラリーの場所を特定するオプションは 2 つあります。
-
実行ファイルに保存された
rpath
の値を使用する方法 -
ランタイム時に
LD_LIBRARY_PATH
変数を使用する方法
実行ファイルに保存された rpath
の値を使用する方法
rpath
は、リンク時に実行ファイルの一部として保存される特別な値です。その後、実行ファイルからプログラムを読み込む時に、ランタイムリンカーが rpath
の値を使用してライブラリーファイルの場所を特定します。
GCC とリンクし、library_path のパスを rpath
として保存します。
$ gcc ... -Llibrary_path -lfoo -Wl,-rpath=library_path ...
library_path のパスは、libfoo.so ファイルを含むディレクトリーを参照する必要があります。
-Wl,-rpath=
オプションのコンマの後にスペースを追加しないでください。
あとでプログラムを実行するには、次のコマンドを実行します。
$ ./program
LD_LIBRARY_PATH 環境変数を使用する方法
プログラムの実行ファイルに rpath
がない場合、ランタイムリンカーは LD_LIBRARY_PATH
の環境変数を使用します。この変数の値は、プログラムごとに変更する必要があります。この値は、共有ライブラリーオブジェクトがあるパスを表す必要があります。
rpath
セットがなく、ライブラリーが library_path パスにある状態で、プログラムを実行します。
$ export LD_LIBRARY_PATH=library_path:$LD_LIBRARY_PATH
$ ./program
rpath
の値を空白にすると柔軟性がありますが、プログラムを実行するたびに LD_LIBRARY_PATH
変数を設定する必要があります。
ライブラリーのデフォルトディレクトリーへの配置
ランタイムのリンカー設定では、複数のディレクトリーを動的ライブラリーファイルのデフォルトの場所として指定します。このデフォルトの動作を使用するには、ライブラリーを適切なディレクトリーにコピーします。
動的リンカーの動作に関する詳細な説明は、本書の対象外です。詳しい情報は、以下の資料を参照してください。
動的リンカーの Linux man ページ:
$ man ld.so
/etc/ld.so.conf
設定ファイルの内容:$ cat /etc/ld.so.conf
追加設定なしに動的リンカーにより認識されるライブラリーのレポート (ディレクトリーを含む):
$ ldconfig -v
2.2.6. GCC で静的ライブラリーおよび動的ライブラリーの両方を使用
場合によっては、静的ライブラリーと動的ライブラリーの両方をリンクする必要があります。このような場合には、いくつかの課題があります。
前提条件
はじめに
GCC は、動的ライブラリーと静的ライブラリーの両方を認識します。-lfoo
オプションがあると、gcc はまず、動的にリンクされたバージョンの foo ライブラリーを含む共有オブジェクト (.so
ファイル) を検索し、静的ライブラリーを含むアーカイブファイル (.a
) を検索します。したがって、この検索により、以下の状況が発生する可能性があります。
- 共有オブジェクトのみが見つかり、gcc がそのオブジェクトに動的にリンクする
- アーカイブファイルのみが見つかり、gcc がそのファイルに静的にリンクする
- 共有オブジェクトとアーカイブファイルの両方が見つかり、デフォルトでは gcc が共有オブジェクトに動的にリンクする
- 共有オブジェクトもアーカイブファイルも見つからず、リンクに失敗する
このようなルールがあるため、リンクするために、静的ライブラリーまたは動的ライブラリーを選択する場合は、gcc が検索可能なバージョンのみを指定するようにします。これにより、-Lpath
オプションで指定する場合に、静的ライブラリーまたは動的ライブラリーを含むディレクトリーを追加するか、追加しないかで、ある程度制御が可能になります。
また、動的リンクがデフォルトの設定であるため、明示的にリンクを指定する必要があるのは、静的と動的の両方を静的にリンクする必要がある場合のみです。考えられる方法は以下の 2 つです。
-
-l
オプションではなく、ファイルパスで静的ライブラリーを指定する -
-Wl
オプションを使用して、オプションをリンカーに渡す
ファイルで静的ライブラリーを指定する方法
通常、gcc は、-lfoo
オプションで、foo ライブラリーにリンクするように指示されます。ただし、代わりに、ライブラリーを含む libfoo.a
ファイルの完全パスは指定できます。
$ gcc ... path/to/libfoo.a ...
ファイルの拡張子 .a
から、gcc は、このファイルがプログラムとリンクするためのライブラリーであることを理解します。ただし、ライブラリーファイルの完全パスを指定するのは柔軟な方法ではありません。
-Wl
オプションの使用
gcc
オプションの -Wl は、基盤のリンカーにオプションを渡す特別なオプションです。このオプションの構文は、他の gcc オプションとは異なります。-Wl
オプションの後に、リンカーのオプションをコンマ区切りのリストにして入力します。ただし、他の gcc オプションには、スペース区切りのリストにしてオプションを指定する必要があります。
gcc が使用する ld リンカーには、-Bstatic
と -Bdynamic
のオプションがあり、このオプションの後に来るライブラリーが静的または動的にリンクすべきかどうかを指定します。-Bstatic
とライブラリーをリカーに渡した後、以降のライブラリーを -Bdynamic
オプションで動的にリンクするには、デフォルトの動的リンクの動作を手動で復元する必要があります。
プログラムをリンクするには、first ライブラリーを静的にリンク (libfirst.a
) して、second ライブラリーを動的にリンク (libsecond.so
) します。
$ gcc ... -Wl,-Bstatic -lfirst -Wl,-Bdynamic -lsecond ...
gcc は、デフォルトの ld 以外のリンカーを使用するように設定できます。
関連情報
- GNU コンパイラーコレクション (GCC) の使用 - 3.14 Options for Linking
- binutils 2.27 のドキュメント - 2.1 Command Line Options