第16章 GCC でのライブラリーの使用

この章では、コード内でのライブラリーの使用について説明します。

16.1. ライブラリーの命名規則

特別なファイルの命名規則をライブラリーに使用します。foo として知られるライブラリーは、libfoo.so または libfoo.a ファイルとして存在する必要があります。この規則は、リンクする GCC の入力オプションで、自動的に理解されますが、出力オプションでは理解されません。

  • ライブラリーにリンクする場合には、-lfoo のように、-l オプションと foo の名前でしか、ライブラリーを指定することはできません。

    $ gcc ... -lfoo ...
  • ライブラリーの作成時には、libfoo.so または libfoo.a など、完全なファイル名を指定する必要があります。

関連資料

16.2. 静的リンクおよび動的リンク

開発者には、完全にコンパイルした言語でアプリケーションを構築する際に、静的または動的のリンクを使用することが選択できます。本セクションでは、Red Hat Enterprise Linux で C 言語および C++ 言語した場合の違い (特にコンテキストについて) を説明します。つまり、Red Hat は、Red Hat Enterprise Linux 用のアプリケーションで静的リンクを使用することを推奨しません。

静的リンクおよび動的リンクの比較

静的リンクは、結果として作成された実行ファイルのライブラリーの一部になります。動的リンクは、このライブラリーを別々のファイルとして保持します。

動的リンクおよび静的リンクは、いくつかの方法で比較できます。

リソースの使用

静的リンクにでは、含まれるコードが増えるため、実行ファイルが大きくなります。ライブラリーから追加されるこのコードは、システム内の複数のプログラムで共有できるため、ランタイム時のファイルシステムの使用と、メモリーの使用が増えます。静的にリンクされた同じプログラムを実行する複数のプロセスは、依然としてそのコードを共有します。

一方、静的なアプリケーションでは、必要なランタイムの再配置がより少なくなるため、起動時が短くなり、必要なプライベートの RSS (Resident Set Size) メモリーも少なくなります。静的リンクに生成されるコードは、PIC (Position-Independent Code) により導入されるオーバーヘッドにより、動的リンクよりも効果的になります。

セキュリティー

ABI 互換性を提供する動的にリンクされたライブラリーは、そのライブラリーに依存する実行ファイルを変更せずに更新できます。これは、特に、Red Hat Enterprise Linux の一部として Red Hat がセキュリティー更新を提供するライブラリーで重要になります。このようなライブラリーには静的リンクを使用しないことが強く推奨されます。

さらに、ロードアドレスのランダム化などのセキュリティー対策は、静的にリンクされた実行ファイルで使用することはできません。これにより、アプリケーションのセキュリティーが低減します。

互換性

静的リンクは、オペレーティングシステムが提供するライブラリーのバージョンに依存しない実行ファイルを提供するように見えます。ただし、大概のライブラリーは、他のライブラリーに依存しています。静的リンクでは、この依存関係は柔軟性に欠けるとなり、結果として、前方互換性と後方互換性が失われます。静的リンクは、実行ファイルが構築されたシステムでのみ動作することが保証されます。

警告

GNU C ライブラリー (glibc) から静的にライブラリーをリンクするアプリケーションでは、システムに動的ライブラリーとして存在する glibc が依然として必要になります。さらに、アプリケーションのランタイム時に利用できる glibc の動的ライブラリーのバリアントは、アプリケーションをリンクしている間に存在するものとビット単位で同じバージョンである必要があります。そのため、静的リンクは、実行ファイルが構築されたシステムでのみ動作することが保証されます。

サポート範囲
Red Hat が提供するほとんどの静的ライブラリーは Optional チャンネルにあり、Red Hat ではサポートされていません。
機能

いくつかのライブラリー (特に GNU C ライブラリー (glibc)) は、静的にリンクすると提供する機能が少なくなります。

たとえば、静的にリンクすると、glibc は、スレッドと、同じプログラム内の dlopen() 関数への呼び出しの形式をサポートしません。

記載されたデメリットにより、静的リンクは、特にアプリケーション全体、glibc ライブラリー、および libstdc++ ライブラリーに対しては、使用しないようにする必要があります。

注記

