[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

10. libltdlの使用

libtoolは,`libltdl'と呼ばれる小さなライブラリを提供し,それは, dlopenライブラリの様々な困難をプログラマから隠すことを目指します.それ は,dlopenの機能で必要とされるアプリケーションとともに配布可能な,ヘッ ダファイルと小さなCソースファイルから成り立ちます.`libltdl'サー ビスの単純な実装に対し,あまりに制限が多いダイナミックリンカをもつプラッ トフォーム上では,GNU DLDを要求したり,libtoolのdlpreopenメカニズムを 用いてダイナミックリンクをエミュレートするだけのものもあります.

libltdlは,現在以下のダイナミックリンクメカニズムをサポートします.

以下の例外で,libltdlはGNUライブラリ公有使用許諾書の条件下でライセンス されています.

GNU Lesser General Public Licenseの特別な例外として,GNU libtoolを使用 してビルドされるプログラムやライブラリの一部としてこのファイルを配布す る場合,プログラムの残りに対して使用する配布条件と同じものにして,それ を含めることができます.


10.1 プログラムでのlibltdlの使用法

libltdl APIは,強力なSolarisとLinuxのdlopenインターフェースに似ていて, それは,非常に簡単ですが強力です.

プログラムでlibltdlを使用するために,ヘッダファイル`ltdl.h'をイン クルードする必要があります.

 
#include <ltdl.h>

libltdlの前回のリリースでは,POSIX名前空間の慣習に違反していたシ ンボルをいくつか使用していました.これらのシンボルの使用は,現在では非 難されるので,ここで記述されるように置換されました.古い非難されそうな シンボル名に依存したコードがある場合,`ltdl.h'をインクルードする 前に`LT_NON_POSIX_NAMESPACE'を定義すると,変換されたマクロが提供 されます.使用するシンボルの組が何であっても,新しいAPIは前回のものと バイナリ互換ではないので,このバージョンのlibltdlを使用するため,アプ リケーションを再コンパイルする必要があるでしょう.

libltdlがスレッドセーフでない,すなわち,マルチスレッドアプリケーショ ンは,libtoolに対しミューテックスを使用する必要があることに注意してく ださい.それは,GNU/Linuxのglibc 2.0の`RTLD_LAZY'を用いた dlopenが(デフォルトでlibtoolを使用します),スレッドセーフではな いことが報告されていますが,この問題は,glibc 2.1でおそらく修正される でしょ.一方,`RTLD_NOW'は,FreeBSD上のマルチスレッドアプリケーショ ンで問題が生じたと報告されています.これらの問題に関する作業は,読者の 演習として残っています.貢献は,きっと歓迎されます.

以下の型は`ltdl.h'で定義されています.

Type: lt_ptr

lt_ptrは,汎用ポインタです.

Type: lt_dlhandle

lt_dlhandleはモジュール"ハンドル"です.すべてのlt_dlopenされる モジュールはそれに関連付けされたハンドルがあります.

Type: lt_dlsymlist

lt_dlsymlistはdlpreopenされるモジュールのシンボルリストです.こ の構造体は,see section dlopenで記述されます.

libltdlは以下の関数を提供します.

Function: int lt_dlinit (void)

libltdlを初期化します.この関数は,libltdl使用する前に呼び出す必要があ り,複数回呼び出すことが可能です.成功したら0,それ以外ではエラーの番 号を返します.

Function: int lt_dlexit (void)

libltdlを終了し,すべてのモジュールを閉じます.この関数は, lt_dlinitが正常に呼び出された回数と同じだけ呼び出されたとき, libltdlを終了するだけです.成功したら0,それ以外ではエラーの番号を返し ます.

Function: lt_dlhandle lt_dlopen (const char *filename)

ファイル名filenameを用いてモジュールを開き,そのハンドルを返しま す.lt_dlopenは,libtoolダイナミックモジュール,プリロードされ たスタティックモジュール,プログラム自身,そしてネイティブなダイナミッ クライブラリを開くことが可能です.

モジュール内の未解決のシンボルは,それが依存する(まだ実装されていない) ライブラリと,前もってdlopenされたモジュールを用いて解決されます.この モジュールを使用している実行形式が-export-dynamicフラグでリンク されている場合,実行形式の大域的なシンボルもモジュール内の参照の解決に 使用されます.

filenameNULLでプログラムが-export-dynamic-dlopen selfを用いてリンクされている場合,lt_dlopenはプ ログラム自身のハンドルを返し,それはそのシンボルのアクセスに使用可能で す.

libltdlがライブラリを見つけられず,ファイル名filenameがディレク トリコンポーネントを持たない場合,それは,以下の検索パスを(以下の順番 で),さらにモジュールを検索します.

  1. ユーザ定義の検索パス: この検索パスは,関数lt_dlsetsearchpathlt_dladdsearchdir,そしてlt_dlinsertsearchdirを用いたプ ログラムで変更可能です.

  2. libltdlの検索パス: この検索パスは,環境変数LTDL_LIBRARY_PATHの値です.

  3. システムのライブラリ検索パス: システム依存のライブラリ検索パスです(例えば,Linuxでは LD_LIBRARY_PATHになります).

それぞれの検索パスは,例えば"/usr/lib/mypkg:/lib/foo"のように, コロンで分離された絶対的なディレクトリのリストにする必要があります.

同じモジュールが複数回ロードされた場合,同じハンドルが返されます.あら ゆる原因でlt_dlopenが失敗した場合,NULLが返されます.

Function: lt_dlhandle lt_dlopenext (const char *filename)

ファイル名に異なるファイル名の拡張子を追加を試みる以外は, lt_dlopenと同じです.ファイル名filenameを持つファイルが見 つからない場合,libltdlは,以下の拡張子の追加を試みます.

  1. libtoolのアーカイブ拡張子`.la'

  2. ホストプラットフォームの本来のダイナミックライブラリに使用される拡張子 で,例えば,`.so',`.sl'等です.

この探索手法は,本来のダイナミックライブラリの命名規則を知らないプログ ラムが,そのようなライブラリを,libtoolモジュールと同様に,透過的に dlopenすることを可能にするために設計されています.

Function: int lt_dlclose (lt_dlhandle handle)

モジュールhandleの参照カウントを減らします.ゼロになったり,この モジュールに依存する他のモジュールがない場合,モジュールはアンロードさ れます.成功時には0を返します.

Function: lt_ptr lt_dlsym (lt_dlhandle handle, const char *name)

モジュールhandle内のアドレスを返し,そこでは,ヌルで終端された文 字列nameで与えられるシンボルがロードされています.シンボルが見つ からない場合はNULLを返します.

Function: const char * lt_dlerror (void)

libltdlのあらゆる関数から発生した最も新しいエラーを記述する,可読性の 高い文字列を返します.初期化からまたは最後に呼び出されてからエラーが発 生していない場合,NULLを返します.

Function: int lt_dlpreload (const lt_dlsymlist *preloaded)

プリロードされているモジュールpreloadedのリストを登録します. preloadedNULLの場合,lt_dlpreload_defaultで設定 されているリスト以外の,これまで登録されているすべてのシンボルリストが 検出されます.成功時には0を返します.

Function: int lt_dlpreload_default (const lt_dlsymlist *preloaded)

プリロードされているモジュールリストのデフォルトをpreloadedに設 定し,それはlt_dlpreloadで検出されません.この関数は, lt_dlinitを使用して初期化されるためにlibltdlを要求しない ことと,デフォルトでプリロードされるモジュールを登録するためにプログラ ムで使用できることに注意してください.この関数を直接呼び出す代わりに, ほとんどのプログラムはマクロLTDL_SET_PRELOADED_SYMBOLSを使用し ます.

成功時には0を返します.

Macro: LTDL_SET_PRELOADED_SYMBOLS

プリロードされるシンボルのデフォルトリストを設定します.プリロードされ るlibltdlのモジュールを初期化するために,プログラムで使用した方が良い でしょう.

 
#include <ltdl.h>

int main() {
  /* ... */
  LTDL_SET_PRELOADED_SYMBOLS();
  /* ... */
}
Function: int lt_dladdsearchdir (const char *search_dir)

検索ディレクトリsearch_dirを現在のユーザ定義のライブラリ検索パス に後置します.成功時には0を返します.

Function: int lt_dlinsertsearchdir (const char *before, const char *search_dir)

検索ディレクトリsearch_dirをユーザ定義のライブラリ検索パスを,ア ドレスbeforeで始まる項目の直前に挿入します.beforeが `NULL'の場合,lt_dladdsearchdirが呼び出されたのと同様に後 置します.成功時には0を返します.

Function: int lt_dlsetsearchpath (const char *search_path)

現在のユーザ定義のライブラリ検索パスをsearch_pathで置換し,それ はコロンで分けられた絶対的なディレクトリのリストにする必要があります. 成功時には0を返します.

Function: const char * lt_dlgetsearchpath (void)

現在のユーザ定義のライブラリ検索パスを返します.

Function: int lt_dlforeachfile (const char *search_path, int (*func) (const char *filename, lt_ptr data), lt_ptr data)

アプリケーションによっては,既知の名前でモジュールを個別にロードしたく なく,むしろディレクトリの組みからすべてのモジュールを見つけたり,初期 化中にすべてロードしたいかもしれません.この関数を用いると,libltdlに 候補となるsearch_path内のコロンで分離されたディレクトリリストを 走査させ,それらを独自のコールバック関数funcに渡すdataと併 せて渡すことが可能です.seach_pathが`NULL'の場合, lt_dlopenが調査する標準的な場所をすべて検索します.この関数は, これらの呼び出しの一つでもゼロ以外の値が返されるまで,またはファイルが 亡くなるまで,search_pathで見つかったそれぞれのファイルに対し, funcを呼び出し続けます.`lt_dlforeachfile'は最後の funcの呼び出しの返り値を返します.

例えば,最初のベクトル(配列)のアドレスを保持しているdataを使用し ているファイルの,順番になっているargvのようなベクトル(配列)を構 築するために,funcを定義することも可能です.

Function: int lt_dlmakeresident (lt_dlhandle handle)

モジュールを`lt_dlclose'できないように印を付けます.モジュールが プロジェクトの中心部の機能を実装している場合,削除されるとコードが壊れ るので,これは役に立つはずです.成功すると0を返します.

実行しているバイナリに対するhandleを取得するために `lt_dlopen (NULL)'を使用する場合,そのハンドルは常駐しているよう な印が常に付き,したがってうまく`lt_dlclose'することができません.

Function: int lt_dlisresident (lt_dlhandle handle)

特定のモジュールが常駐しているように印が付いているかどうか調査し,その 場合は1を返し,それ以外では0を返します.この関数の実行中にエラーがある 場合, -1 が返され,lt_dlerrorを用いて回収されるエラーメッセー ジが設定されます.

Variable: lt_ptr (*) (size_t size) lt_dlmalloc
Variable: void (*) (lt_ptr ptr) lt_dlfree

これらの変数は,デフォルトでmallocfreeに設定されますが, 同等の機能を提供する他の関数に設定可能です.しかし, lt_dlpreopen_defaultやマクロLTDL_SET_PRELOADED_SYMBOLS以 外のあらゆるlibltdl関数の呼び出し後に,その値を編集すべきではありませ ん.


10.2 dlopen可能なモジュールの作成

libtoolモジュールは,いくつかの例外はありますが,通常のlibtoolライブラ リに似ています.

libtoolの`-module'スイッチを用いて,モジュールとリンクする必要が あり,そして,dlopenをサポートしていないプラットフォームでlibtoolが dlpreopenできるよう,`-dlopen modulename.la'を用いてモジュールを dlopenするために,あらゆるプログラムとリンクすべきです.モジュールが, あらゆる他のライブラリに依存する場合,モジュールとリンクするときや,そ れをdlopenするプログラムをリンクするとき,それらを確実に指定してくださ い.特定のモジュールに対しsee section ライブラリインターフェースのバージョンを使用禁止にしたい場合, `-avoid-version'スイッチを用いてリンクすべきです.libtoolモジュー ルは,"lib"接頭辞が不要なことに注意してください.しかし,automake 1.4 やそれ以降のものは,そのようなモジュールのビルドが必要です.

通常,その内部を知る必要なしにプログラムがdlopenできるよう,一組のモ ジュールは同じインターフェース提供し,すなわち同じシンボルをエクスポー トします.すべてのエクスポートされたシンボルで,シンボルの衝突を避ける ため,"modulename_LTX_"を前置する必要があります(`modulename'はモ ジュール名です).内部シンボルは,例えば"_modulename_"を前置するといっ た,他のモジュールと衝突しないような方法で命名する必要があります.一回 以上宣言された,同じシンボルを持つことをサポートするシステムもあります がそれは通常移植性がなく,そのようなモジュールをdlpreopenすることを不 可能にします.libltdlは,シンボルの本当の名前を得るとき,自動的に接頭 辞を切り取ります.さらに,非libtoolモジュールもdlopenできるよう,接頭 辞を使用していないモジュールをサポートします.

`foo1.c'は移植可能なlibtoolモジュールの例です.エクスポートされた シンボルは"foo1_LTX_",内部シンボルは"_foo1_"が前置されています.コー ドの可読性を高めるため,エイリアスは最初に定義されています.

 
/* aliases for the exported symbols */
#define foo	foo1_LTX_foo
#define bar	foo1_LTX_bar

/* a global variable definition */
int bar = 1;

/* a private function */
int _foo1_helper() {
  return bar;
}

/* an exported function */
int foo() {
  return _foo1_helper();
}

`Makefile.am'は,モジュール`foo1.la'をビルドするのに必要な規 則を含んでいます.

 
...
lib_LTLIBRARIES = foo1.la

foo1_la_SOURCES = foo1.c
foo1_la_LDFLAGS = -module
...

10.3 マルチスレッド環境でのlibtldlの使用

lt_dlmutex_register()関数を使用し,適切なコールバック関数の定義 を提供することで,libltdlをマルチスレッド環境で使用することが可能です.

Type: void lt_dlmutex_lock (void)

これは,ミューテックスロックが必要なlibltdlの実装コードの部分の,最初 に呼び出される関数のアドレスを持っている,関数のポインタ型です.

libltdlは本質的に再帰的なので,これらのコールバック関数によって使用さ れるロックメカニズムが再入可能であることは重要で,そうでなければ,おか しな問題が発生します.

Type: void lt_dlmutex_unlock (void)

アンロック関数に一致する型です.

Type: void lt_dlmutex_seterror (const char *error);

libltdl APIの関数の多くは,エラーを発生したクライアントを示す,特 殊な返り値をとります.通常(シングルスレッドアプリケーションでは),内部 から回収することができるエラーを記述する文字列は,lt_dlerror() に保存されます.

この形式の関数は,それがマルチスレッドのコンテクストで動作するように, ライブラリに登録される必要があります.関数は,スレッドローカルストレー ジに渡されるあらゆるエラーメッセージを保存すべきです.

Type: const char * lt_dlmutex_geterror (void)

スレッドローカルのストレージに,最後にエラーメッセージを保存したものに 関連するコールバック関数に一致する型です.

正しく登録されたとき,クライアントに対するエラーメッセージを回収するた めに,全てのスレッドからlt_dlerror())によって,この関数は使用さ れます.

Function: int lt_dlmutex_register (lt_dlmutex_lock *lock, lt_dlmutex_unlock *unlock, lt_dlmutex_set_error *seterror, lt_dlmutex_geterror *geterror)

libltdlのマルチスレッドの準備で,上記のそれぞれの関数の型を登録するた めに,この関数を使用してください.全ての引数は,有効なNULLでな い関数アドレスにする必要があり,また,そうでない場合は,シングルスレッ ドオペレーションへの返り値として,全てNULLにする必要があります.


10.4 ロードされたモジュールに関連するデータ

libltdlが管理している,それぞれのロードされたモジュールに関する内部情 報には,ユーザが利用可能なものもあり,それは以下のような構造体の形式で す.

Type: struct lt_dlinfo { char *filename; char *name; int ref_count; }

lt_dlinfoは,モジュールの情報を保存するために使用されます. filename属性は,NULLで終端された,実際のモジュールファイ ル名の文字列です.モジュールがlibtoolモジュールの場合,nameはそ のモジュール名(例えば,"dir/libfoo.la"に対する"libfoo") で,それ以外ではNULLに設定されます.ref_count属性は,現在 ロードされている同じモジュールの回数を記述する参照カウンタです.

以下の関数は,与えられたhandleに対するこの構造体のlibltdlの内部 のコピーへのポインタを返します.

Function: const lt_dlinfo * lt_dlgetinfo (lt_dlhandle handle)

モジュールhandleに関するいくつかの情報を含む構造体の,ポインタを 返します.構造体の内容は編集してはなりません.失敗時にはNULLが 返ります.

さらに,ロードした全てのモジュールのハンドルリストを保持する手助けをす るために,これらの関数で,ロードされているモジュールのlibltdlのリスト 全体を繰り返すことが可能となります.

Function: int lt_dlforeach (int (*func) (lt_dlhandle handle, lt_ptr data), lt_ptr data)

ロードされているそれぞれのモジュールに対し関数funcを呼び出します. 引数のhandleは,ロードされているモジュールのハンドルの一つで, dataは,lt_dlforeachに渡すdata引数です.func がハンドルの一つに対し,ゼロでない値を返すとすぐに, lt_dlforeachfuncの呼び出しを停止し,直ちに1を返します. それ以外は0が返ります.

Function: lt_dlhandle lt_dlhandle_next (lt_dlhandle place)

placeNULLの場合は,リスト内の最初のハンドルを返し,そし て順番に次ものを呼び出すことで,ロードされているモジュール全体を繰り返 します.placeが,ロードされているモジュールリスト内の最後の要素 の場合,この関数はNULLを返します.

もちろん,アプリケーションの目的のために,それぞれのハンドルに関連付け する必要があるデータがある場合,libltdlで管理されるリストと平行して, ロードされたモジュールハンドルの独自のリストの管理が必要になります.し かし,個別のモジュールハンドルを用いたアプリケーションデータに,ロード されたものとして関連付けさせるために,以下のAPIの呼び出しを使用す る場合には,実際にはそうする必要はありません.前もって保存したデータを 回収するために後で利用するlibltdlからのユニークな呼び出しidを,最初に 取得する必要があります.これで,ロードされているモジュールに対する独自 のデータを個別に保存したい異なるライブラリが,もう一つの(ライブラリ)の データへのインターフェースなしでそれを行うことが可能となります.

Type: lt_dlcaller_id

個別のデータセットのキーを保つ,透過でない型です.

Function: lt_dlcaller_id lt_dlcaller_register (void)

モジュールデータごとに個別のセットを,保存し回収するためのユニークなキー を取得するために,これを使用してください.

Function: lt_ptr lt_dlcaller_set_data (lt_dlcaller_id key, lt_dlhandle handle, lt_ptr data)

後で回収するために,keyhandleにユニークに関連付けされた データのセットとして,dataを設定します.この関数は,以前に関連付 けされたkeyhandleがある場合は,そのdataを返します. 0の結果は,前回のエラー(が存在する場合)に対する診断結果が, lt_dlerror() で利用可能であることを示している可能性があります.

例えば,いくつかの関連データを正しく削除するために,以下のようにします.

 
    lt_ptr stale = lt_dlcaller_set_data (key, handle, 0);
    if (stale == NULL)
      {
        char *error_msg = lt_dlerror ();

        if (error_msg != NULL)
          {
            my_error_handler (error_msg);
            return STATUS_FAILED;
          }
      }
    else
      {
        free (stale);
      }
Function: lt_ptr lt_dlcaller_get_data (lt_dlcaller_id key, lt_dlhandle handle)

keyhandleに関連付けされているdataのアドレス,また は,無い場合はNULLを返します.

ここまでの関数は,アプリケーションにロードされたりアンロードされたりし たモジュールを追跡させる必要なく,オペレーションの検索と適用を実装する ために,lt_dlforeachと組み合わせることが可能です.

 
int
my_dlcaller_callback (lt_dlhandle handle, lt_ptr key_ptr)
{
  struct my_module_data *my_data;

  my_data = lt_dlcaller_get_data (handle, (lt_dlcaller_id) *key_ptr);

  return process (my_data);
}

int
my_dlcaller_foreach (lt_dlcaller_id key)
{
  lt_dlforeach (my_dlcaller_callback, (lt_ptr) &key);
}

10.5 新しいモジュールローダの作成方法と登録方法

モジュールにアクセスするためのlibltdlの方法は多いけれど,プロジェクト の目的に十分でないときもあります.独自のローダを書き,lt_dlopen が利用できるように,libltdlでそれを登録することが可能です.

ローダを書くことは,lt_dlopenlt_dlsymそして lt_dlcloseで呼び出し可能な,少なくとも三つの関数を書くことを必 要とします.オプションで,lt_dlexitが実行されるときクリーンアッ プ処理を実行する終了関数と,lt_dlsymに渡されるあらゆるシンボル に前置されるシンボルの前置文字を提供することも可能です.これらの関数は, 以下の関数のポインタ型に一致する必要があり,その後,それらを lt_user_dlloaderの代わりに関連付けし,登録することが可能です.

ローダの登録には,lt_dlloader_findが認識でき, lt_dlloader_removeで削除できるように,それに対する名前を選択す ることが必要です.選択した名前はユニークである必要があり,libltdlの組 み込みローダで既に使用しているものはいけません.

"dlopen"

存在する場合は,システムのダイナミックローダ.

"dld"

libltdlがビルドされたときに`libdld'がインストールされている場合は, GNU dldローダ.

"dlpreload"

プリロードされているスタティックモジュールのlt_dlopenのためのロー ダ.

前置される"dl"は,libltdlの将来のバージョンで提供されるローダとして予 約されているので,独自のローダ名に使用すべきではありません.

以下の型は,`ltdl.h'で定義されています.

Type: lt_module

lt_moduleはモジュール依存のdlloaderです.ダイナミックモジュール ローダの拡張は,これらの低レベルの型を使用して通信を行ないます.

Type: lt_dlloader

lt_dlloaderはモジュールローダの型に対するハンドルです.

Type: lt_user_data

lt_user_dataはローダのインスタンスデータに対して使用されます.

Type: struct lt_user_dlloader {const char *sym_prefix; lt_module_open *module_open; lt_module_close *module_close; lt_find_sym *find_sym; lt_dlloader_exit *dlloader_exit; }

ダイナミックモジュールを開くために新しい方法を定義したくて,それを使用 したlt_dlopen APIがある場合,これらの構造体のインスタンス を作成し,それをlt_dlloader_addに渡す必要があります.好みの dlloader_dataフィールドで渡すことが可能で,それは,関数ポインタ フィールドで指定されている,それぞれの関数への最初のパラメータの値とし て返されます.

Type: lt_module lt_module_open (const char *filename)

lt_dlloaderモジュールローダに対するローダ関数の型です. struct lt_user_dlloader構造体のdlloader_dataフィールドに設定さ れる値は,loader_dataパラメータで,この関数に渡されます.そのよ うな関数の実装は,指名されたモジュールのロードを試み,関連する lt_module_closelt_sym_find関数のポインタに渡すのに適切 なlt_moduleを返すべきです.関数が失敗した場合はNULLを返 し,lt_dlseterrorを用いてエラーメッセージを設定すべきです.

Type: int lt_module_close (lt_user_data loader_data, lt_module module)

ユーザが定義したモジュールローダに対するアンローダの型です.そのような 関数の実装は,moduleモジュールに結び付けられたあらゆるリソースの 解放を試み,その後でメモリからアンロードすべきです.理由があって関数が 失敗した場合,lt_dlseterrorを用いてエラーメッセージを設定し,ゼ ロ以外を返すべきです.

Type: lt_ptr lt_find_sym (lt_module module, const char *symbol)

ユーザが定義したモジュールローダに対する,シンボルルックアップ関数の型 です.そのような関数の実装は,モジュールmodule内の指名された symbolのアドレスを返す,もしくは,検査が失敗した場合は,エラーメッ セージをlt_dlseterrorで設定し,NULLを返すべきです.

Type: int lt_dlloader_exit (lt_user_data loader_data)

ユーザが定義したモジュールローダに対する,終了関数の型です.そのような 関数の実装は,ローダに関連するあらゆるリソースを解放すべきで,それには lt_user_dlloaderdlloader_dataフィールド内部にあるユー ザが指定したあらゆるデータを含みます.NULLでない場合は,関数は lt_dlexitlt_dlloader_removeから呼び出されます.

例えば,以下のようにします.

 
int
register_myloader (void)
{
  lt_user_dlloader dlloader;

  /* User modules are responsible for their own initialisation. */
  if (myloader_init () != 0)
    return MYLOADER_INIT_ERROR;

  dlloader.sym_prefix    = NULL;
  dlloader.module_open   = myloader_open;
  dlloader.module_close  = myloader_close;
  dlloader.find_sym      = myloader_find_sym.
  dlloader.dlloader_exit = myloader_exit;
  dlloader.dlloader_data = (lt_user_data)myloader_function;

  /* Add my loader as the default module loader. */
  if (lt_dlloader_add (lt_dlloader_next (NULL), &dlloader, "myloader") != 0)
    return ERROR;

  return OK;
}

ローダに対する必要な初期化がある場合は,ローダが登録される前に手動で実 行する必要があることに注意してください - libltdlはユーザローダの初期 化を扱いません.

終了はlibltdlで扱われますが,dlloader_exitのコールバック が初期化フェーズの間に要求された,あらゆるリソースを解放することを確か めることは重要です.

libltdlは,独自のモジュールローダを書くために,以下の関数を提供します.

Function: int lt_dlloader_add (lt_dlloader *place, lt_user_dlloader *dlloader, const char *loader_name)

新しいモジュールローダを全てのローダリストに加え,それは,(placeNULLの場合は)最後のローダとして,それ以外ではplaceとし て渡されたローダの直前に加えます.loader_nameは,新しく登録され たローダが渡された場合,lt_dlloader_nameを返します,これらの loader_nameは,ユニークである必要があり,そうでない場合は, lt_dlloader_removelt_dlloader_findは動作不可能です.成 功に対し0を返します.

 
{
  /* Make myloader be the last one. */
  if (lt_dlloader_add (NULL, myloader) != 0)
    perror (lt_dlerror ());
}
Function: int lt_dlloader_remove (const char *loader_name)

ユニークな名前loader_nameで識別されているローダを削除します.こ れが成功可能となる前に,指名されたローダにより開かれている全てのモジュー ルを,閉じておく必要があります.成功に対し0を返し,それ以外では,エラー メッセージがlt_dlerrorから取得可能です.

 
{
  /* Remove myloader. */
  if (lt_dlloader_remove ("myloader") != 0)
    perror (lt_dlerror ());
}
Function: lt_dlloader * lt_dlloader_next (lt_dlloader *place)

ローダモジュール全体を繰り返し,それは,placeNULLの場合 は最初のローダを返し,順番に次を呼び出すことで行います.ハンドルは, lt_dlloader_add用です.

 
{
  /* Make myloader be the first one. */
  if (lt_dlloader_add (lt_dlloader_next (NULL), myloader) != 0)
    return ERROR;
}
Function: lt_dlloader * lt_dlloader_find (const char *loader_name)

loader_name識別子に一致する最初のローダを返し,識別子が見つから ない場合はNULLを返します.

libltdl自身で使用可能な識別子は,ホストアーキテクチャがサポートしてい る場合はdlopen(10)dld,そしてdlpreloadです.

 
{
  /* Add a user loader as the next module loader to be tried if
     the standard dlopen loader were to fail when lt_dlopening. */
  if (lt_dlloader_add (lt_dlloader_find ("dlopen"), myloader) != 0)
    return ERROR;
}
Function: const char * lt_dlloader_name (lt_dlloader *place)

lt_dlloader_nextlt_dlloader_findで取得される, PLACEの識別名を返します.この関数が失敗する場合,NULLを返 し,lt_dlerrorで回収するためのエラーを設定します.

Function: lt_user_data * lt_dlloader_data (lt_dlloader *place)

lt_dlloader_nextlt_dlloader_findで取得される, PLACEのアドレスを返します.この関数が失敗する場合,NULLを 返し,lt_dlerrorで回収するためのエラーを設定します.


10.5.1 ユーザモジュールローダでのエラー処理

Function: int lt_dladderror (const char *diagnostic)

この関数で,独自のエラーメッセージをlt_dlerrorに組み込むことが 可能となります.lt_dlerrorで返すための適切な診断メッセージに渡 すものと,lt_dlseterrorで使用されるエラー識別子が返されます.

識別子の割り当てが失敗した場合,この関数は-1を返します.

 
int myerror = lt_dladderror ("Doh!");
if (myerror < 0)
  perror (lt_dlerror ());
Function: int lt_dlseterror (int errorcode)

独自のモジュールローダを書くとき,lt_dlerrorインターフェースを 通じて伝搬されるようにエラーを発生させるために,この関数を使用すべきで す.libltdlで使用される標準エラーの全ては,`ltdl.h'で宣言されてい て,そうでなければ,lt_dladderrorを用いて独自に書き加えることが 可能です.

 
if (lt_dlseterror (LTDL_ERROR_NO_MEMORY) != 0)
  perror (lt_dlerror ());

10.6 パッケージとともにlibltdlを配布する方法

libltdlはlibtoolとともにインストールされるのですが,libtoolやlibltdlを インストールしていないパッケージユーザの利便性のため,パッケージの配布 物にlibltdlを含めたいと思うかもしれません.この場合,手動でパッケージ に加えるltdlオブジェクト,または,使用したいlibltdlの特色を決定 する必要があります.それは,コンビニエンスライブラリやインストール可能 なlibtoolライブラリです.

libltdlをッケージに加える最も簡単な方法は,ソースファイルの `ltdl.c'と`ltdl.h'をパッケージのソースディレクトリにコピーし, ソースの残りと一緒にリンクすることです.これの手助けをするため, autoconfのm4マクロが`ltdl.m4'で利用可能です.autoconfを実行する前 に,それらが`aclocal.m4'で利用可能かどうかを確かめる必要がありま す - automakeを使用している場合は`ltdl.m4'の内容を `acinclude.m4'に加え,そうでない場合は`aclocal.m4'に加えます. マクロを利用可能にした後,`ltdl.o'を正しくビルドするために必要な コンフィグレーション時の調査を実行するため,`AC_LIB_LTDL'マクロの 呼び出しを,パッケージの`configure.in'に加える必要があります.イ ンストールされているlibltdl やlibltdlに依存しているライブラリと,パケー ジのバイナリをリンクしようとする場合,この手法には問題があります.シン ボルの二重定義の問題があるかもしれません.

コンビニエンスライブラリの利点の一つは,インストールされていないという ことなので,libtoolを使用するという事実はユーザにとって明白ではなく, ユーザが以前にインストールしているlibtoolのバージョンを上書きしません. 一方,(例えば,バグフィックスといった)理由があって,libltdlをアップグ レードしたい場合,インストールされているバージョンのlibtoolを置き換え る代わりに,パッケージを再コンパイルする必要があります.しかし,プログ ラムやライブラリが以前にインストールされているバージョンのlibltdlを使 用しているライブラリとリンクする場合,リンカエラーが発生し実行時にクラッ シュするかもしれません.もう一つの問題は,一つ以上のlibtoolライブラリ へコンビニエンスライブラリをリンクできないことで,複製されたシンボルを 得る可能性があるので,そのときは,これらのライブラリを用いた単一のプロ グラムとリンクしてください.一般的に,libtoolを使用している他のライブ ラリに依存しないプログラムでは,コンビニエンスライブラリを問題なく使用 可能です.libltdlのこの特徴を利用可能にするため, `AC_LIBLTDL_CONVENIENCE'行を`configure.in'に, `AC_PROG_LIBTOOL'の前に加えた方が良いでしょう.

インストール可能なバージョンのlibltdlを選択するために,マクロ `AC_LIBLTDL_INSTALLABLE'の呼び出しを`configure.in'に, `AC_PROG_LIBTOOL'の前に加えた方が良いでしょう.このマクロ は,libltdlが既にインストールされているかどうか調査し,そうでない場合, ビルドしインストールされるパッケージlibltdlを埋め込むことを要求します. しかし,バージョン調査は実行されないことに注意してください.ユーザは, コンフィグレーションスイッチ`--enable-ltdl-install'を使用すること で,他のバージョンの存在に関係なく,テストを優先し,埋め込まれた libtoolをインストールする必要があるか決定することができます.

libtoolをパッケージに埋め込むため,libtoolizeコマンドラインに `--ltdl'のみ加えてください.それで,パッケージのサブディレクトリ `libltdl'にlibtoolのソースをコピーします.どちらのマクロも, `libltdl'ディレクトリの位置を指定する追加の引数を受け入れます.デ フォルトで,どちらのマクロも`${top_srcdir}/libltdl'を仮定します.

どのマクロを使用しても,`configure.in'は`AC_CONFIG_SUBDIRS' を使用して,libltdlをコンフィグレーションし,`Makefile'が,例えば, automakeのSUBDIRSを使用して,libtoolのディレクトリでサブmakeを開 始することを確実にするのはあなたです.どちらのマクロも,libltdlでリン クするために使用するリンクフラグのシェル変数LIBLTDLと, `ltdl.h'をインクルードするプログラムをコンパイルするために使用す るプリプロセッサフラグLTDLINCLを定義します.この変数が `Makefile'で利用可能にすることを確実にするため`AC_SUBST'を使 用したり,デフォルトで`AC_SUBST'される,LIBSCPPFLAGSのような変数に加えるのはあなた次第です.

コンビニエンスlibltdlを使用している場合,LIBLTDLはコンビニエンス libltdlのバージョンに対するパス名で,LTDLINCLはlibltdlを含むディ レクトリが続く`-I'になり,どちらも`${top_builddir}/',また は,`${top_srcdir}/'で,それぞれ始まります.

インストールされているlibltdlのバージョンを要求し,それが見つかった場 合(11)LIBLTDLは `-lltdl'に,LTDLINCLは空に設定されます(それは,libltdlがラ イブラリパスにある場合,`ltdl.h'がインクルードパスのどこかにある という,暗黙の仮定です).インストール可能なlibltdlのバージョンをビルド する必要がある場合,`${top_builddir}/'で始まるそのパス名は, LIBLTDLに保存され,LTDLINCLはコンビニエンスライブラリの場 合と同様に設定されます.

そのため,libltdlとプログラムをリンクしたいときは,それをインストール された,またはインストール可能なコンビニエンスライブラリにし,すなわち, libtoolを使用して,LTDLINCLを用いてコンパイルし, `$(LIBLTDL)'を用いてリンクしてください.

