スタティックリンクとダイナミックリンクによって作成される実行バイナリサイズの違い
前回スタティックリンクとダイナミックリンクの違いを述べ、それぞれの方法でリンクした時のファイルのサイズを見ようとしたが、printfのスタティックライブラリが見つからなかったので、途中で断念してしまった。そこで今回は自分で関数を作ってそれをライブラリにして、スタティック・ダイナミックの二つの方法でリンクしてみようと思う。
注意点
私はMacを使っているのだが、Macでgccを使おうとするとデフォルトでclangを使おうとするようだ。具体的に以下のコマンドを実行するとわかる。
$ gcc -v Apple clang version 13.1.6 (clang-1316.0.21.2.5) Target: x86_64-apple-darwin21.6.0 Thread model: posix InstalledDir: /Library/Developer/CommandLineTools/usr/bin
そこで、brewなどを使ってGNUのgccを使えるようにすることを推奨する。なぜなら今回はgccを想定したリンクを行うのだが、gccのオプションはclangでは使えないからだ。私は/usr/local/bin/gcc-12
を今回使用した。
準備
以下の2つのC言語ソースコードを準備した。add関数の方をライブラリにするつもりだ。
main.c #include "Add.c" int main() { int a = 1; int b = 2; int n = 100; int c; c = add(a, b, n); return c; }
// Add.c int add(int a, int b, int n) { int c = 0; for (int i = 0; i < n; i++) { c -= a; c += b; } return c; }
ダイナミックリンク
まずは、ダイナミックライブラリを以下のコマンドで作る。
gcc-12 -shared -fPIC -o libAdd.so Add.c
ここで、-fPIC
オプションは、共有ライブラリを作るときに使われるオプションで、メインメモリのどこに配置されても絶対アドレスに関わらず正しく実行されることを保証するものである。Position-Independent Codeの略称である。また共有ライブラリを作るため、オプションとして-shared
も忘れずにつける。
最後に以下のコマンでmain.cのコンパイルと共有ライブラリとのダイナミックリンクを行う。
$ gcc-12 -L. -o main.dynamic main.c -lAdd
スタティックリンク
まず、Add.cのオブジェクトファイルを作る。
$ gcc-12 -c Add.c -o Add.o
これを以下のコマンドで静的ライブラリに変換する。
$ ar rcs libAdd.a Add.o
最後に、このライブラリを用いて、スタティックリンクを行う。
$ gcc-12 -o main.static main.o -L. -lAdd
その後、ダイナミックリンクをした実行バイナリとスタティックリンクをした実行バイナリのファイルサイズを比較した結果が以下だ。
16568 11 1 09:44 main.dynamic 49456 11 1 09:49 main.static
スタティックリンクをした実行バイナリの方が3倍程度も大きくなっていることがわかる。ダイナミックリンクの方がメモリ効率が良いことをこれらの実験で確認することができた。