compat-glibc パッケージは Red Hat Enterprise Linux 7 に含まれますが、ランタイムパッケージではないため、何も実行する必要がありません。これは、リンクのためのヘッダーファイルとダミーのライブラリーが含まれる開発パッケージでしかありません。これにより、以前の Red Hat Enterprise Linux バージョンを実行するパッケージのコンパイルおよびリンクができるようになります (ヘッダーやライブラリーに compat-gcc-\* を使用)。このパッケージの使用の詳細は、rpm -qpi compat-glibc-* を実行します。

静的リンクの理由

静的リンクは、次のようないくつかのケースでは合理的な選択が可能です。

  • 動的リンクが使用できないライブラリー
  • 完全に静的なリンクは、空の chroot 環境またはコンテナーでコードを実行するのに必要になる場合がありますが、glibc-static パッケージを使用した静的リンクは、Red Hat ではサポートされていません。

関連資料

16.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 つの手順でライブラリーを使用するコードをコンパイルとリンクする方法

gcc コマンド 1 つでコードをコンパイルリンクできる場合には、上記のオプションを一度に使用します。

関連資料

16.4. GCC での静的ライブラリーの使用

静的ライブラリーは、オブジェクトファイルを含むアーカイブファイルとして提供します。リンク後には、これは、作成される実行ファイルの一部になります。

注記

Red Hat は、さまざまな理由から静的リンクを使用することは推奨していません。「静的リンクおよび動的リンク」を参照してください。特に Red Hat が提供するライブラリーに対してリンクする場合など、必要な場合にのみ、静的リンクを使用するようにしてください。

前提条件

注記

Red Hat Enterprise Linux の一部であるほとんどのライブラリーは、動的リンクでのみサポートされています。以下の手順は、動的リンクで 有効ではない ライブラリーにのみ有効です。「GCC で静的および動的ライブラリー両方の使用」を参照してください。

ステップ

ソースとオブジェクトファイルからのプログラムをリンクするには、静的にリンクされたライブラリー foo (libfoo.a として検索可能) を追加します。

  1. コードが含まれるディレクトリーに移動します。
  2. foo ライブラリーのヘッダーで、プログラムソースファイルをコンパイルします。

    $ gcc ... -Iheader_path -c ...

    header_path は、foo ライブラリーのヘッダーファイルを含むディレクトリーへのパスに置き換えます。

  3. プログラムを foo ライブラリーとリンクします。

    $ gcc ... -Llibrary_path -lfoo ...

    library_pathlibfoo.a ファイルを含むディレクトリーへのパスに置き換えます。

  4. あとでプログラムを実行するには、以下を実行するだけです。

    $ ./program
注意

静的リンクに関連する -static GCC オプションでは、動的リンクを使用できません。代わりに、-Wl,-Bstatic オプションおよび -Wl,-Bdynamic オプションを使用して、リンカーの動作を正確に制御してください。「GCC で静的および動的ライブラリー両方の使用」 を参照してください。

16.5. GCC での動的ライブラリーの使用

動的ライブラリーは、スタンドアロンの実行可能ファイルとして提供します。このファイルは、リンク時、ランタイム時に必要です。これらのファイルは、アプリケーションの実行ファイルからは独立しています。

前提条件

プログラムの動的ライブラリーへのリンク

動的ライブラリー 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

16.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 オプションとは異なります。このオプションの後に、リンカーのオプションのコンマ区切りのリストを指定して、スペースで区切る gcc オプションと混同されないようにします。

gcc が使用する ld リンカーには、-Bstatic-Bdynamic のオプションがあり、このオプションの後に来るライブラリーが静的、または動的にリンクすべきかどうかを指定します。-Bstatic とライブラリーをリカーに渡した後、以降のライブラリーを -Bdynamic オプションで動的にリンクするには、デフォルトの動的リンクの動きを手動で復元する必要があります。

プログラムをリンクするには、まず 静的に (libfirst.a) ライブラリーをリンクして、ルギに 動的に (libsecond.so) リンクします。

$ gcc ... -Wl,-Bstatic -lfirst -Wl,-Bdynamic -lsecond ...
注記

gcc は、デフォルトの ld 以外のリンカーを使用するように設定できます。-Wl オプションは、gold リンカーにも適用されます。

関連資料