libtool on Linux, Cygwin, MinGW

(2003.11.30新規作成。)
(2004.11.07 リンク切れを修正。)
(2005.7.10 MinGWを追加。)

libtoolは、共有オブジェクト(shared object; so、あるいは動的リンクライブラリ;DLL)を生成するためのMakefileを、環境に依存せずに書くためのプログラム。

利用者(プログラムの開発者)は、Makefileで、仮想的なファイルをコンパイル、あるいはリンクするように書く。libtoolは、それらのファイルに対する操作を解釈して、実際のファイルに対するコンパイルオプションなどを生成し、実行する。

libtoolの各コマンド

libtoolは、--modeオプションで実行したい操作を区別する。modeによって、libtoolの動作は、まったく異なる。

--modeの値意味
compile コンパイル
link リンク
install インストール
uninstallアンインストール
clean クリーンアップ
execute ライブラリをインストールせずに、ライブラリを使用するプログラムを実行する。
finish 完了メッセージを表示する。

Cygwinでは、configure.(ac|in) ファイルを見て、開発版か安定版のいずれかのlibtoolを起動するようになっている。そのため、configureファイルがない場合は、libtoolは、絶対パスで記述する必要がある。

コンパイル

まずはライブラリにするためのファイルをコンパイルする。ここでのファイル名は実在のものを使う。

$ /usr/autotool/devel/bin/libtool --mode=compile gcc -c mydll.cc
mkdir .libs
 gcc -c mydll.cc  -DPIC -o .libs/mydll.o
 gcc -c mydll.cc -o mydll.o >/dev/null 2>&1

ディレクトリ.libsが生成され、必要であれば、本物の生成物はこのディレクトリに入れられる。libtoolは、自動的に適当なコンパイルオプションを追加し(-DPIC など)、コンパイルする。

カレントディレクトリにmydll.lo、mydll.oの二つのファイルが生成される。位置独立なコードオブジェクトとそうでないオブジェクトが区別される環境では、*.o は位置独立ではない、*.lo は位置独立なファイルとなる。

Cygwinでは、mydll.loは、ただのテキストファイル。MinGWでも、mydll.loは単なるテキストファイル。

ライブラリのリンク

ライブラリを生成する場合は、libtool --mode=link とする。リンクする対象(オブジェクトファイル)は、*.oではなく*.lo ファイルを指定する。

gccの -o オプションで出力するライブラリのファイル名を指定する。出力ファイルは lib で始まらなければならず、拡張子は、静的ライブラリであれば.a、動的リンクライブラリであれば.la とする。

動的リンクライブラリを出力するときは、libtoolのオプション -rpathを指定しなければならない。このオプションには、ライブラリの最終的なインストール先を指定する。

$ /usr/autotool/devel/bin/libtool --mode=link gcc mydll.lo -o libmydll.a
または
$ /usr/autotool/devel/bin/libtool --mode=link gcc mydll.lo -o libmydll.la -rpath /usr/local/lib

これで、libmydll.la が生成される。Cygwin / MinGWでは、これもテキストファイル。

Cygwinでは、libtoolのオプション -no-undefined を付けないとリンク時にエラーが発生する。このオプションは、出力ファイルが他のライブラリに依存していないことを宣言するもの。Linux, MinGWでは、-no-undefinedオプションはなくてもいい(付けても問題ない)。

$ /usr/autotool/devel/bin/libtool --mode=link gcc mydll.lo -o libmydll.la \
              -no-undefined -rpath /usr/lib
gcc -shared  .libs/mydll.o   -o .libs/cygmydll-0.dll 
    -Wl,--image-base=0x10000000 -Wl,--out-implib,.libs/libmydll.dll.a
Creating library file: .libs/libmydll.dll.a
ar cru .libs/libmydll.a  mydll.o
ranlib .libs/libmydll.a
creating libmydll.la
(cd .libs && rm -f libmydll.la && ln -s ../libmydll.la libmydll.la)

Cygwinでは、次のように、*.dllファイルが生成される。

$ ls .libs/
cygmydll-0.dll  libmydll.a  libmydll.dll.a  libmydll.la  libmydll.lai  mydll.o

-export-symbols または -export-symbols-regex オプションでエクスポートするシンボルを指定することもできる。付けなければ、すべてのシンボルがエクスポートされる。

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

(2005.7.10 この節追加。)

ライブラリをインストールするには、libtool --mode=install を使う。installまたはcpコマンドとそのオプションを続けて書く。コピー元は*.laファイル、コピー先はディレクトリにする。

libtool --mode=install [ install | cp ] ...

Linuxでは、次のようになる。

