前回力尽きたlibtoolについて。
/usr/local/libにあるライブラリを見ていると、.laとか、.so.1.1.0 みたいなファイルがあることに気づく。
こう言ったライブラリをリンクするときは、たとえば -lhoge とか書くとlibhoge.laを見てリンクが実行される。
この、*.laが何者なのか?と言う疑問がこのエントリを書いた動機である。
答えを先に言ってしまえば、これは GNU libtoolが作成したファイルである。
libtoolは、おそらく直接呼ぶことは少なくて、autoconf/automakeが生成したMakefileから呼び出されるツールである。
が、libtool単体でも使うことができるので、ここでは簡単なサンプルを挙げて説明してみる。
詳細なマニュアルは、http://www.gnu.org/software/libtool/manual/ から参照することができる。
前回、直接ccを呼び出して動的ライブラリを作成する方法について説明したが、「-fPICつけるんだっけ?」とか、「-rpathと-rpath-linkを適切に指定しないと・・・」とか、「とりあえずビルドはできたけど、インストール前に試しに実行しようと思っても.soが見つからなくてエラーになる」とかいろいろ問題がある。
そんな問題を解決してくれるのがlibtoolである。
libtoolのインストール
FreeBSDのbaseシステムには、libtoolは入っていない。pkgngを使っている場合は、以下のコマンドでインストールできる
% sudo pkg install libtool
今日時点では、libtool 2.4.5 がインストールされた。
libtoolの使い方
ライブラリに入れるソースのコンパイル
今回もソースを用意しよう。
int func4(void)
{
return 7;
}
ビルドするときのコマンドは、以下。
% libtool --mode=compile cc -c func4.c
libtool: compile: cc -c func4.c -fPIC -DPIC -o .libs/func4.o
libtool: compile: cc -c func4.c -o func4.o >/dev/null 2>&1
libtool --mode=compile
に続けて、通常のコンパイルコマンドを書けば良い。
libtoolを使うと、2回コンパイルされる。1度目は動的ライブラリ用に-fPICがついたもの、2度目は静的ライブラリ用に-fPICがつかないもの。
このコマンドにより、以下のファイルが生成される。
- func4.o
- 静的ライブラリ用のオブジェクト
- func4.lo
- libtoolオブジェクト(テキストファイル)
- .libs/func4.o
- 動的ライブラリ用のオブジェクト
ライブラリの生成
ライブラリの生成は、以下のコマンドで行う
% libtool --mode=link cc -o libfunc4.la func4.lo -rpath /usr/local/lib
libtool: link: cc -shared -fPIC -DPIC .libs/func4.o -Wl,-soname -Wl,libfunc4.so.0 -o .libs/libfunc4.so.0.0.0
libtool: link: (cd ".libs" && rm -f "libfunc4.so.0" && ln -s "libfunc4.so.0.0.0" "libfunc4.so.0")
libtool: link: (cd ".libs" && rm -f "libfunc4.so" && ln -s "libfunc4.so.0.0.0" "libfunc4.so")
libtool: link: ar cru .libs/libfunc4.a func4.o
libtool: link: ranlib .libs/libfunc4.a
libtool: link: ( cd ".libs" && rm -f "libfunc4.la" && ln -s "../libfunc4.la" "libfunc4.la" )
libtool --mode=link
に続けて、cc -o 出力するライブラリ名(.la)、入力となるlibtoolオブジェクト(.lo)を並べた後、-rpathオプションを指定する。
このコマンドにより生成されるファイルは以下
- libfunc4.la
- libtool control file
- .libs/libfunc4.a
- 静的ライブラリ
- .libs/libfunc4.la
- ../libfunc4.laへのシンボリックリンク
- .libs/libfunc4.lai
- インストール用のlaファイル
- .libs/libfunc4.so
- libfunc4.so.0.0.0へのシンボリックリンク
- .libs/libfunc4.so.0
- libfunc4.so.0.0.0へのシンボリックリンク
- .libs/libfunc4.so.0.0.0
- 動的ライブラリ
実行ファイルの生成
int func4(void);
int main(int argc, char *argv[])
{
return func4();
}
% libtool --mode=link cc -o test4 test4.c libfunc4.la
libtool: link: cc -o .libs/test4 test4.c ./.libs/libfunc4.so -Wl,-rpath -Wl,/usr/local/lib
libtool --mode=link
に続けて、通常のコンパイルコマンドを書くが、ライブラリの指定は-lオプションではなく*.laファイルを指定する。-rpathオプション等は気にしなくて良い。
このコマンドにより生成されるファイルは以下
- test4
- 実行ファイルのwrapper script
- .libs/test4
- 実行ファイルの実体
前回の例と違うのは、ここで生成されるtest4が実行可能であると言うこと。
インストール前に、思う存分テストができる。
インストール
ライブラリのインストール
% sudo libtool --mode=install install -c libfunc4.la /usr/local/lib/
libtool: install: install -c .libs/libfunc4.so.0.0.0 /usr/local/lib/libfunc4.so.0.0.0
libtool: install: (cd /usr/local/lib && { ln -s -f libfunc4.so.0.0.0 libfunc4.so.0 || { rm -f libfunc4.so.0 && ln -s libfunc4.so.0.0.0 libfunc4.so.0; }; })
libtool: install: (cd /usr/local/lib && { ln -s -f libfunc4.so.0.0.0 libfunc4.so || { rm -f libfunc4.so && ln -s libfunc4.so.0.0.0 libfunc4.so; }; })
libtool: install: install -c .libs/libfunc4.lai /usr/local/lib/libfunc4.la
libtool: install: install -c .libs/libfunc4.a /usr/local/lib/libfunc4.a
libtool: install: chmod 644 /usr/local/lib/libfunc4.a
libtool: install: ranlib /usr/local/lib/libfunc4.a
実行ファイルのインストール
% sudo libtool --mode=install install -c test4 /usr/local/bin/
libtool: install: install -c .libs/test4 /usr/local/bin/test4
lddで見てみる
% ldd /usr/local/bin/test4
/usr/local/bin/test4:
libfunc4.so.0 => /usr/local/lib/libfunc4.so.0 (0x80081d000)
libc.so.7 => /lib/libc.so.7 (0x800a1e000)
libtoolを使ってインストールしたライブラリを使う
普通に/usr/local/libにあるライブラリを使うときと同じ
% cc -o test4-2 test4.c -L/usr/local/lib -lfunc4
% ldd test4-2
test4-2:
libfunc4.so.0 => /usr/local/lib/libfunc4.so.0 (0x80081d000)
libc.so.7 => /lib/libc.so.7 (0x800a1e000)
.aもインストールされているので、静的リンクも可
% cc -o test4-3 -static test4.c -L/usr/local/lib -lfunc4
% ldd test4-3
ldd: test4-3: not a dynamic ELF executable