42 にわか勉強: ローダブル・モジュールとかダイナミック・ローディングとか

(勉強中なので内容の正確さは保証しない。元々すべてがそうだけど。)


(ダイナミック, 動的, 実行時) ローディングとかモジュールとか、 共有ライブラリィとか、 ぼんやり分かっているようなつもりでいたけれど、 勉強が必要そうに感じたので。


言葉の使い方が、OS によっても違ったりするそうである。 特に Mac は他とは違い独特とか。 以下は、Mac で使うことを念頭にまとめる。


(このパラグラフは自分勝手説明かも…言い訳をすると、 元々どの OS でも通用するような用語が決まっていないらしく、 仕方がないのではないか…) 一つの実行プログラムは、複数のソースプログラムから作るのが普通で、 それを組み合わせる仕方に、 リンク (静的リンクと動的リンクがある) と実行時のロードがある。 動的リンクは、実行時にライブラリィをロードすると言っても良さそうで、 言葉ではっきり区別しにくいところがある。 Mac でははっきり区別するそうで、 それを独特という人がいるけれど、 説明をする場合は、区別する方が説明しやすいので、以下ではそうする。


以下の内容は、 「Macでのライブラリの作り方」 を読んで理解したもので、説明プログラムもそこのを拝借している。 プログラムの名前を変えたり、説明の順序を入れ替えているけれど、 それで何か間違いが入っているかもしれない (その場合はすみません)。


リンク
リンクには、静的なリンクと動的なリンクがある。
(動的)ロード
ロードモジュールというのを作り、実行時にそれを呼び出して使う (メモリにロードするという感覚で「ロードする」と言うのか?)。 共有ライブラリィと呼ぶ人もいるようだが、 そうすると動的なリンクのためのライブラリィと区別しにくい?

動的リンクでは、実行形式を作る「リンク」の段階で、 どのライブラリィとリンクするか名前を決めなければならない (後から同じ名前の別ライブラリィに差し替える、という裏技はできるけど)。

これに対して、動的ロードでは、 プログラムの実行時にどのモジュールをロードするか決めれば良い。 実行形式を作るときに、ロードするモジュールの名前を決める必要はない。

動的なモジュールの拡張子として、.so が使われることが多いが、 Macの場合 Apple は .bundle を推奨しているそうだ。


リンクの実例     繰り返しになるが、以下のプログラムは丸々拝借している。

リンクには二種類の方法があるが、どちらをするにしても、 ソース・プログラムは共通で済む。
libhello.h
    
/Users/mk/.tex-inputs/staticlink_dynamiclink_dynamicload/libhello.h
libhello.c
    
/Users/mk/.tex-inputs/staticlink_dynamiclink_dynamicload/libhello.c
main_link.c
    
/Users/mk/.tex-inputs/staticlink_dynamiclink_dynamicload/main_link.c

メインのプログラムの方のコンパイルの仕方は共通である。
gcc -Wall -g -c main_link.c -o main_link.o
静的なリンクをして実行形式 (main_static) を作るには、 静的なライブラリィ (.a) を作ってそれとリンクする。
静的なリンク (比較的一般的なやり方)
gcc -Wall -g -c -o libhello.o libhello.c
ar rcs libhello.a libhello.o
gcc -g -o main_static main_link.o -L. -lhello
動的なリンクをして実行形式 (main_dynamic) を作るには、 静的なライブラリィ (.dylib) を作ってそれとリンクする。
動的なリンク (これは自分ではやったことがない)
gcc -fno-common -fPIC -Wall -g -c libhello.c
gcc -g -dynamiclib -install_name libhello.0.0.0.dylib \
  -compatibility_version 0.0 \
  -current_version 0.0.0 \
   -o libhello.0.0.0.dylib libhello.o -lc
ln -s libhello.0.0.0.dylib libhello.0.dylib
ln -s libhello.0.0.0.dylib libhello.dylib
#rm -f libhello.a
gcc -g -o main_dynamic main_link.o -L. -lhello
以上は macOS の場合であるが、Solaris や Linux では、 .dylib でなくて .so と言う拡張子を使う。

動的ロードの実例     繰り返しになるが、以下のプログラムは丸々拝借している。

モジュール (「ライブラリィ」) 側のソース・プログラムは上と同じで良い。 まずモジュール (libhello.so) を作ってみる。
Macでの動的モジュールの作成
gcc -fno-common -fPIC -Wall -g -c libhello.c
gcc -bundle -flat_namespace -undefined suppress -o libhello.so libhello.o
(Apple 的には、libhello.so よりも libhello.bundle と言う名前を推奨しているそうである。 FreeFem++ に対する plotPDF() では、 plotPDF.dylib という名前にしたけれど、ちょっと変わった選択なのかも (動的モジュールなので、Apple 推奨の御作法にのっとれば plotPDF.bundle で、Linux などの流儀の真似をすれば plotPDF.so となる?私が勘違いをしているのかもしれないけれど。)。

次はこれを呼び出す側だが、これはちょっと面倒である。
main_load.c

/Users/mk/.tex-inputs/staticlink_dynamiclink_dynamicload/main_load.c
コンパイルそのものは普通にやれば良い。
gcc -Wall -g -c main_load.c -o main_load.o
実行形式の生成(リンク)は、-ldl するだけが要点である。
gcc -g -o main_load main_load.o -ldl

どのモジュールをロードするかは、 この場合 main_load.c の中に書かれているわけだが、 その気になれば "libhello.so" という文字列を実行時にユーザーに決めさせることも出来るわけだ ("libbye.so" とか)。 確かにダイナミック・リンクとダイナミック・ロードは違う概念だ。


FreeFem++ で plotPDF() を使う場合、 実行形式 (FreeFem++) の方は先に作ってあって、 plotPDF() の入っているモジュールは後から作って、 どれをロードするか .edp の中で指定できる (それこそユーザーに文字列入力させて選ぶようにもできる)、 と言うことだ。



桂田 祐史