$ libtool --mode=install cp libmydll.la /home/hori/src/test/share/simple/t
cp .libs/libmydll.so.0.0.0 /home/hori/src/test/share/simple/t/libmydll.so.0.0.0
(cd /home/hori/src/test/share/simple/t && rm -f libmydll.so.0 && ln -s libmydll.so.0.0.0 libmydll.so.0)
(cd /home/hori/src/test/share/simple/t && rm -f libmydll.so && ln -s libmydll.so.0.0.0 libmydll.so)
cp .libs/libmydll.lai /home/hori/src/test/share/simple/t/libmydll.la
cp .libs/libmydll.a /home/hori/src/test/share/simple/t/libmydll.a
ranlib /home/hori/src/test/share/simple/t/libmydll.a
chmod 644 /home/hori/src/test/share/simple/t/libmydll.a

クリーンアップ

オブジェクトファイルなどを一掃するには、libtool --mode=clean とする。

$ /usr/autotool/devel/bin/libtool --mode=clean rm libmydll.la main.lo \
          main.o mydll.lo mydll.o testpg testpg.exe 
rm libmydll.la .libs/libmydll.dll.a .libs/libmydll.a .libs/libmydll.la .libs/libmydll.lai
rm main.lo ./.libs/main.o ./main.o
rm main.o
rm: cannot remove `main.o': No such file or directory
rm mydll.lo ./.libs/mydll.o ./mydll.o
rm mydll.o
rm: cannot remove `mydll.o': No such file or directory
rm testpg .libs/testpg .libs/testpgS.o .libs/lt-testpg
rm: cannot unlink `.libs/testpg': No such file or directory
rm: cannot remove `.libs/testpgS.o': No such file or directory
rm: cannot remove `.libs/lt-testpg': No such file or directory
rm testpg.exe testpg
rm: cannot remove `testpg': No such file or directory
rmdir .libs

む、main.o、mydll.o、testpg は不要だったか。

利用プログラムとのリンク

メインプログラムをコンパイルする。これもlibtool --mode=link を使う。

$ /usr/autotool/devel/bin/libtool --mode=compile gcc -g -c main.cc
 gcc -g -c main.cc  -DPIC -o .libs/main.o
 gcc -g -c main.cc -o main.o >/dev/null 2>&1

$ /usr/autotool/devel/bin/libtool --mode=link gcc -o testpg main.o libmydll.la 
gcc -o .libs/testpg main.o  ./.libs/libmydll.dll.a
creating testpg.exe

これで、仮想的な testpg(シェルスクリプト)、仮想的な testpg.exe(何?)、実体である.libs/testpg.exe が生成される。

Makefileの作成

これらを踏まえて、Makefileを作成すると、次のようになる。-no-undefined と .exe はCygwin依存。完全に差異を吸収するのはなかなか難しい。このほか、Linuxではリンク時に-lstdc++オプションが必要になる。

# Cygwinでは次のようにする
LIBTOOL = /usr/autotool/devel/bin/libtool
LDFLAGS = 
EXEEXT = .exe

# Linuxでは次のようにする
#LIBTOOL = /usr/bin/libtool
#LDFLAGS = -lstdc++
#EXEEXT =

.SUFFIXES: .cc .lo .la $(EXEEXT)

.cc.lo:
	$(LIBTOOL) --mode=compile gcc -c $< -o $@

testpg$(EXEEXT): main.lo libmydll.la
	$(LIBTOOL) --mode=link gcc -o $@ $^ $(LDFLAGS)

libmydll.la: mydll.lo
	$(LIBTOOL) --mode=link gcc -o $@ $^ -no-undefined -rpath /usr/local/lib

main.lo: main.cc
mydll.lo: mydll.cc

clean:
	$(LIBTOOL) --mode=clean rm -rf libmydll.la main.lo mydll.lo testpg$(EXEEXT)

エクスポートするシンボルを指定する

2003.12.03

上記の例では、すべての関数をエクスポートしていた。特定の関数だけエクスポートする場合は、シンボル一覧ファイルを別に用意する。

次のファイルからライブラリを作り、このうちexp_func()だけエクスポートしてみる。

#include <stdio.h>

extern "C" {
void exp_func();
void no_exp_func();
}

void exp_func() {
    printf("ok.\n");
}

void no_exp_func() {
    printf("failed.\n");
}

次の内容のシンボルファイル dll2.sym を作る。エクスポートするシンボルを1行1シンボルにて記述する。シンボルの先頭に'_'などを付ける必要はない。このシンボル名は、CygwinでもLinuxでも同じものが使える。

exp_func

Makefileでは、次のように書く。libtool の -export-symbols オプションでこのファイルを指定する。

libdll2.la: dll2.lo
	$(LIBTOOL) --mode=link gcc -o $@ $^ -no-undefined -rpath /usr/local/lib \
                   -export-symbols dll2.sym

libtoolは、Cygwinの場合は内部で次のファイルを生成し、これをgccに与えることで特定のシンボルだけエクスポートする。

EXPORTS
exp_func

外部リンク

Libtool
libtool 1.5のマニュアルの日本語訳
Using static and shared libraries across platforms
いろいろな環境での、ライブラリ生成、使用のためのコンパイルオプション、環境変数など。