C/C++で作成したDLLのテストをPythonで行う

C/C++でDLLを作成した後、そのDLLの動作確認を行うには別途プログラムが必要になってきますが*1、それにまたC/C++を用いるのはあまり効率が宜しくないと前から思っていて、スクリプトを使ってもっとお手軽にしたいと考えていたのを少し実践してみました。

なぜC/C++でテストプログラムを作成するのが効率が悪いのかといえば、C/C++はコンパイル言語だからです。コードを書いて実行する前に、当然のことながら毎回コンパイルしてリンクして...といった作業が必要になりますが、ちょっと関数のパラメータを書き換えたいというだけの時にもこの作業を通さなければならないのは結構苦痛です。まあパラメータを標準入出力なりGUIなりで入力できるようにするという手もありますが、あまり凝ってしまうとテストプログラムの作成の方に時間を取られてしまってそれはそれで問題です。

そこで、Pythonを用いてDLLのテストコードを書くことができれば色々手間が省けて作業効率も上がるのではないかな、ということで。Pythonにしたのは特に意味は無く、気分です。

Pythonは標準モジュールがとても豊富で、DLLを取り扱えるモジュールも当たり前のように存在しています。以下のctypesというモジュールです。

ドキュメントもしっかりしていて必要なことは全部書いてあると思うのですが、せっかくなのでちょっと書いてみます。

まずDLLのロードを行うためのオブジェクトとして cdll と windll の2種類が用意されています。どちらを使うかは使用したい関数(DLL)の呼び出し規約によって異なってくるのですが、とりあえずcdeclだったらcdll、stdcallだったらwindllを使用するようです。今回はwindllを使いました。

lib = windll.LoadLibrary("hoge.dll");

とするとlibにDLLをロードしてできたオブジェクトが格納されます。LoadLibraryはWin32APIのそれと同じ感覚で使ってしまって良いと思います。

これだけやれば、あとは簡単にhoge.dllからエクスポートされた関数を呼び出すことができます。例えば以下のような関数がエクスポートされているとします。

int __stdcall Add(int x, int y) {
  return x + y;
}

これを呼び出すには lib.Add(1,2) とします。メソッド呼び出しと同じ形で呼べてしまうのですね。

ということでhoge.dllをテストするには以下のようなコードになります。って、繋げただけですが。

from ctypes import *
lib = windll.LoadLibrary("hoge.dll");
if (lib.Add(1,2) != 3):
  print "error!"

関数の呼び出し自体、C/C++で書くよりもずっと簡単になっています。これだけでもずいぶん違ってきそうです。

また、戻り値の確認を自前で行っていますが、ここはunittestモジュールを使うともっとスマートになると思いますが、今回は端折っています。

そういえば、少し前に両手を使って仕事をするという話を読みましたが、こういう使い方も当てはまるのでしょうか。

*1:直接テストコード書いてEXEとしてビルドするという手もありますが