第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 (homeal Set Size) メモリーも少なくなります。静的リンク用に生成されたコードは、PIC (位置独立コード) により発生するオーバーヘッドにより、動的リンクよりも効率が良くなります。

セキュリティー

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 は、ライブラリーディレクトリーのパスに置き換えます。

-L オプションは複数回使用して、ディレクトリーを複数追加できます。ライブラリーを検索する場合は、-L オプションの表示順に、これらのディレクトリーが検索されます。

オプションの指定順は重要です。対象のライブラリーがディレクトリーにリンクされていることが分からないと、GCC は、ライブラリー foo をリンクできません。そのため、-L オプションを使用して先にライブラリーディレクトリーを指定してから、-l オプションでライブラリーをリンクするようにしてください。

ライブラリーを使用するコードを 1 つの手順でコンパイルし、リンクする方法

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

関連資料

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

静的なライブラリーは、オブジェクトファイルを含むアーカイブとして利用できます。リンク後、それらは作成された実行可能ファイルの一部となります。

注記

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

前提条件

注記

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

手順

ソースとオブジェクトファイルからプログラムをリンクするには、静的にリンクされた、libfoo.a という名前の foo ライブラリーを追加ます。

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

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

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

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

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

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

  4. プログラムを実行するには、以下を行います。

    $ ./program
注意

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

16.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

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 オプションとは異なります。-Wl オプションの後に、リンカーのオプションをコンマ区切りのリストにして入力します。ただし、他の gcc オプションには、スペース区切りのリストにしてオプションを指定する必要があります。gcc が使用する ld リンカーには、-Bstatic-Bdynamic のオプションがあり、このオプションの後に来るライブラリーを静的または動的にリンクすべきかどうかを指定します。-Bstatic とライブラリーをリンカーに渡した後、後続のライブラリーを -Bdynamic オプションで動的にリンクするには、デフォルトの動的リンクの動作を手動で復元する必要があります。

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

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

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

関連資料


このページには機械翻訳が使用されている場合があります (詳細はこちら)。