[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

3. libtoolを使用する

libtoolが人生をより単純にする方法が分かるまで,独自のパッケージでlibtool を使用することを話す意味はありません.この章の例は,標準的なライブラリの ビルド処理と,libtoolの処理を,2つの異なるプラットフォームで比較すること で,主な特徴を紹介します.

` a23'

スタティックライブラリのみのUltrix 4.2プラットフォーム.

` burger'

共有ライブラリを持つ,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 オブジェクトファイルの作成

ソースファイルからオブジェクトファイルを作成するため,コンパイラは`-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がその出力を破棄していることに注意してください.こ れは,コンパイラの警告がうるさく重複しないために行われます.


3.2 ライブラリのリンク

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の使 用を忘れていて他のプログラムを実行するとき,確実に手ひどく失敗するので役 に立ちます.


3.3 実行形式のリンク

ライブラリを実行形式とリンクする前に,インストールする(永久に位置 する場所にそれを配置する)場所を選択した場合,リンクするために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'を維持する ことは利点になりません.


3.4 実行形式のデバッグ

`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$

3.5 ライブラリのインストール

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のインストールは,同様に全く単純です.通常使用する, installcpコマンドをそのまま使用してください (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#

これらのステップを完了した後,インストールされたライブラリの使用開始が可 能になります.作成されたライブラリに依存する実行形式もインストールできま す.


3.6 実行形式のインストール

インストールされていない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#

3.7 スタティックライブラリとのリンク

libtoolの旨味を知って,arranlibの愚かさへなぜ戻るのでしょ う?さて,決して共有されるはずがないスタティックアーカイブをつくることが 望ましいときもあります.最もよくある状況として,複数の異なるプログラムを ビルドするために使用する,オブジェクトファイルの集まりを持っているときが あります.個々のプログラムに対し,すべてのオブジェクトファイルをリストアッ プする代わりに,それらのオブジェクトから"便利なライブラリ"を作成し,ラ イブラリとプログラムをリンクすることが可能です.この技術は,他のディレク トリのライブラリへのリンクをサポートするので,他のディレクトリのソースか らビルドされるオブジェクトファイルをリンクするサポートが欠けている,GNU automakeを補うためによく使用されます.この制限は,リリース1.4までのGNU automakeに当てはまります.より新しいリリースは,他のディレクトリのソース をサポートするでしょう.

この便利なライブラリとプログラムをリンクしたいだけの場合,完全にlibtool を無視し,古いarranlibコマンド(や,対応する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.