4.3. DLL のビルドと利用

DLL とはダイナミックリンクライブラリのことであり、 ライブラリがビルド時ではなくプログラムの実行時にリンクされることを意味します。 DLL は 3 つの部分に分かれています。

コードとデータはあなたが記述する部分、すなわち関数、 変数などです。これらは全て、 一つの大きなオブジェクトファイルを作成するように互いにマージされ、 DLL 内部に格納されます。.exe には格納されません。

エクスポートには DLL が他のプログラムに対して提供する関数と変数のリストが含まれています。 これらは「グローバル」シンボルのリストであると考えられ、残りは隠されています。 通常、このリストはテキストエディタによって手作業で作成されますが、 しかしコード中の関数のリストから自動的に作成することも出来ます。 dlltool プログラムは、 エクスポートされたシンボルが記述されたテキストファイルから DLL のエクスポートセクションを作成します。

インポートライブラリは通常の UNIX 風の .a ライブラリですが、 プログラムがどのように DLL と互いに影響しあう(インポートする) かを OS に伝えるために必要となる、ごく小さな情報だけを含んでいます。 この情報は .exe にリンクされます。 これもまた dlltool から作成されます。

このページでは、gcc によって DLL を構築する単純な例を示すだけにしておきます。 更なる沢山の追加機能について調べてみるつもりなら、gcc のドキュメントか、現在は http://gcc.gnu.org/ にある Web サイトを参照することから始めてみて下さい。

それでは、DLL をビルドする単純な例をお見せしましょう。 この例では、プログラム(myprog.exe) に対する一つのファイル myprog.c と、 DLL(mydll.dll) の内容となる一つのファイル mydll.c を使用します。

幸運にも、最新の gcc と binutils を利用するのであれば、DLL をビルドする手順は今や非常に単純なものとなっています。 mydll.c 中の、この最小の関数をビルドするとしましょう。

#include <stdio.h>

int
hello()
{
  printf ("Hello World!\n");
}

最初に、mydll.c をオブジェクトコードへとコンパイルします。

gcc -c mydll.c

続いて、gcc に共有ライブラリをビルドさせます。

gcc -shared -o mydll.dll mydll.o

これだけです! この例を完了すべく、作成した DLL を単純なプログラムへとリンクしてみましょう。

int
main ()
{
  hello ();
}  

以下のようなコマンドを利用して、先ほどの DLL をリンクしてみます。

gcc -o myprog myprog.c -L./ -lmydll

しかし、DLL をエクスポートライブラリとしてビルドするのであれば、 恐らく次のようなコンパイル構文を利用することになるでしょう。

gcc -shared -o cyg${module}.dll \
    -Wl,--out-implib=lib${module}.dll.a \
    -Wl,--export-all-symbols \
    -Wl,--enable-auto-import \
    -Wl,--whole-archive ${old_libs} \
    -Wl,--no-whole-archive ${dependency_libs}

${module} はライブラリの名前ですが、DLL に対しては接頭辞 cyg が、インポートライブラリについては接頭辞 lib が付与されます。 ネイティブの Windows MinGW DLL との区別をつけるため、Cygwin の DLL は接頭辞として cyg を利用します。詳細については MinGW Web サイト を参照して下さい。 ${old_libs} は全てのオブジェクトファイル(組み込まれる静的ライブラリ、或いは単体のオブジェクトファイル)であり、 ${dependency_libs} はリンクに必要となるインポートライブラリ (例えば、「'-lpng -lz -L/usr/local/special -lmyspeciallib'」)です。

既存の DLL をリンクするためには、Cygwin と互換性のあるインポートライブラリを作成する必要があります。 DLL をコンパイルするために必要なソースが手元にあるのなら、 gcc を利用して DLL をビルドする方法の詳細については 項4.3.1. 「DLL のビルド」 を参照して下さい。 もしソースが手元になく、利用可能なインポートライブラリも提供されていない場合、 以下のコマンド群によって .def ファイルを作成することにより、 この作業の大部分を行うことが出来ます (クォーティングが正しく行われるように、この作業は bash を使って行う必要があります)。

echo EXPORTS > foo.def
nm foo.dll | grep ' T _' | sed 's/.* T _//' >> foo.def

これは DLL がストリップされていない場合のみ可能であることを覚えておいて下さい。 そうでなければ「No symbols in foo.dll(foo.dll にはシンボルが含まれていません)」 というエラーメッセージが発生することになるでしょう。

一旦 .def ファイルが出来上がったなら、 このようにしてこのファイルからインポートライブラリを作成出来ます。

dlltool --def foo.def --dllname foo.dll --output-lib foo.a