[ << ] [ >> ]           [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 を用いたプログラムで設定可能です.

  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_dlsetsearchpath (const char *search_path)

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

Function: const char * lt_dlgetsearchpath (void)

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

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で呼び出し可能な,少なくとも3つの関数を書くことを必要と します.オプションで,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_dlloader_data

lt_dlloader_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_dlloader_data dlloader_data; }

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

Type: lt_module lt_module_open (lt_user_data loader_data, 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_dlloader_data loader_data, lt_module module)

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

Type: lt_ptr lt_find_sym (lt_user_data loader_data, 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'を インクルードするプログラムをコンパイルするために使用するプリプロセッサフ ラグINCLTDLを定義します.この変数が`Makefile'で利用可能にする ことを確実にするため`AC_SUBST'を使用したり,デフォルトで `AC_SUBST'される,LIBSCPPFLAGSのような変数に加えるの はあなた次第です.

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

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

そのため,libltdlとプログラムをリンクしたいときは,それをインストールさ れたまたはインストール可能な便利なライブラリにし,すなわち,libtoolを使 用して,`$(INCLTDL)'を用いてコンパイルし,`$(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 INCLTDL and LIBLTDL in the Makefiles
AC_SUBST(INCLTDL)
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 = $(INCLTDL)

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.