静的ライブラリ (.a) の作成と利用
静的ライブラリ (.a) の作成
ar コマンド
で複数のオブジェクトファイル (.o
) をまとめて静的ライブラリ (.a
)
を作成できます。
ar rcs libfoo.a foo.o bar.o baz.o
静的ライブラリをリンクする
オブジェクトファイルをリンクするのと同じように gcc に引数を渡すとリンクされます
gcc(g++) -o program program.o libfoo.a
-L
で指定したディレクトリにある libname.a
という静的ライブラリは
-lname
として指定することもできる。 たまにみる -lpthread
とかは
libpthread.a
をリンクするという意味です。
gcc(g++) -o program program.o -L. -lfoo
ただし後述するように、オブジェクトファイルをリンクする場合と違って 静的ライブラリ (.a) をリンクする場合は引数の順序が重要になるので注意が必要です <linker>。
静的ライブラリの内容(シンボル)の確認
nm コマンドで .o
ファイルや .a
ファイルに存在するシンボルを確認することができます。
$ nm foo.o
U _Z7say_bari
0000000000000000 T _Z7say_fooi
U __gxx_personality_v0
U printf
$ nm bar.o
0000000000000000 T _Z7say_bari
U _Z7say_fooi
U __gxx_personality_v0
U printf
$ ar rcs foobar.a foo.o bar.o
$ nm foobar.a
foo.o:
U _Z7say_bari
0000000000000000 T _Z7say_fooi
U __gxx_personality_v0
U printf
bar.o:
0000000000000000 T _Z7say_bari
U _Z7say_fooi
U __gxx_personality_v0
U printf
リンカーの挙動
静的ライブラリをリンクする場合は、引数で与える静的ファイルやオブジェクトファイルの順序が重要になります。 基本的にはAがBに依存しているなら、AをBの前に引数で与えなくてはなりません。 このルールはリンカーが静的ライブラリ内のオブジェクトファイルを参照する際の挙動を理解していると分かりやすいです。
大雑把な流れ
リンカは未解決の参照のリストを保持している。はじめ、このリストにはmainが入っている1。 リンカはオブジェクトファイル(.o)を受け取り、参照を解決し、新しい未解決の参照がみつかったらリストに追加する(リンクする)。 静的ライブラリ(.a)を受け取った場合は、未解決の参照を定義しているオブジェクトファイルのみを静的ライブラリから抜き出し、リンクを行う。 いままで処理したオブジェクトファイルから参照されていないオブジェクトファイルは 静的ライブラリに含まれていても無視される。 そのため、main.oがlibfoo.a内のシンボルを参照している場合
gcc -o program main.o libfoo.a
は問題なく実行できるが
gcc -o program libfoo.a main.o
は、libfoo.aをリンカが読み込んだ時点ではlibfoo.a内のシンボルは「未解決の参照リスト」には含まれてないので libfoo.a内のオブジェクトファイルはリンカに無視されてしまい、 あとでmain.oを読み込んだ際に、参照の解決が行えなくなりエラーとなる。
whole-archive
リンカ(ld)に --whole-archive
を指定すると、それ以降の引数で与えらる静的ライブラリに含まれる全てのオブジェクトファイルがリンクされるようになる。
--no-whole-archive
で挙動を元に戻す。 gcc(g++)の引数で指定する場合は
-Wl,
を前につける
# これはコンパイルできる
gcc -o program -Wl,--whole-archive libfoo.a -Wl,--no-whole-archive main.o
文献
-
厳密にはmainへの参照をもつcrt0.oがリンカに渡されるというのが正しい?
↩