Pythonで動くDLLをVCでビルドする方法

きっかけは、
「ピストンコラージュのファイルをPythonで聴けるようにしたいなー」
と思ったことからでした。
(※ピストンコラージュの再生エンジンはDLLで提供されている)
 
ただ、DLLやら分っていないことが多く、
調査開始から3日間もかかってしまいましたがー。
 
そんなこんなで苦労して得た情報を惜しげもなく公開します。
 

よくあるエラー

kenmoがハマったエラーはこんな感じです。

fatal error LNK1104: コンパイラは、ファイル 'python23_d.lib' を開くことができません。

ビルドの構成が「Debug」だと、デバッグ用のlibを見にに行くためこのようなエラーが出るみたいです。
なのでビルドの構成を「Release」にすれば解決です。
 
あと、ビルドはできたものの動かないケース。

Traceback (most recent call last):
File "c:\work\vsproj\test\release\test.py", line 1, in ?
import test
ImportError: dynamic module does not define init function (inittest)

これにはいくつか原因があります。

  1. cppファイルをビルドする場合に初期化メソッドに「extern "C"」がない場合
  2. ヘッダファイルがない
  3. 初期化関数に「__declspec(dllexport)」がない

1は、Pythonは直接にはCのコードしか呼び出せないためです。
なので、初期化メソッドには「extern "C"」をつけなければいけません。
2は、DLLはヘッダファイルがないとダメみたいです。
原因は良く分かりませんがー。
3は、DLLの決まりごとみたいです。
 

環境

kenmoの環境は、

  • VC++2003
  • Python2.3

でした。
(他の環境でも頑張れば動くかも…)
 

手順

プロジェクトの作成
  1. 新しいプロジェクトの作成->Win32プロジェクト(ここでは「test」というプロジェクト名にします)
  2. アプリケーションウィザードで「アプリケーションの設定」を選び、アプリケーションの種類を「DLL」、追加のオプションで「空のプロジェクト」を選びます。
ビルドの設定
  1. ビルド->構成マネージャー->アクティブソリューション構成を「Release」に

これをやらないと「fatal error LNK1104: コンパイラは、ファイル 'python23_d.lib' を開くことができません。」というエラーが出ます。
(自分でPythonをビルドした人は問題ないのですが)

プロジェクトの設定
  1. プロジェクト->testのプロパティ、でプロパティページを開く
  2. C/C++->全般->追加のインクルードディレクトリに「C:\Python23\include」を設定(2.4を使っていれば「C:\Python24\include」)
  3. C/C++->コード生成->ランタイムライブラリを「マルチスレッド DLL (/MD)」に設定
  4. リンカ->全般->追加のライブラリディレクトリに「C:\Python23\libs」を設定(2.4を使っていれば「C:\Python24\libs」)

 
あと、出力ファイルの拡張子が「.dll」というのが気に入らなければ、

  • リンカ->全般->出力ファイルを「$(OutDir)/test.dll」から「$(OutDir)/test.pyd」に変更

です。
ただ、これは必須ではないですがー。

テスト用ソースコード

例えばこのようなtest.h/test.cppをプロジェクトに追加します。
<test.h>

#include "Python.h"

// これがないとダメみたい
#define DLLEXPORT __declspec(dllexport)

extern "C" DLLEXPORT void inittest();

 
<test.cpp>

#include "test.h"
// "Hello .."という文字列を返す関数
static PyObject* test_hello(PyObject* self)
{
	return Py_BuildValue("s", "Hello! This is test.");
}

// 関数テーブル
static PyMethodDef testmethods[] = {
	// メソッド"hello"の実体は「test_hello」で引数はなし
	{"hello", (PyCFunction)test_hello, METH_NOARGS},
	{NULL},
};

// 初期化メソッド(init+モジュール名でなければならない)
extern "C" void inittest()
{
	// "test"モジュールを初期化
	Py_InitModule("test", testmethods);
} 

 

ビルド

F7キーでビルドすると、Releaseフォルダに「test.dll」(もしくはtest.pyd)ができます。
 

Pythonからの呼び出し

Releaseフォルダにコマンドプロンプトを移動して、Pythonを実行し、

>>>import test
>>>test.hello()
Hello! This is test.

と出ればOKです。
 
これでPythonから、libBulletMLとかT'SoundSystemとかをいじれるようになります。
おおお、夢が膨らみますねー。
 

参考リンク

これらのページがなければ、なんともなりませんでした。
インターネットは素晴らしいなー、などと今更思いました。

追記

現在無料でMSのサイトから手に入る、
「Visual C++ 2005 Express Edition」
Windows Platform SDK
をインストールすることにより、同一の手順でビルドできることを確認しましたー。
(※インストール参考ページ「Visual C++ Express Editionを使ってみる(Windows Platform SDK編)」)