リンクモード: [-lNAME] [-o OUTPUT-FILE] [-LLIBDIR] [-R LIBDIR] [-all-static] [-avoid-version] [-dlopen FILE] [-dlpreopen FILE] [-export-dynamic] [--export-symbols FILE] [--export-symbols REGEX] [--module] [-no-undefined] [-release RELEASE] [-rpath LIBDIR] [-static] [-version-info CURRENT[:REVISION[:AGE]]
実行モード: [-dlopen FILE]
libtool [--features] [--help] [--version]
libtool はコンパイル・実行・リンク・フィニッシュ・インストール・アンインストール という 6 つのモードで動作できる。
libtool は出力ファイルの名前を決定するとき、 ソースファイル名からディレクトリ構成要素を取り除き、 それから C 言語のソースコードの拡張子 `.c' をライブラリオブジェクトの 拡張子 `.lo' に置き換えるという方法を用いる。
共有ライブラリがビルドされる場合、必要な PIC 作成フラグすべてが
コンパイルコマンドに挿入される。
-static オプションを指定すると、たとえ --disable-static が
設定されていたとしても、libtool は `.o' ファイルを作成する。
-o オプションが直接サポートされていないプラットフォーム上では
(コンパイラによって作成されたオブジェクトファイルのロックと移動により)
エミュレートを行う。
したがって、以下のような通常の構文を使うことができる。
lightside:% libtool cc -c foo/x.c -o foo/x.lo
プラットフォームが -c と -o オプションをサポートしていない場合、 古い `foo/x.o' を上書きせずに `foo/x.lo' をビルドすることはできない。 この場合、`foo/x.o' が `foo/x.lo' の後に (再) ビルドされることを 確かめておかなければならない。
MODE-ARGS は、C コンパイラがオブジェクトファイルから (-o フラグにより) 出力ファイル OUTPUT-FILE を作成する ときに使用するコマンドで構成される。 以下のように、ファイルの形式は OUTPUT-FILE の拡張子に依存する。
一番目の MODE-ARGS はプログラム名として扱われ、 残りはプログラムの引数として扱われる。
引数の中のどれかが libtool 実行ファイルのラッパーであった場合、 その引数はそれぞれ対応するアンインストール済みバイナリの名前に変換される。 このとき、必要とされるライブラリディレクトリがライブラリパスに加えられる。
残りの MODE-ARGS は、インストールコマンドの 引数として解釈される。
このコマンドは実行され、 インストール後の処理に必要な非特権コマンドもすべて完了する。
MODE-ARG はライブラリディレクトリ名として解釈される。 このコマンドを実行するのにはスーパーユーザー特権が必要なため、 --dry-run オプションを使うと便利だろう。
一番目の MODE-ARG はファイルを削除するためのプログラム名 (一般には `/bin/rm') である。
残りの MODE-ARGS は削除プログラムの (`-' で始まる) フラグもしくは、 削除するファイルの名前である。
FILE が `実行ファイル自身' であった場合、 libtool は実行ファイルが -export-dynamic や -dlpreopen を使って自らを dlopen(3) できるかを確かめる。
FILE が `出力プログラム自身' であった場合、 出力プログラム自身のシンボルが LT_PRELOADED_SYMBOLS に加えられる。
REVISION と AGE が省略された場合のデフォルトは 0 である。 AGE は CURRENT インターフェース番号より小さいか 等しくなければならないことにも注意すること。 2 つのライブラリが同一の CURRENT 番号と AGE 番号であるとき、 ダイナミックリンカは大きい REVISION 番号のライブラリを選択する。
バージョニングのガイドライン:
* 1. それぞれの libtool ライブラリについて `0:0:0' というバージョン情報から始めなさい。
* 2. バージョン情報を更新するのは ソフトウェアの公開リリースの直前だけにしなさい。 頻繁な更新は不必要であり、現在のインターフェース番号が大きくなるのを 早くするだけである。
* 3. 前回の更新からライブラリのソースコードが すっかり変更されたなら、REVISION を増加させなさい (C:R:A が C:R+1:A になる)。
* 4. 前回の更新からインターフェースが 追加・削除・変更されたなら、CURRENT を増加させ、REVISION を 0 にしなさい。
* 5. 前回の公開リリースからインターフェースが 追加されたなら、AGE を増加させなさい。
* 6. 前回の公開リリースからインターフェースが 削除されたなら、AGE を 0 にしなさい。
パッケージバージョンをライブラリ名にエンコードしたい場合や、 libtool のバージョニングと衝突せずに 他のバージョニングシステムを使いたい場合は、-release を使うこと。 たとえば binutils-2.7.0.2 に付属する `libbfd.so.2.7.0.2' は libtool のバージョニングと明らかに衝突する。 `-release 2.7.0' を使えば `libbfd-2.7.0.so.0.0.0' で終ることができる。
異なる CURRENT バージョンのライブラリや 異なる -release のライブラリはバイナリ非互換であろう。
設計に対するガイドラインをいくつか示す:
* 前もって計画を立てる
エントリーポイントを頻繁に削除する必要がないように、
それぞれのインターフェースを最小にするようにしなさい。
* インターフェースの変更を避ける
もしインターフェースを再設計する必要があるならば、
クライアントが既に存在するコードを書き直す必要がないように、
互換性のある関数も残しておくようにしなさい。
* 見えないデータタイプを使う
クライアントがアクセスする必要のあるデータタイプの定義は少ない程良い。
可能ならば、関数がジェネリックポインタ
(内部データタイプにキャストすることが可能) を
受け付けるように設計しなさい。
クライアントに直接データを操作させるよりは、
アクセス関数を提供しなさい。
このようするとインターフェースを変更することなく
データ構造を自由に変更できる。
* ヘッダファイルを使う
それぞれのライブラリについて大域関数・大域変数をヘッダファイルに書いて
ライブラリのソースファイルにインクルードしておけば、
気づかずにインターフェースの変更をしてしまっても
コンパイラが知らせてくれるだろう。
* 可能なときはいつでも静的 (もしくは等価なもの) を使う
ライブラリに大域関数が少ないほど、ライブラリは柔軟に変更できる。
静的な関数・変数は、クライアントがアクセスできないから
インターフェースの変更とはならないので、好きなだけ変更することができる。
プログラムを libtool ライブラリにリンクするためには、 ライブラリ名を指定する program_LDADD 変数を使うこと。 libtool に -static といったオプションを渡すためには program_LDFLAGS を使うと良い。
libtool ライブラリをビルドするには、 ライブラリ名を指定する lib_LTLIBRARIES を使うこと。 そして、たとえば、libtool に -version-info オプションを 渡すには lib_LDFLAGS を使うこと。 次のセクションに例がある。
作業をするためには、パッケージにいくつかの基本的なファイルを入れたり、 libtoolize を使う必要があるだろう。 libtool スクリプトを直接インクルードしてはならない。
struct lt_dlsymlist { const char *NAME; lt_ptr_t ADDRESS; }
NAME には、"fprintf" のような、シンボル名のアスキー文字列が保持される。 ADDRESS は、&fprintf のような、 適切なオブジェクトへのジェネリックポインタである。
const lt_dlsymlist * lt_preloaded_symbols;
この配列は実行ファイルにリンクされている プリロードされたシンボルを表す。 -dlpreloaded されたファイルのそれぞれについて要素が存在し、 ファイル名 NAME と `0' というアドレス ADDRESS、 およびこのファイルからエクスポートされたすべてのシンボルを保持する。 実行ファイル自身については、特別な名前 @PROGRAM@ が使われる。 最後のエレメントは NAME と `0' という ADDRESS を持つ。
ダイナミックロードされるライブラリもしくは、 モジュールをダイナミックロードしようとする実行ファイルをリンクするときは、 -module フラグを指定するのを忘れないこと。
ダイナミックロードしようとしているライブラリの外部シンボルを、 実行ファイルが参照する必要がある場合は、実行ファイルをリンクするときに -export-dynamic を使用すること。
ライブラリ名にバリエーションがあるので、
プログラムはどれがダイナミックロードするための
正しいファイルであるのかを決定する必要がある。
直接的な方法は `.la' ファイルを調べて、
dlname='DLNAME' という行を探すことである。
この行はライブラリをダイナミックロードできない場合は空で、
そうでない場合はライブラリの名前が入っている。
lightside:~% libtool cc -c foo.c cc -c -fPIC -DPIC foo.c -o .libs/foo.lo cc -c foo.c >/dev/null 2>&1 lightside:~% libtool cc -c bar.c cc -c -fPIC -DPIC bar.c -o .libs/bar.lo cc -c bar.c >/dev/null 2>&1
* リンクモード、静的ライブラリのみをビルドする: 以前に作成された `.o' というオブジェクトファイルを指定している。 -o オプションは必須である。
lightside:~% libtool cc -o libbaz.a foo.o bar.o ar cru libbaz.a foo.o bar.o ranlib libbaz.a
* リンクモード、静的ライブラリと共有ライブラリをビルドする: `.lo' というオブジェクトファイルを指定する。 必須オプションは、前と同じ -o と ライブラリのインストールされるディレクトリを指示する -rpath である。 ライブラリは `.libs' ディレクトリに作成される。
lightside:~% libtool cc -o libbaz.la foo.lo bar.lo \ -rpath /usr/local/lib cc -shared -Wl,-soname -Wl,libbaz.so.0 \ -o .libs/libbaz.so.0.0.0 foo.lo bar.lo (cd .libs && ln -s libbaz.so.0.0.0 libbaz.so.0) (cd .libs && ln -s libbaz.so.0.0.0 libbaz.so) ar cru .libs/libbaz.a foo.o bar.o ranlib .libs/libbaz.a creating libbaz.la (cd .libs && ln -s ../libbaz.la libbaz.la)
* インストールモード:ライブラリを指定したパス (この場合は `/usr/local/lib') にインストールするために 必要なコマンドを実行する。 このモードでは共有ライブラリ (`.so') と静的ライブラリ (`.a') を インストールするとともに、アンインストールと情報提供の目的で libtool ファイル (`.la') がインストールされる。
このモードはふつう特権ユーザーとして実行されるので、 -n または --dry-run オプションを 指定して結果をチェックしておくとよい。
lightside:/tmp% libtool -n install libbaz.la /usr/local/lib install .libs/libbaz.so.0.0.0 /usr/local/lib/libbaz.so.0.0.0 (cd /usr/local/lib && ln -s libbaz.so.0.0.0 libbaz.so.0) (cd /usr/local/lib && ln -s libbaz.so.0.0.0 libbaz.so) install libbaz.la /usr/local/lib/libbaz.la install .libs/libbaz.a /usr/local/lib/libbaz.a ranlib /usr/local/lib/libbaz.a chmod 644 /usr/local/lib/libbaz.a
cc -c a.c
ライブラリが既にインストールされている場合には、 普段のように続行することができる
cc a.c -lbaz -L/usr/local/lib
ライブラリがまだインストールされていない場合は、 実行ファイルのリンク・デバッグ・インストールに libtool を使用しなければならない (一度ライブラリがインストールされるまで、これはつづく)。 実際の実行ファイルはインストールされるまで `.libs' 内にあり、 作業ディレクトリにある実行ファイルは単なるラッパーであることに注意すること。
曖昧さを避けるため、絶対に -l と -L を使ってアンインストールされた 共有ライブラリにリンクしてはならない。 `.la' ファイルへのパスだけを指定すること。 以下の (`-lm') でわかるように、インストール済みのライブラリは問題ではない。
lightside:~% libtool cc a.o libbaz.la -o a -lm cc a.o -Wl,--rpath -Wl,/usr/local/lib \ .libs/libbaz.so -o .libs/a -lm lightside:~% libtool gdb a [複雑なデバッグのセッションは省略] lightside:~% libtool install -c a /usr/local/bin/a install -c .libs/a /usr/local/bin/a
AC_DEFUN(AM_INIT_AUTOMAKE) AC_INIT(a.c) AM_INIT_AUTOMAKE(a, 1.0) AC_PROG_CC AM_PROG_LIBTOOL AC_OUTPUT(Makefile)
* 対応する Makefile.am
# ライブラリのビルド lib_LTLIBRARIES=libbaz.la libbaz_la_SOURCES = foo.c bar.c libbaz_la_LDFLAGS = -version-info 0:0:0 bin_PROGRAMS = a a.debug # a.c と libbaz.la から a をビルド a_SOURCES = a.c a_LDADD = libbaz.la # 静的デバッグバージョンを作成 a_debug_SOURCES = a.c a_debug_LDADD = libbaz.la a_debug_LDFLAGS = -static
* そして最後に実行する
lightside:~% aclocal; libtoolize; automake --add-missing; autoconf lightside:~% ./configure; make