clang++ による DLL (ダイナミックリンクライブラリ) のビルド

D言語で作成した数値計算プログラムが思っていたほど速くなかったので、C++ で作成した関数を clang++ で DLL にコンパイルし、それを D言語のプログラムから呼び出すことを検討しています。

以下では、clang++ を使って DLL をビルドした後、D言語のプログラムから DLL を呼び出す手順について説明します。


ダウンロードとインストール

1. LLVMClang for Windows (現時点での最新版:LLVM-3.4-win32.exe)

Dドライブの直下にインストールします。 → D:\LLVM

2. MinGWMinGW – Minimalist GNU for Windows (mingw-get-setup.exe)

Dドライブの直下に MinGW をインストールします。 → D:\MinGW

MinGW Installation Manager を起動して、”mingw32-gcc-g++” を選択 → Mark for Installation


メニューから、Installation → Apply Changes


3. DMD (現時点での最新版:dmd.2.063.2.zip)

解凍して Dドライブの直下に置きます。 → D:\dmd2

4. Digital Mars C and C++ Compiler PackagesBasic Utilities (bup.zip)

解凍して Dドライブの直下に置きます。 → D:\dm

dm の中にある implib.exe は、.dll ファイルからインポートライブラリ (.lib ファイル) を生成する際に必要になります。

フォルダの配置はあくまで一例ですので、配置に合わせて以下の設定をして下さい。


DLL ビルド用プログラムの作成 (C++)

DLL をビルドするのに必要なファイルは、呼び出される関数が入ったファイル (array.cpp) だけです。モジュール定義ファイルはなくても構いません。

array.cpp

extern "C" void setArray(double* a, int i, double ai) {
  a[i] = ai;
}

extern "C" double getArray(double* a, int i) {
  return a[i];
}


.dll ファイルのビルド

dll.bat を array.cpp のあるフォルダに入れて実行すると array.dll がビルドされます。

dll.bat

set path=D:\LLVM\bin;D:\MinGW\bin
clang++ -std=c++11 -O -shared array.cpp -o array.dll


.lib ファイルの生成

lib.bat を array.dll のあるフォルダに入れて実行するとインポートライブラリ array.lib (テキストファイル)が生成されます。インポートライブラリ (.lib ファイル) は暗黙的リンクの場合に必要になります。明示的リンクの場合は必要ありません。

lib.bat

set path=D:\dm\bin
implib /system array.lib array.dll


DLL リンク用プログラムの作成 (D言語)

DLL をリンクするプログラムは、暗黙的リンクの場合と明示的リンクの場合で異なります。明示的リンクの場合は、リンクする .dll のファイル名を明示する必要がありますが、暗黙的リンクの場合は、その必要はありません。

(暗黙的リンクの場合)

implicit.d

import std.stdio;

extern (C) void setArray(double*, int, double);
extern (C) double getArray(double*, int);

void main() {
  uint n = 10;
  auto a = new double[](n);
  a[] = 0;
  foreach (i; 0..a.length) {
    setArray(a.ptr, i, cast(double)i);
    writefln("a[%d] = %.5f", i, getArray(a.ptr, i));
  }
}

(明示的リンクの場合)

explicit.d

import std.stdio;

extern (Windows) void* LoadLibraryA(in char*);
extern (Windows) void* GetProcAddress(void*, in char*);
extern (Windows) int FreeLibrary(void*);

alias extern (C) void function(double*, int, double) type_setArray;
alias extern (C) double function(double*, int) type_getArray;

void main() {
  auto dll = LoadLibraryA("array.dll");
  auto setArray = cast(type_setArray)GetProcAddress(dll, "setArray");
  auto getArray = cast(type_getArray)GetProcAddress(dll, "getArray");
  uint n = 10;
  auto a = new double[](n);
  a[] = 0;
  foreach (i; 0..a.length) {
    setArray(a.ptr, i, cast(double)i);
    writefln("a[%d] = %.5f", i, getArray(a.ptr, i));
  }
  FreeLibrary(dll);
}


.exe ファイルのビルド

暗黙的リンクの場合は、implicit.bat を implicit.d と array.lib のあるフォルダに入れて実行します。また、明示的リンクの場合は、explicit.bat を explicit.d のあるフォルダに入れて実行します。エラーがなければ、caller.exe がビルドされます。

(暗黙的リンクの場合)

implicit.bat

set path=D:\dmd2\windows\bin
dmd -O -release caller.d array_h.d array.lib -ofcaller.exe

(明示的リンクの場合)

explicit.bat

set path=D:\dmd2\windows\bin
dmd -O -release explicit.d -ofcaller.exe


実行

暗黙的リンク、明示的リンク、いずれの場合も run.bat を caller.exe と array.dll のあるフォルダに入れて実行すると array.dll が呼び出されます。実行時に .lib ファイルは必要ありません。尚、D:\MinGW\bin にパスを通しているのは、実行時に libgcc_s_dw2-1.dll が必要になるからです。

run.bat

set path=D:\MinGW\bin
caller.exe
pause

以上の説明では、分かり易くするために個別にバッチファイルを作成していますが、実際には一連の処理を1つのバッチファイルで行っています。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中