おそらく`AC_LIBTOOL_DLOPEN'も`configure.in'に, `AC_PROG_LIBTOOL'の前に加えた方が良く,そうしない場合は, libtoolはdlopenメカニズムがサポートされていないと仮定し,おそらく希望 していないdlpreopenに逆戻りします.

libltdlとプログラムをリンクするとき,-static-all-staticスイッチの使用を避けてください.dlopen関数はスタティッ クリンクに対して利用可能でない可能性があるので,これはすべてのプラット フォームで動作するわけではありません.

以下の例は,パッケージにコンビニエンスlibltdlを埋め込む方法を示します. インストール可能な形態を使用するために,`AC_LIBLTDL_CONVENIENCE' を`AC_LIBLTDL_INSTALLABLE'で置換してください.我々は,libltdlが `libtoolize --ltdl'を使用して埋め込まれていると仮定しています.

configure.inは以下のようになります.

 
...
dnl Enable building of the convenience library
dnl and set LIBLTDL accordingly
AC_LIBLTDL_CONVENIENCE
dnl Substitute LTDLINCL and LIBLTDL in the Makefiles
AC_SUBST(LTDLINCL)
AC_SUBST(LIBLTDL)
dnl Check for dlopen support
AC_LIBTOOL_DLOPEN
dnl Configure libtool
AC_PROG_LIBTOOL
dnl Configure libltdl
AC_CONFIG_SUBDIRS(libltdl)
...

Makefile.amは以下のようになります.

 
...
SUBDIRS = libltdl

INCLUDES = $(LTDLINCL)

myprog_LDFLAGS = -export-dynamic
# The quotes around -dlopen below fool automake <= 1.4 into accepting it
myprog_LDADD = $(LIBLTDL) "-dlopen" self "-dlopen" foo1.la
myprog_DEPENDENCIES = $(LIBLTDL) foo1.la
...

[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Akihiro Sagawa on June, 15 2005 using texi2html 1.70.