[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
libtoolが人生をより単純にする方法が分かるまで,独自のパッケージでlibtool を使用することを話す意味はありません.この章の例は,標準的なライブラリの ビルド処理と,libtoolの処理を,2つの異なるプラットフォームで比較すること で,主な特徴を紹介します.
スタティックライブラリのみのUltrix 4.2プラットフォーム.
共有ライブラリを持つ,NetBSD/i386 1.2プラットフォーム.
独自のプラットフォームの例をこれに続けることが可能で,それは,libtoolで インストールされた,前もってコンフィグレーションされたlibtoolスクリプト を使用します(see section libtoolのコンフィグレーション).
以下の例のソースファイルは,libtool配布物の`demo'サブディレクトリか ら持ってきています.ファイル`foo.c'と`hello.c'からライブラリ `libhello'をビルドしていると仮定してください.
`foo.c'ソースファイルがcos
数学ライブラリ関数を使用していて,
それは通常,Cライブラリではなく単独の数学ライブラリで見つかることに注意
してください(see (libc)Trig Functions section `Trigonometric Functions' in The GNU C Library Reference Manual).そのため,`foo.o'や`foo.lo'
を実行形式やライブラリにリンクするときは,常にリンク行の最後に-lm
を加える必要があります(see section ライブラリ内部の依存).
同じ規則は,標準Cライブラリに無い関数を使用するとき,常に当てはまります … これらのオブジェクトに対しリンクするときは,適切な -lnameフラグをリンク行の終りに加える必要があります.
ライブラリをビルドした後,`libhello'に対して`main.o'をリンクす ることでプログラムを作成したいと思います.
3.1 オブジェクトファイルの作成 | Compiling object files for libraries. | |
3.2 ライブラリのリンク | Creating libraries from object files. | |
3.3 実行形式のリンク | Linking object files against libtool libraries. | |
3.4 実行形式のデバッグ | Running GDB on libtool-generated programs. | |
3.5 ライブラリのインストール | Making libraries available to users. | |
3.6 実行形式のインストール | Making programs available to users. | |
3.7 スタティックライブラリとのリンク | When shared libraries are not wanted. |
ソースファイルからオブジェクトファイルを作成するため,コンパイラは`-c'フ ラグ(とその他の必要なあらゆるフラグ)とともに呼び出されます.
burger$ gcc -g -O -c main.c burger$ |
上記のコンパイラコマンドは,ソースファイル`main.c'からオブジェクト ファイル`main.o'を生成します.
ほとんどのライブラリシステムでは,スタティックライブラリの一部となるオブ ジェクトファイルを作成することは,実行可能な形式にリンクされるオブジェク トファイルを作成することと同じくらい単純です.
burger$ gcc -g -O -c foo.c burger$ gcc -g -O -c hello.c burger$ |
しかし,共有ライブラリはposition-independent code (PIC)のみからビ ルドされます.そのため,標準のposition-dependent codeではなくPICを生成す るようコンパイラに伝えるため,特定のフラグを渡す必要があります.
これがライブラリ実装の詳細なので,libtoolは個別の(`.o'の代わりに `.lo'で終わる)ライブラリオブジェクトファイルを用いて,複雑なPICコン パイラフラグを隠蔽します.共有ライブラリが無い(または,特定のPICフラグが 無い)システムでは,これらのライブラリオブジェクトファイルは"標準の"オ ブジェクトファイルと同じです.
`foo.c'と`hello.c'に対するライブラリオブジェクトファイルを作成 するため,単純に標準のコンパイルコマンドを引数として,libtoolを呼び出し てください(see section コンパイルモード).
a23$ libtool gcc -g -O -c foo.c gcc -g -O -c foo.c echo timestamp > foo.lo a23$ libtool gcc -g -O -c hello.c gcc -g -O -c hello.c echo timestamp > hello.lo a23$ |
それぞれの呼び出しで,libtoolが2つのファイルを作成することに注意してく ださい.`.lo'ファイルはライブラリオブジェクトで,それは共有ライブラ リにビルドされ,`.o'ファイルは標準的なオブジェクトファイルです. `a23'では,スタティックライブラリのみサポートされているので,ライブ ラリオブジェクトはタイムスタンプのみです.
共有ライブラリのあるシステムでは,ライブラリオブジェクトと標準オブジェク トが異なるように,libtoolはPIC生成フラグをコンパイルコマンドに自動的に挿 入します.
burger$ libtool gcc -g -O -c foo.c gcc -g -O -c -fPIC -DPIC foo.c mv -f foo.o foo.lo gcc -g -O -c foo.c >/dev/null 2>&1 burger$ libtool gcc -g -O -c hello.c gcc -g -O -c -fPIC -DPIC hello.c mv -f hello.o hello.lo gcc -g -O -c hello.c >/dev/null 2>&1 burger$ |
2番目に実行されるGCCがその出力を破棄していることに注意してください.こ れは,コンパイラの警告がうるさく重複しないために行われます.
libtoolを用いない場合,スタティックライブラリを作成するため,プログラマ
はar
コマンドを呼び出していました.
burger$ ar cru libhello.a hello.o foo.o burger$ |
しかしもちろん,それだけではあまりに単純すぎて,多くのシステムでは(それ
以上のカルマや何かを与えるため)結果として生成されたライブラリ上で,
ranlib
コマンドを実行する必要があります.
burger$ ranlib libhello.a burger$ |
libtoolの"ライブラリはプログラム"というアプローチで与えられるこの作業
に対して,Cコンパイラを使用することは,より自然に感じられます.そのため,
共有ライブラリが無いプラットフォームでは,libtoolは単純にシステムの
ar
(そして可能ならranlib
)コマンドのラッパーとして動作します.
また,libtoolのライブラリ名は,標準の名前(`.a'接尾子の代わりに `.la' 接尾子を持ちます)と異なります.libtoolの引数は,コンパイラで `libhello.la'という名の実行形式を生成するために使用したのと同じもの です(see section リンクモード).
a23$ libtool gcc -g -O -o libhello.la foo.o hello.o libtool: cannot build libtool library `libhello.la' from non-libtool \ objects a23$ |
あぁ!libtoolは通常のエラーを得てしまった… ライブラリオブジェクト の代わりに,標準のオブジェクトからライブラリをビルドしています.これはス タティックライブラリでは問題ありませんが,共有ライブラリシステムでは非常 に重要です.
そのため,今回はライブラリオブジェクトファイルを用いて,もう一度試してみ
ましょう.`foo.c'がcos
数学ライブラリを使用しているので,コマ
ンドラインに-lmを加える必要があることも忘れないでください
(see section libtoolを使用する).
共有ライブラリをビルドするその他の複雑なことは,(最終的に)インストールさ れるディレクトリパス(この場合は,`/usr/local/lib') (1) を指定する必要があることです.
a23$ libtool gcc -g -O -o libhello.la foo.lo hello.lo \ -rpath /usr/local/lib -lm mkdir .libs ar cru .libs/libhello.a foo.o hello.o ranlib .libs/libhello.a creating libhello.la a23$ |
さて,共有ライブラリのプラットフォーム上で同じトリックを試してみましょう.
burger$ libtool gcc -g -O -o libhello.la foo.lo hello.lo \ -rpath /usr/local/lib -lm mkdir .libs ld -Bshareable -o .libs/libhello.so.0.0 foo.lo hello.lo -lm ar cru .libs/libhello.a foo.o hello.o ranlib .libs/libhello.a creating libhello.la burger$ |
さてそれはかなり賢いです… libtoolは共有ライブラリを作成するため,
スタティックライブラリと同様に,曖昧なld
コマンドを実行しただけで
す.
libtoolが,現在のディレクトリではなく,`.libs'サブディレク トリに余分なファイルを作成することに注意してください.この機能は,ビルド ディレクトリをきれいにするのをより簡単にするためと,たまたまlibtoolの使 用を忘れていて他のプログラムを実行するとき,確実に手ひどく失敗するので役 に立ちます.
ライブラリを実行形式とリンクする前に,インストールする(永久に位置 する場所にそれを配置する)場所を選択した場合,リンクするためにlibtoolを使 用する必要はありません.ライブラリの位置を指定するため,単純に適切な `-L'と`-l'フラグを使用してください.
システムのリンカによっては,結果として生じる実行形式に,共有ライブラリの 完全なディレクトリ名の符号化を強要するものもあります.libtoolは,永久に 配置されるディレクトリ名のみをインストールされた実行形式に書き込むことを 確実にするため,特別な魔法でこの設計ミスに関して動作する必要があります.
このバグの重要性は見落としてはなりません.それによるプログラムの暴走は明 白ではありません.それはセキュリティホールを作成し,さらに悪いことには, パッケージのインストール後にライブラリソースコードを編集した場合,インス トールされたプログラムの動作を変更してしまうでしょう!
そのため,インストールする前にライブラリとプログラムをリンクさせたい場合, リンクするためにlibtoolを使用する必要があります.
インストールされていないライブラリとリンクする古い方法は,以下のようにな ります.
burger$ gcc -g -O -o hell.old main.o libhello.a -lm burger$ |
libtoolの方法は,ほとんど同じです(2)(see section リンクモード).
a23$ libtool gcc -g -O -o hell main.o libhello.la -lm gcc -g -O -o hell main.o ./.libs/libhello.a -lm a23$ |
真実としてはあまりに単純に見えます.libtoolが行うことは, `libhello.la'を`./.libs/libhello.a'に変換することがす べてですが,`a23'は共有ライブラリがないことを忘れないでください.
`burger'では,状況が異なります.
burger$ libtool gcc -g -O -o hell main.o libhello.la -lm gcc -g -O -o .libs/hell main.o -L./.libs -R/usr/local/lib -lhello -lm creating hell burger$ |
さて,`libhello.la'が既にインストールされていると仮定し,新しいプロ グラムをそれとリンクしたいとします.自分でそれがある場所を探し,以下を実 行します.
burger$ gcc -g -O -o test test.o -L/usr/local/lib -lhello |
しかし,`/usr/local/lib'が標準のライブラリ検索パスに無い場合,
test
を実行することはできません.しかし,既にインストールされてい
るlibtoolライブラリとリンクするためlibtoolを使用する場合,それは The
Right Thing (TM)となります.
burger$ libtool gcc -g -O -o test test.o /usr/local/lib/libhello.la gcc -g -O -o .libs/test test.o -Wl,--rpath -Wl,/usr/local/lib /usr/local/lib/libhello.a -lm creating test burger$ |
libtoolが,ライブラリlibhello.laが依存している`-lm'同様,必要なラン タイムパスフラグを追加していることに注意してください.いいですね,ふっふ?
libtoolがラッパースクリプトを作成したので,インストールとデバッグにも libtoolを使用したほうがいいでしょう.しかし,プログラムはインストールさ れていないlibtoolライブラリには全く依存しないので,ラッパースクリプトを 用いない場合でもおそらく有用でしょう.この場合は,ラッパースクリプトの作 成を避けるため,おそらくより賢くlibtoolを作成できたでしょうが,これは読 者の演習として残しておきます.
実行形式hell
は,実際には`.libs'サブディレクトリに作
成されることに注意してください.そして,ラッパースクリプトは現在のディレ
クトリに作成されます.
NetBSD 1.2では,libtoolは`-R/usr/local/lib'コンパイラフラグを使用し て,`libhello'のディレクトリのインストールを符号化します.そして, ラッパースクリプトは,正しくインストールされるまで実行形式が正しい (`./.libs'にある)共有ライブラリを見つけることを保証します.
2つの異なるプログラムを比較してみましょう.
burger$ time ./hell.old Welcome to GNU Hell! ** This is not GNU Hello. There is no built-in mail reader. ** 0.21 real 0.02 user 0.08 sys burger$ time ./hell Welcome to GNU Hell! ** This is not GNU Hello. There is no built-in mail reader. ** 0.63 real 0.09 user 0.59 sys burger$ |
ラッパースクリプトは実行にかなり時間がかかりますが,共有ライブラリがイン ストールされていなくても,少なくとも結果は正しくなります.
そのため,共有ライブラリがもたらした,全体的なスペース削減ははどうなって いるのでしょう?
burger$ ls -l hell.old libhello.a -rwxr-xr-x 1 gord gord 15481 Nov 14 12:11 hell.old -rw-r--r-- 1 gord gord 4274 Nov 13 18:02 libhello.a burger$ ls -l .libs/hell .libs/libhello.* -rwxr-xr-x 1 gord gord 11647 Nov 14 12:10 .libs/hell -rw-r--r-- 1 gord gord 4274 Nov 13 18:44 .libs/libhello.a -rwxr-xr-x 1 gord gord 12205 Nov 13 18:44 .libs/libhello.so.0.0 burger$ |
うーん,だめだなあ(3).おそらく, 私はこのプロジェクトを破壊し,作成中のゆりかごを取り上げたほうがいいでしょ う.
実際,それは重要なことを証明しています.共有ライブラリには,それが(関連 する)複雑さのため,オーバーへッドをがあります.この状況では,ダイナミッ クの価値は8キロバイトで,報酬は約4キロバイトです.そのため,少なくとも2, 3個以上のプログラムとリンクするまで,共有される`libhello'を維持する ことは利点になりません.
`hell'が複雑なプログラムの場合,システムにインストールする前にそれ のテストとデバッグを間違いなく行いたいでしょう.上記のセクションで, libtoolラッパースクリプトが,プログラムを直接実行することを可能にする方 法を見ましたが,残念ながら,このメカニズムはデバッガの邪魔になります.
burger$ gdb hell GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is no warranty for GDB; type "show warranty" for details. GDB 4.16 (i386-unknown-netbsd), (C) 1996 Free Software Foundation, Inc. "hell": not in executable format: File format not recognized (gdb) quit burger$ |
残念です.GDBは実行形式がある場所が分からないので動作しません.そのため, もう一度実行形式でGDBを呼び出してみてください.
burger$ gdb .libs/hell trick:/home/src/libtool/demo$ gdb .libs/hell GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is no warranty for GDB; type "show warranty" for details. GDB 4.16 (i386-unknown-netbsd), (C) 1996 Free Software Foundation, Inc. (gdb) break main Breakpoint 1 at 0x8048547: file main.c, line 29. (gdb) run Starting program: /home/src/libtool/demo/.libs/hell /home/src/libtool/demo/.libs/hell: can't load library 'libhello.so.2' Program exited with code 020. (gdb) quit burger$ |
あぁ.さて,GDBは,`hell'がリンクしている共有ライブラリを見つけるこ とができないため文句を言いました.そのため,正しいライブラリパスを設定し てデバッガを実行するために,libtoolを使う必要があります.幸い, `.libs'ディレクトリを完全に忘れて,そのままの実行形式のラッ パーで実行可能です(see section 実行モード).
burger$ libtool gdb hell GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is no warranty for GDB; type "show warranty" for details. GDB 4.16 (i386-unknown-netbsd), (C) 1996 Free Software Foundation, Inc. (gdb) break main Breakpoint 1 at 0x8048547: file main.c, line 29. (gdb) run Starting program: /home/src/libtool/demo/.libs/hell Breakpoint 1, main (argc=1, argv=0xbffffc40) at main.c:29 29 printf ("Welcome to GNU Hell!\n"); (gdb) quit The program is running. Quit anyway (and kill it)? (y or n) y burger$ |
libtoolが無いシステムでライブラリをインストールすることは,全く簡単です … それらをその場所にコピーするだけです.(4)
burger$ su Password: ******** burger# cp libhello.a /usr/local/lib/libhello.a burger# |
おっと,ranlib
コマンドを忘れないでください.
burger# ranlib /usr/local/lib/libhello.a burger# |
libtoolのインストールは,同様に全く単純です.通常使用する,
install
やcp
コマンドをそのまま使用してください
(see section インストールモード).
a23# libtool cp libhello.la /usr/local/lib/libhello.la cp libhello.la /usr/local/lib/libhello.la cp .libs/libhello.a /usr/local/lib/libhello.a ranlib /usr/local/lib/libhello.a a23# |
アンインストールでlibtoolを助け(see section アンインストールモード),リンクし (see section 実行形式のリンク),dlopenでプログラムを助ける (see section dlopenモジュール)ため,libtoolのライブラリ`libhello.la'も インストールされることに注意してください.
Here is the shared library example:
共有ライブラリの例は,以下のようになります.
burger# libtool install -c libhello.la /usr/local/lib/libhello.la install -c .libs/libhello.so.0.0 /usr/local/lib/libhello.so.0.0 install -c libhello.la /usr/local/lib/libhello.la install -c .libs/libhello.a /usr/local/lib/libhello.a ranlib /usr/local/lib/libhello.a burger# |
ライブラリインストール時にBSD互換のinstallプログラムを使用する場合, `-s'(シンボルのstrip)フラグを指定すると安全です.libtoolは`-s' フラグを無視する,またはライブラリからデバッグとコンパイラシンボルのみを stripするプログラムを実行します.
ライブラリを一度配置すると,使用する前に必要な追加のコンフィグレーション を行います.最初に,ビルド時に使用した`-rpath'フラグと同じ場所に, ライブラリが実際にインストールされていることを確かめる必要があります.
そして,`libtool -n --finish libdir'を実行すると,行うことの ヒントが与えられるはずです(see section フィニッシュモード).
burger# libtool -n --finish /usr/local/lib PATH="$PATH:/sbin" ldconfig -m /usr/local/lib ----------------------------------------------------------------- Libraries have been installed in: /usr/local/lib To link against installed libraries in a given directory, LIBDIR, you must use the `-LLIBDIR' flag during linking. You will also need to do one of the following: - add LIBDIR to the `LD_LIBRARY_PATH' environment variable during execution - add LIBDIR to the `LD_RUN_PATH' environment variable during linking - use the `-RLIBDIR' linker flag See any operating system documentation about shared libraries for more information, such as the ld and ld.so manual pages. ----------------------------------------------------------------- burger# |
これらのステップを完了した後,インストールされたライブラリの使用開始が可 能になります.作成されたライブラリに依存する実行形式もインストールできま す.
インストールされていないlibtoolライブラリに対して,実行形式をリンクする ためにlibtoolを使用した場合(see section 実行形式のリンク),ライブラリをイ ンストールした後に実行形式をインストールするため,libtoolを使用する必要 があります.
それでは,Ultrixの例を対象に,以下のように実行します.
a23# libtool install -c hell /usr/local/bin/hell install -c hell /usr/local/bin/hell a23# |
共有ライブラリシステムでは,libtoolはラッパースクリプトを無視し,正しい バイナリをインストールします.
burger# libtool install -c hell /usr/local/bin/hell install -c .libs/hell /usr/local/bin/hell burger# |
libtoolの旨味を知って,ar
とranlib
の愚かさへなぜ戻るのでしょ
う?さて,決して共有されるはずがないスタティックアーカイブをつくることが
望ましいときもあります.最もよくある状況として,複数の異なるプログラムを
ビルドするために使用する,オブジェクトファイルの集まりを持っているときが
あります.個々のプログラムに対し,すべてのオブジェクトファイルをリストアッ
プする代わりに,それらのオブジェクトから"便利なライブラリ"を作成し,ラ
イブラリとプログラムをリンクすることが可能です.この技術は,他のディレク
トリのライブラリへのリンクをサポートするので,他のディレクトリのソースか
らビルドされるオブジェクトファイルをリンクするサポートが欠けている,GNU
automakeを補うためによく使用されます.この制限は,リリース1.4までのGNU
automakeに当てはまります.より新しいリリースは,他のディレクトリのソース
をサポートするでしょう.
この便利なライブラリとプログラムをリンクしたいだけの場合,完全にlibtool
を無視し,古いar
とranlib
コマンド(や,対応するGNU automake
`_LIBRARIES'規則)が使用可能です.(おそらく使用したくはないでしょう
が)libtoolを使用して,便利なライブラリをインストールすることさえ可能です.
burger$ libtool ./install-sh -c libhello.a /local/lib/libhello.a ./install-sh -c libhello.a /local/lib/libhello.a ranlib /local/lib/libhello.a burger$ |
スタティックライブラリのインストールにlibtoolを使用すると,ライブラリが
(`-s'フラグを使用したインストーラの場合のように)偶然stripされること
から守り,自動的に実行される正しいranlib
コマンドと同様になります.
しかし,libtoolライブラリは単にオブジェクトファイルの集合以上です.それ らは古いアーカイブにはない,ライブラリの依存情報をも運ぶことが可能です. libtoolの静的な便利なライブラリを作成したい場合,スタティックライブラリ のみに興味があることを示すため,`-rpath'フラグを省略し `-static'を使用することができます.そのようなスタティックライブラリ とリンクするとき,libtoolは実際にすべてのオブジェクトファイルと依存する ライブラリをプログラムにリンクします.
`-rpath'と`-static'の両方を省略した場合,libtoolは,他の libtoolライブラリで,共有ライブラリの作成にすら使用可能なlibtoolの便利な ライブラリを作成します.静的な場合のように,ライブラリは一組のオブジェク トファイルと依存するライブラリの別名として動作しますが,この場合,オブジェ クトファイルは共有ライブラリに含まれるほうが適しています.しかし,直接ま たは間接的に,単一のプログラムやライブラリに単一の便利なライブラリをリン クしないように注意して下さい.さもなければ,シンボル再定義に関するエラー を得るでしょう.
GNU automakeを使用するとき,`-rpath'オプションがリンク時に渡されな
いように,便利なライブラリに対するlib_LTLIBRARIES
の代わりに
noinst_LTLIBRARIES
を使用した方が良いでしょう.
経験的に,最大一つのlibtoolライブラリにlibtoolの便利なライブラリをリンク し,プログラムにはリンクしないようにしてください,そして,libtoolの便利 なスタティックライブラリを一つのプログラムにのみリンクし,それは,ライブ ラリ依存情報を便利なスタティックライブラリのユーザに運ぶことが必要な場合 のみにしてください.
静的なリンクが適している,その他の一般的な状況は,独立したバイナリを作成 するときです.リンクにlibtoolを使用し,`-all-static'フラグを加えて ください.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
This document was generated by Akihiro Sagawa on June, 15 2005 using texi2html 1.70.