[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
libtoolは,`libltdl'と呼ばれる小さなライブラリを提供し,それは, dlopenライブラリの様々な困難をプログラマから隠すことを目指します.それ は,dlopenの機能で必要とされるアプリケーションとともに配布可能な,ヘッ ダファイルと小さなCソースファイルから成り立ちます.`libltdl'サー ビスの単純な実装に対し,あまりに制限が多いダイナミックリンカをもつプラッ トフォーム上では,GNU DLDを要求したり,libtoolのdlpreopenメカニズムを 用いてダイナミックリンクをエミュレートするだけのものもあります.
libltdlは,現在以下のダイナミックリンクメカニズムをサポートします.
dlopen
(Solaris,Linux,そして様々なBSD)
shl_load
(HP-UX)
LoadLibrary
(Win16とWin32)
load_add_on
(BeOS)
GNU DLD (スタティックライブラリに対するダイナミックリンクのエミュレーション)
libtoolのdlpreopen (see section dlopen)
以下の例外で,libltdlはGNUライブラリ公有使用許諾書の条件下でライセンス されています.
GNU Lesser General Public Licenseの特別な例外として,GNU libtoolを使用 してビルドされるプログラムやライブラリの一部としてこのファイルを配布す る場合,プログラムの残りに対して使用する配布条件と同じものにして,それ を含めることができます.
10.1 プログラムでのlibltdlの使用法 | How to use libltdl in your programs. | |
10.2 dlopen 可能なモジュールの作成 | Creating modules that can be dlopen ed.
| |
10.3 マルチスレッド環境でのlibtldlの使用 | Registering callbacks for multi-thread safety. | |
10.4 ロードされたモジュールに関連するデータ | Associating data with loaded modules. | |
10.5 新しいモジュールローダの作成方法と登録方法 | Creating user defined module loaders. | |
10.6 パッケージとともにlibltdlを配布する方法 | How to distribute libltdl with your package. |
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'で定義されています.
lt_ptr
は,汎用ポインタです.
lt_dlhandle
はモジュール"ハンドル"です.すべてのlt_dlopenされる
モジュールはそれに関連付けされたハンドルがあります.
lt_dlsymlist
はdlpreopenされるモジュールのシンボルリストです.こ
の構造体は,see section dlopenで記述されます.
libltdlは以下の関数を提供します.
libltdlを初期化します.この関数は,libltdl使用する前に呼び出す必要があ り,複数回呼び出すことが可能です.成功したら0,それ以外ではエラーの番 号を返します.
libltdlを終了し,すべてのモジュールを閉じます.この関数は,
lt_dlinit
が正常に呼び出された回数と同じだけ呼び出されたとき,
libltdlを終了するだけです.成功したら0,それ以外ではエラーの番号を返し
ます.
ファイル名filenameを用いてモジュールを開き,そのハンドルを返しま
す.lt_dlopen
は,libtoolダイナミックモジュール,プリロードされ
たスタティックモジュール,プログラム自身,そしてネイティブなダイナミッ
クライブラリを開くことが可能です.
モジュール内の未解決のシンボルは,それが依存する(まだ実装されていない)
ライブラリと,前もってdlopenされたモジュールを用いて解決されます.この
モジュールを使用している実行形式が-export-dynamic
フラグでリンク
されている場合,実行形式の大域的なシンボルもモジュール内の参照の解決に
使用されます.
filenameがNULL
でプログラムが-export-dynamic
や
-dlopen self
を用いてリンクされている場合,lt_dlopen
はプ
ログラム自身のハンドルを返し,それはそのシンボルのアクセスに使用可能で
す.
libltdlがライブラリを見つけられず,ファイル名filenameがディレク トリコンポーネントを持たない場合,それは,以下の検索パスを(以下の順番 で),さらにモジュールを検索します.
ユーザ定義の検索パス:
この検索パスは,関数lt_dlsetsearchpath
,
lt_dladdsearchdir
,そしてlt_dlinsertsearchdir
を用いたプ
ログラムで変更可能です.
libltdlの検索パス: この検索パスは,環境変数LTDL_LIBRARY_PATHの値です.
システムのライブラリ検索パス: システム依存のライブラリ検索パスです(例えば,Linuxでは LD_LIBRARY_PATHになります).
それぞれの検索パスは,例えば"/usr/lib/mypkg:/lib/foo"
のように,
コロンで分離された絶対的なディレクトリのリストにする必要があります.
同じモジュールが複数回ロードされた場合,同じハンドルが返されます.あら
ゆる原因でlt_dlopen
が失敗した場合,NULL
が返されます.
ファイル名に異なるファイル名の拡張子を追加を試みる以外は,
lt_dlopen
と同じです.ファイル名filenameを持つファイルが見
つからない場合,libltdlは,以下の拡張子の追加を試みます.
libtoolのアーカイブ拡張子`.la'
ホストプラットフォームの本来のダイナミックライブラリに使用される拡張子 で,例えば,`.so',`.sl'等です.
この探索手法は,本来のダイナミックライブラリの命名規則を知らないプログ
ラムが,そのようなライブラリを,libtoolモジュールと同様に,透過的に
dlopen
することを可能にするために設計されています.
モジュールhandleの参照カウントを減らします.ゼロになったり,この モジュールに依存する他のモジュールがない場合,モジュールはアンロードさ れます.成功時には0を返します.
モジュールhandle内のアドレスを返し,そこでは,ヌルで終端された文
字列nameで与えられるシンボルがロードされています.シンボルが見つ
からない場合はNULL
を返します.
libltdlのあらゆる関数から発生した最も新しいエラーを記述する,可読性の
高い文字列を返します.初期化からまたは最後に呼び出されてからエラーが発
生していない場合,NULL
を返します.
プリロードされているモジュールpreloadedのリストを登録します.
preloadedがNULL
の場合,lt_dlpreload_default
で設定
されているリスト以外の,これまで登録されているすべてのシンボルリストが
検出されます.成功時には0を返します.
プリロードされているモジュールリストのデフォルトをpreloadedに設
定し,それはlt_dlpreload
で検出されません.この関数は,
lt_dlinit
を使用して初期化されるためにlibltdlを要求しない
ことと,デフォルトでプリロードされるモジュールを登録するためにプログラ
ムで使用できることに注意してください.この関数を直接呼び出す代わりに,
ほとんどのプログラムはマクロLTDL_SET_PRELOADED_SYMBOLS
を使用し
ます.
成功時には0を返します.
プリロードされるシンボルのデフォルトリストを設定します.プリロードされ るlibltdlのモジュールを初期化するために,プログラムで使用した方が良い でしょう.
#include <ltdl.h> int main() { /* ... */ LTDL_SET_PRELOADED_SYMBOLS(); /* ... */ } |
検索ディレクトリsearch_dirを現在のユーザ定義のライブラリ検索パス に後置します.成功時には0を返します.
検索ディレクトリsearch_dirをユーザ定義のライブラリ検索パスを,ア
ドレスbeforeで始まる項目の直前に挿入します.beforeが
`NULL'の場合,lt_dladdsearchdir
が呼び出されたのと同様に後
置します.成功時には0を返します.
現在のユーザ定義のライブラリ検索パスをsearch_pathで置換し,それ はコロンで分けられた絶対的なディレクトリのリストにする必要があります. 成功時には0を返します.
現在のユーザ定義のライブラリ検索パスを返します.
アプリケーションによっては,既知の名前でモジュールを個別にロードしたく
なく,むしろディレクトリの組みからすべてのモジュールを見つけたり,初期
化中にすべてロードしたいかもしれません.この関数を用いると,libltdlに
候補となるsearch_path内のコロンで分離されたディレクトリリストを
走査させ,それらを独自のコールバック関数funcに渡すdataと併
せて渡すことが可能です.seach_pathが`NULL'の場合,
lt_dlopen
が調査する標準的な場所をすべて検索します.この関数は,
これらの呼び出しの一つでもゼロ以外の値が返されるまで,またはファイルが
亡くなるまで,search_pathで見つかったそれぞれのファイルに対し,
funcを呼び出し続けます.`lt_dlforeachfile'は最後の
funcの呼び出しの返り値を返します.
例えば,最初のベクトル(配列)のアドレスを保持しているdataを使用し ているファイルの,順番になっているargvのようなベクトル(配列)を構 築するために,funcを定義することも可能です.
モジュールを`lt_dlclose'できないように印を付けます.モジュールが プロジェクトの中心部の機能を実装している場合,削除されるとコードが壊れ るので,これは役に立つはずです.成功すると0を返します.
実行しているバイナリに対するhandleを取得するために `lt_dlopen (NULL)'を使用する場合,そのハンドルは常駐しているよう な印が常に付き,したがってうまく`lt_dlclose'することができません.
特定のモジュールが常駐しているように印が付いているかどうか調査し,その
場合は1を返し,それ以外では0を返します.この関数の実行中にエラーがある
場合, -1 が返され,lt_dlerror
を用いて回収されるエラーメッセー
ジが設定されます.
これらの変数は,デフォルトでmalloc
とfree
に設定されますが,
同等の機能を提供する他の関数に設定可能です.しかし,
lt_dlpreopen_default
やマクロLTDL_SET_PRELOADED_SYMBOLS
以
外のあらゆるlibltdl関数の呼び出し後に,その値を編集すべきではありませ
ん.
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 ... |
lt_dlmutex_register()
関数を使用し,適切なコールバック関数の定義
を提供することで,libltdlをマルチスレッド環境で使用することが可能です.
これは,ミューテックスロックが必要なlibltdlの実装コードの部分の,最初 に呼び出される関数のアドレスを持っている,関数のポインタ型です.
libltdlは本質的に再帰的なので,これらのコールバック関数によって使用さ れるロックメカニズムが再入可能であることは重要で,そうでなければ,おか しな問題が発生します.
アンロック関数に一致する型です.
libltdl APIの関数の多くは,エラーを発生したクライアントを示す,特
殊な返り値をとります.通常(シングルスレッドアプリケーションでは),内部
から回収することができるエラーを記述する文字列は,lt_dlerror()
に保存されます.
この形式の関数は,それがマルチスレッドのコンテクストで動作するように, ライブラリに登録される必要があります.関数は,スレッドローカルストレー ジに渡されるあらゆるエラーメッセージを保存すべきです.
スレッドローカルのストレージに,最後にエラーメッセージを保存したものに 関連するコールバック関数に一致する型です.
正しく登録されたとき,クライアントに対するエラーメッセージを回収するた
めに,全てのスレッドからlt_dlerror())
によって,この関数は使用さ
れます.
libltdlのマルチスレッドの準備で,上記のそれぞれの関数の型を登録するた
めに,この関数を使用してください.全ての引数は,有効なNULL
でな
い関数アドレスにする必要があり,また,そうでない場合は,シングルスレッ
ドオペレーションへの返り値として,全てNULL
にする必要があります.
libltdlが管理している,それぞれのロードされたモジュールに関する内部情 報には,ユーザが利用可能なものもあり,それは以下のような構造体の形式で す.
lt_dlinfo
は,モジュールの情報を保存するために使用されます.
filename属性は,NULL
で終端された,実際のモジュールファイ
ル名の文字列です.モジュールがlibtoolモジュールの場合,nameはそ
のモジュール名(例えば,"dir/libfoo.la"
に対する"libfoo"
)
で,それ以外ではNULL
に設定されます.ref_count属性は,現在
ロードされている同じモジュールの回数を記述する参照カウンタです.
以下の関数は,与えられたhandleに対するこの構造体のlibltdlの内部 のコピーへのポインタを返します.
モジュールhandleに関するいくつかの情報を含む構造体の,ポインタを
返します.構造体の内容は編集してはなりません.失敗時にはNULL
が
返ります.
さらに,ロードした全てのモジュールのハンドルリストを保持する手助けをす るために,これらの関数で,ロードされているモジュールのlibltdlのリスト 全体を繰り返すことが可能となります.
ロードされているそれぞれのモジュールに対し関数funcを呼び出します.
引数のhandleは,ロードされているモジュールのハンドルの一つで,
dataは,lt_dlforeach
に渡すdata引数です.func
がハンドルの一つに対し,ゼロでない値を返すとすぐに,
lt_dlforeach
はfuncの呼び出しを停止し,直ちに1を返します.
それ以外は0が返ります.
placeがNULL
の場合は,リスト内の最初のハンドルを返し,そし
て順番に次ものを呼び出すことで,ロードされているモジュール全体を繰り返
します.placeが,ロードされているモジュールリスト内の最後の要素
の場合,この関数はNULL
を返します.
もちろん,アプリケーションの目的のために,それぞれのハンドルに関連付け する必要があるデータがある場合,libltdlで管理されるリストと平行して, ロードされたモジュールハンドルの独自のリストの管理が必要になります.し かし,個別のモジュールハンドルを用いたアプリケーションデータに,ロード されたものとして関連付けさせるために,以下のAPIの呼び出しを使用す る場合には,実際にはそうする必要はありません.前もって保存したデータを 回収するために後で利用するlibltdlからのユニークな呼び出しidを,最初に 取得する必要があります.これで,ロードされているモジュールに対する独自 のデータを個別に保存したい異なるライブラリが,もう一つの(ライブラリ)の データへのインターフェースなしでそれを行うことが可能となります.
個別のデータセットのキーを保つ,透過でない型です.
モジュールデータごとに個別のセットを,保存し回収するためのユニークなキー を取得するために,これを使用してください.
後で回収するために,keyとhandleにユニークに関連付けされた
データのセットとして,dataを設定します.この関数は,以前に関連付
けされたkeyとhandleがある場合は,その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); } |
keyとhandleに関連付けされている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); } |
モジュールにアクセスするためのlibltdlの方法は多いけれど,プロジェクト
の目的に十分でないときもあります.独自のローダを書き,lt_dlopen
が利用できるように,libltdlでそれを登録することが可能です.
ローダを書くことは,lt_dlopen
,lt_dlsym
そして
lt_dlclose
で呼び出し可能な,少なくとも三つの関数を書くことを必
要とします.オプションで,lt_dlexit
が実行されるときクリーンアッ
プ処理を実行する終了関数と,lt_dlsym
に渡されるあらゆるシンボル
に前置されるシンボルの前置文字を提供することも可能です.これらの関数は,
以下の関数のポインタ型に一致する必要があり,その後,それらを
lt_user_dlloader
の代わりに関連付けし,登録することが可能です.
ローダの登録には,lt_dlloader_find
が認識でき,
lt_dlloader_remove
で削除できるように,それに対する名前を選択す
ることが必要です.選択した名前はユニークである必要があり,libltdlの組
み込みローダで既に使用しているものはいけません.
存在する場合は,システムのダイナミックローダ.
libltdlがビルドされたときに`libdld'がインストールされている場合は, GNU dldローダ.
プリロードされているスタティックモジュールのlt_dlopen
のためのロー
ダ.
前置される"dl"は,libltdlの将来のバージョンで提供されるローダとして予 約されているので,独自のローダ名に使用すべきではありません.
以下の型は,`ltdl.h'で定義されています.
lt_module
はモジュール依存のdlloaderです.ダイナミックモジュール
ローダの拡張は,これらの低レベルの型を使用して通信を行ないます.
lt_dlloader
はモジュールローダの型に対するハンドルです.
lt_user_data
はローダのインスタンスデータに対して使用されます.
ダイナミックモジュールを開くために新しい方法を定義したくて,それを使用
したlt_dlopen
APIがある場合,これらの構造体のインスタンス
を作成し,それをlt_dlloader_add
に渡す必要があります.好みの
dlloader_dataフィールドで渡すことが可能で,それは,関数ポインタ
フィールドで指定されている,それぞれの関数への最初のパラメータの値とし
て返されます.
lt_dlloader
モジュールローダに対するローダ関数の型です.
struct lt_user_dlloader
構造体のdlloader_dataフィールドに設定さ
れる値は,loader_dataパラメータで,この関数に渡されます.そのよ
うな関数の実装は,指名されたモジュールのロードを試み,関連する
lt_module_close
とlt_sym_find
関数のポインタに渡すのに適切
なlt_module
を返すべきです.関数が失敗した場合はNULL
を返
し,lt_dlseterror
を用いてエラーメッセージを設定すべきです.
ユーザが定義したモジュールローダに対するアンローダの型です.そのような
関数の実装は,moduleモジュールに結び付けられたあらゆるリソースの
解放を試み,その後でメモリからアンロードすべきです.理由があって関数が
失敗した場合,lt_dlseterror
を用いてエラーメッセージを設定し,ゼ
ロ以外を返すべきです.
ユーザが定義したモジュールローダに対する,シンボルルックアップ関数の型
です.そのような関数の実装は,モジュールmodule内の指名された
symbolのアドレスを返す,もしくは,検査が失敗した場合は,エラーメッ
セージをlt_dlseterror
で設定し,NULL
を返すべきです.
ユーザが定義したモジュールローダに対する,終了関数の型です.そのような
関数の実装は,ローダに関連するあらゆるリソースを解放すべきで,それには
lt_user_dlloader
のdlloader_data
フィールド内部にあるユー
ザが指定したあらゆるデータを含みます.NULL
でない場合は,関数は
lt_dlexit
とlt_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は,独自のモジュールローダを書くために,以下の関数を提供します.
新しいモジュールローダを全てのローダリストに加え,それは,(place
がNULL
の場合は)最後のローダとして,それ以外ではplaceとし
て渡されたローダの直前に加えます.loader_nameは,新しく登録され
たローダが渡された場合,lt_dlloader_name
を返します,これらの
loader_nameは,ユニークである必要があり,そうでない場合は,
lt_dlloader_remove
とlt_dlloader_find
は動作不可能です.成
功に対し0を返します.
{ /* Make myloader be the last one. */ if (lt_dlloader_add (NULL, myloader) != 0) perror (lt_dlerror ()); } |
ユニークな名前loader_nameで識別されているローダを削除します.こ
れが成功可能となる前に,指名されたローダにより開かれている全てのモジュー
ルを,閉じておく必要があります.成功に対し0を返し,それ以外では,エラー
メッセージがlt_dlerror
から取得可能です.
{ /* Remove myloader. */ if (lt_dlloader_remove ("myloader") != 0) perror (lt_dlerror ()); } |
ローダモジュール全体を繰り返し,それは,placeがNULL
の場合
は最初のローダを返し,順番に次を呼び出すことで行います.ハンドルは,
lt_dlloader_add
用です.
{ /* Make myloader be the first one. */ if (lt_dlloader_add (lt_dlloader_next (NULL), myloader) != 0) return ERROR; } |
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; } |
lt_dlloader_next
やlt_dlloader_find
で取得される,
PLACEの識別名を返します.この関数が失敗する場合,NULL
を返
し,lt_dlerror
で回収するためのエラーを設定します.
lt_dlloader_next
やlt_dlloader_find
で取得される,
PLACEのアドレスを返します.この関数が失敗する場合,NULL
を
返し,lt_dlerror
で回収するためのエラーを設定します.
この関数で,独自のエラーメッセージをlt_dlerror
に組み込むことが
可能となります.lt_dlerror
で返すための適切な診断メッセージに渡
すものと,lt_dlseterror
で使用されるエラー識別子が返されます.
識別子の割り当てが失敗した場合,この関数は-1を返します.
int myerror = lt_dladderror ("Doh!"); if (myerror < 0) perror (lt_dlerror ()); |
独自のモジュールローダを書くとき,lt_dlerror
インターフェースを
通じて伝搬されるようにエラーを発生させるために,この関数を使用すべきで
す.libltdlで使用される標準エラーの全ては,`ltdl.h'で宣言されてい
て,そうでなければ,lt_dladderror
を用いて独自に書き加えることが
可能です.
if (lt_dlseterror (LTDL_ERROR_NO_MEMORY) != 0) perror (lt_dlerror ()); |
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'される,LIBSと CPPFLAGSのような変数に加えるのはあなた次第です.
コンビニエンス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.