[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
libtoolが人生をより単純にする方法が分かるまで,独自のパッケージで libtoolを使用することを話す意味はありません.この章の例は,標準的なラ イブラリのビルド処理と,libtoolの処理を,二つの異なるプラットフォーム で比較することで,主な特徴を紹介します.
独自のプラットフォームの例をこれに続けることが可能で,それは,libtool でインストールされた,前もってコンフィグレーションされているlibtoolス クリプトを使用します(see 節 5.3 libtoolのコンフィグレーション).
以下の例のソースファイルは,libtool配布物の`demo'サブディレクトリ から持ってきています.ファイル`foo.c'と`hello.c'からライブラ リ`libhello'をビルドしていると仮定してください.
`foo.c'ソースファイルがcos
数学ライブラリ関数を使用していて, それは通常,Cライブラリではなく単独の数学ライブラリで見つかることに注 意してください(see 節 `Trigonometric Functions' in
同じ規則は,標準Cライブラリに無い関数を使用するとき,常に当てはまりま す...これらのオブジェクトに対しリンクするときは,適切な -lnameフラグをリンク行の終りに加える必要があります.
ライブラリをビルドした後,`libhello'に対して`main.o'をリンク することでプログラムを作成したいと思います.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
ソースファイルからオブジェクトファイルを作成するため,コンパイラは`-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 節 4.1 コンパイルモード).
a23$ libtool --mode=compile gcc -g -O -c foo.c gcc -g -O -c foo.c echo timestamp > foo.lo a23$ libtool --mode=compile gcc -g -O -c hello.c gcc -g -O -c hello.c echo timestamp > hello.lo a23$ |
それぞれの呼び出しで,libtoolが二つのファイルを作成することに注意して ください.`.lo'ファイルはライブラリオブジェクトで,それは共有ライ ブラリにビルドされ,`.o'ファイルは標準的なオブジェクトファイルで す.`a23'では,スタティックライブラリのみサポートされているので, ライブラリオブジェクトはタイムスタンプのみです.
共有ライブラリのあるシステムでは,ライブラリオブジェクトと標準オブジェ クトが異なるように,libtoolはPIC生成フラグをコンパイルコマンドに自動的 に挿入します.
burger$ libtool --mode=compile 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 --mode=compile 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$ |
二番目に実行されるGCCがその出力を破棄していることに注意してください. これは,コンパイラの警告がうるさく重複しないために行われます.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
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 節 4.2 リンクモード).
a23$ libtool --mode=link 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 節 3. libtoolを使用する).
共有ライブラリをビルドするその他の複雑なことは,(最終的に)インストール されるディレクトリパス(この場合は,`/usr/local/lib') (1)を指定する必要があることです.
a23$ libtool --mode=link 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 --mode=link 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の使用を忘れていて他のプログラムを実行するとき,確実に手ひどく 失敗するので役に立ちます.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
ライブラリを実行形式とリンクする前に,インストールする(恒久的な 場所にそれを配置する)場所を選択した場合,リンクするためにlibtoolを使用 する必要はありません.ライブラリの位置を指定するため,単純に適切な `-L'と`-l'フラグを使用してください.
システムのリンカによっては,結果として生じる実行形式に,共有ライブラリ の完全なディレクトリ名の符号化を強要するものもあります.libtoolは,恒 久的なディレクトリ名のみをインストールされた実行形式に書き込むことを確 実にするため,特別な魔法でこの設計ミスに関して動作する必要があります.
このバグの重要性は見落としてはなりません.それによるプログラムの暴走は 明白ではありません.それはセキュリティホールを作成し,さらに悪いことに は,パッケージのインストール後にライブラリソースコードを編集した場合, インストールされたプログラムの動作を変更してしまうでしょう!
そのため,インストールする前にライブラリとプログラムをリンクさせたい場 合,リンクするためにlibtoolを使用する必要があります.
インストールされていないライブラリとリンクする古い方法は,以下のように なります.
burger$ gcc -g -O -o hell.old main.o libhello.a -lm burger$ |
libtoolの方法は,ほとんど同じです(2)(see 節 4.2 リンクモード).
a23$ libtool --mode=link 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 --mode=link 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 --mode=link 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'にある)共有ライブラリを見つけることを保証しま す.
二つの異なるプログラムを比較してみましょう.
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キロバイトです.そのため,少なく とも二,三個以上のプログラムとリンクするまで,共有される `libhello'を維持することは利点になりません.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
`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 節 4.3 実行モード).
burger$ libtool --mode=execute 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$ |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
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 節 4.4 インストールモード).
a23# libtool --mode=install 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 節 4.6 アンインストールモード),リンクし (see 節 3.3 実行形式のリンク),dlopenでプログラムを助ける (see 節 9. dlopenモジュール)ため,libtoolのライブラリ`libhello.la' もインストールされることに注意してください.
共有ライブラリの例は,以下のようになります.
burger# libtool --mode=install 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 --mode=finish libdir'を実行すると,行う ことのヒントが与えられるはずです(see 節 4.5 フィニッシュモード).
burger# libtool -n --mode=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# |
これらのステップを完了した後,インストールされたライブラリの使用開始が 可能になります.作成されたライブラリに依存する実行形式もインストールで きます.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
インストールされていないlibtoolライブラリに対して,実行形式をリンクす るためにlibtoolを使用した場合(see 節 3.3 実行形式のリンク),ライブラリ をインストールした後に実行形式をインストールするため,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# |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |
libtoolの旨味を知って,ar
とranlib
の愚かさへなぜ戻るので しょう?さて,決して共有されるはずがないスタティックアーカイブをつくる ことが望ましいときもあります.最もよくある状況として,複数の異なるプロ グラムをビルドするために使用する,オブジェクトファイルの集まりを持って いるときがあります.個々のプログラムに対し,すべてのオブジェクトファイ ルをリストアップする代わりに,それらのオブジェクトから"コンビニエンス ライブラリ"を作成し,ライブラリとプログラムをリンクすることが可能です. この技術は,他のディレクトリのライブラリへのリンクをサポートするので, 他のディレクトリのソースからビルドされるオブジェクトファイルをリンクす るサポートが欠けている,GNU automakeを補うためによく使用されます.この 制限は,リリース1.4までのGNU automakeに当てはまります.より新しいリリー スは,他のディレクトリのソースをサポートするでしょう.
このコンビニエンスライブラリとプログラムをリンクしたいだけの場合,完全 にlibtoolを無視し,古いar
とranlib
コマンド(や,対応する GNU automake `_LIBRARIES'規則)が使用可能です.(おそらく使用したく はないでしょうが)libtoolを使用して,コンビニエンスライブラリをインストー ルすることさえ可能です.
burger$ libtool --mode=install ./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'フ ラグを加えてください.
[ << ] | [ >> ] | [表紙] | [目次] | [索引] | [検索] [上端 / 下端] [?] |