libtool

前回力尽きた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を使っている場合は、以下のコマンドでインストールできる

```shell-session
% sudo pkg install libtool
```
今日時点では、libtool 2.4.5 がインストールされた。

# libtoolの使い方
## ライブラリに入れるソースのコンパイル
今回もソースを用意しよう。

```c:func4.c
int func4(void)
{
    return 7;
}
```
ビルドするときのコマンドは、以下。

```shell-session
% 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がつかないもの。
このコマンドにより、以下のファイルが生成される。

<dl>
<dt>func4.o</dt>
<dd>静的ライブラリ用のオブジェクト</dd>
<dt>func4.lo</dt>
<dd>libtoolオブジェクト(テキストファイル)</dd>
<dt>.libs/func4.o</dt>
<dd>動的ライブラリ用のオブジェクト</dd>
</dl>

## ライブラリの生成
ライブラリの生成は、以下のコマンドで行う

```shell-session
% 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オプションを指定する。

このコマンドにより生成されるファイルは以下

<dl>
<dt>libfunc4.la</dt>
<dd>libtool control file</dd>
<dt>.libs/libfunc4.a</dt>
<dd>静的ライブラリ</dd>
<dt>.libs/libfunc4.la</dt>
<dd>../libfunc4.laへのシンボリックリンク</dd>
<dt>.libs/libfunc4.lai</dt>
<dd>インストール用のlaファイル</dd>
<dt>.libs/libfunc4.so</dt>
<dd>libfunc4.so.0.0.0へのシンボリックリンク</dd>
<dt>.libs/libfunc4.so.0</dt>
<dd>libfunc4.so.0.0.0へのシンボリックリンク</dd>
<dt>.libs/libfunc4.so.0.0.0</dt>
<dd>動的ライブラリ</dd>
</dl>

## 実行ファイルの生成

```c:test4.c
int func4(void);
int main(int argc, char *argv[])
{
    return func4();
}
```
```shell-session
% 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オプション等は気にしなくて良い。

このコマンドにより生成されるファイルは以下

<dl>
<dt>test4</dt>
<dd>実行ファイルのwrapper script</dd>
<dt>.libs/test4</dt>
<dd>実行ファイルの実体</dd>
</dl>

前回の例と違うのは、ここで生成されるtest4が実行可能であると言うこと。
インストール前に、思う存分テストができる。

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

```shell-session
% 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
```
実行ファイルのインストール

```shell-session
% sudo libtool --mode=install install -c test4 /usr/local/bin/
libtool: install: install -c .libs/test4 /usr/local/bin/test4
```

lddで見てみる

```shell-session
% 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にあるライブラリを使うときと同じ

```shell-session
% 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もインストールされているので、静的リンクも可

```shell-session
% cc -o test4-3 -static test4.c -L/usr/local/lib -lfunc4
% ldd test4-3
ldd: test4-3: not a dynamic ELF executable
```