[ << ] | [ >> ] | [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
を用いたプログラムで設定可能です.
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_pathで置換し,それは コロンで分けられた絶対的なディレクトリのリストにする必要があります.成功 時には0を返します.
現在のユーザ定義のライブラリ検索パスを返します.
モジュールを`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
で呼び出し可能な,少なくとも3つの関数を書くことを必要と
します.オプションで,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_dlloader_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'を インクルードするプログラムをコンパイルするために使用するプリプロセッサフ ラグINCLTDLを定義します.この変数が`Makefile'で利用可能にする ことを確実にするため`AC_SUBST'を使用したり,デフォルトで `AC_SUBST'される,LIBSとCPPFLAGSのような変数に加えるの はあなた次第です.
便利な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.