2003.11.29新規作成。
Cygwinでは、共有オブジェクト(動的リンクライブラリ;DLL)の拡張子は.dllとなる。ELFフォーマットを使うUNIXでは拡張子は.so であり、また、コンパイルオプションも若干変えないといけない。以下、UNIXと比較しつつ、Cygwinでライブラリを生成する方法を書く。
UNIXでは、次のようなファイル名となる。.so の後ろの .1.2.3 でライブラリのインターフェイスのバージョンを表すことになっている。インターフェイスに非互換な変更があった場合には、foo.so.2 として、foo.so.1 と区別できるようにする。
foo.so.1.2.3
Cygwin、というかWindowsでは、次のようなファイル名となる。ファイル名にインターフェイスのバージョンが含まれないため、トラブルが起こることが多い。拡張子が異なるため、UNIXと両対応にするためにはMakefileに工夫がいる。あるいはlibtoolなど何かしらツールを使ったほうがいいかも。libtool
bar.dll
ごく簡単なソースを用意する。ファイル名はmydll.ccとする。
#include <stdio.h> extern "C" { void testfunc(); } void testfunc() { printf("test ok.\n"); }
Cygwinでは、ライブラリ用のソースをコンパイルするときに -fPICオプションを付けなくてもいい。Windows(PEフォーマット)では、常に位置独立コード (position-independent code; PIC) が生成される。
$ gcc -c mydll.cc -o mydll.o
リンクは、次のようにする。これでライブラリ mydll.dllが生成される。-sharedを付けないと、WinMain()を探そうとしてエラーになる。UNIXでは libfoo.so のように、ファイル名の頭にlibを付けないといけないが、Cygwinではその必要はない。
$ gcc -shared -o mydll.dll mydll.o
ライブラリを使うメインプログラムを書く。次のファイルは名前をmain.ccとする。
extern "C" { extern void testfunc(); } int main() { testfunc(); return 0; }
コンパイルする。-lオプションで探すライブラリ名にはlibは付けられない。
$ gcc main.cc -L. -lmydll
実行してみる。
$ ./a test ok.
ところで、nmコマンドでエクスポート、インポートの状況を確認できる。I が付いているものは、外部リンクであることを示す。
$ nm mydll.dll | grep testfunc 1000101a T _testfunc
$ nm a.exe | grep testfunc 004040e8 I __imp__testfunc 004016f0 T _testfunc
ちなみに静的にリンクした場合のnmの結果は次のとおり。I の付くものは表示されない。
$ nm a.exe | grep testfunc 0040108a T _testfunc
ライブラリは、プログラムの実行を開始してから、動的にリンクすることもできる。
動的にリンクするには、dlopen()、dlsym()、dlclose()を使う。これらは、<dlfcn.h>で宣言されている。
void *dlopen(const char *file, int mode); void *dlsym(void *restrict handle, const char *restrict name); int dlclose(void *handle);
先ほどのライブラリを動的にリンクし、testfunc()を呼び出すプログラムは、次のようになる。Cygwinは、dlopen()のモードのうち、RTLD_LOCAL をサポートしていない。
#include <assert.h> #include <dlfcn.h> int main() { void (*testfunc)(); void* mylib_handle = dlopen("mydll.dll", /*RTLD_LOCAL |*/ RTLD_LAZY); assert(mylib_handle); testfunc = (void (*)()) dlsym(mylib_handle, "testfunc"); assert(testfunc); testfunc(); dlclose(mylib_handle); return 0; }