pybindgenでC++クラスを呼び出す
いろいろカンでやったとこもあるので間違っているところがあればツッコミお願いします。
前提とする環境
- Windows XP 32bit
- cygwin
- VisualC++ 2008 Express Edition (gccxmlは古いので2010に対応していない)
- Python2.7
gccxmlのインストール
http://sourceforge.net/projects/pygccxml/files/gccxml-setup/gccxml-7-JAN-2009-rev1.127/
gccxml-0.9.0-win32-x86-rev1.127.exe をダウンロードしてインストール
$ cd "%PROGRAMFILES%\gccxml 0.9\bin" $ ./gccxml_vcconfig.bat
これでVisualC++のヘッダをgccxml以下へコピーされる これインストーラで実行されているっぽい --2012.03.09 追記
環境変数に以下を追加
GCCXML_COMPILER=msvc9 # もしくはVC++2005ならmsvc8 GCCXML_FLAGS=-I. GCCXML_DIR=%PROGRAMFILES%\gccxml 0.9\bin PATH=%PATH%;%GCCXML_DIR% # gccxml.exeを呼び出せるようにパスを通しておく
pygccxmlのインストール
http://sourceforge.net/projects/pygccxml/files/pygccxml/pygccxml-1.0/
pygccxml-1.0.0.zipをダウンロード
$ pip install pygccxml-1.0.0.zip $ pydoc pygccxml Help on package pygccxml: NAME pygccxml - Python GCC-XML front end. FILE c:\python27\lib\site-packages\pygccxml\__init__.py DESCRIPTION This package provides functionality to extract and inspect declarations from C/C++ header files. This is accomplished by invoking the external tool U{gccxml<http://www.gccxml.org/>} which parses a header file and dumps the declarations as a ... 中略 .... VERSION 1.0.0
pybindgenのインストール
http://code.google.com/p/pybindgen/downloads/detail?name=pybindgen-0.15.0.zip
pybindgen-0.15.0.zipをダウンロード
$ unzip pybindgen-0.15.0.zip $ cd pybindgen-0.15.0 $ PYTHON=C:/Python27/python.exe ./waf configure --prefix C:/Python27 $ ./waf install $ cd / # pybindgenフォルダの中にいるとそっちをimportしてしまうため $ pydoc pybindgen Help on package pybindgen: NAME pybindgen FILE c:\python27\lib\site-packages\pybindgen\__init__.py PACKAGE CONTENTS container converter_functions cppattribute cppclass ... 以下略 .... $ pydoc pybindgen.version Help on module pybindgen.version in pybindgen: NAME pybindgen.version FILE c:\python27\lib\site-packages\pybindgen\version.py DATA __version__ = [0, 15, 0] VERSION [0, 15, 0]
補足 --2012.02.23
x64環境でVisualStudio2008/2010が両方インストールされた環境下だと waf configure がエラーになるみたい。
pybindgen-0.15.0/waf-1.5.9-(略)/wafadmin/Tools/msvc.py
↑ここでMSVC_TARGETSをちゃんと渡せればx86指定できそうなんだけども、
やり方が見つけられなかったので
- all_msvc_platforms=[('x64','amd64'),('x86','x86'),('ia64','ia64'),('x86_amd64','amd64'),('x86_ia64','ia64')] + all_msvc_platforms=[('x86','x86')]
ぶしっとx86オンリーに修正してリトライ。
C++コードの作成
// hum.h #pragma once class Human { public: Human(); virtual ~Human(); void sayHello(const char* message); };
// hum.cpp #include "hum.h" #include <iostream> using namespace std; Human::Human() { cout << "Human.ctor" << endl; } Human::~Human() { cout << "Human.dtor" << endl; } void Human::sayHello(const char* message) { cout << "Human: hello, " << message << "!!" << endl; }
pybindgenでPythonモジュールを生成
// modgen.py import sys import pybindgen from pybindgen.gccxmlparser import ModuleParser name = sys.argv[1] headers = sys.argv[2:] parser = ModuleParser(name, '::') module = parser.parse(headers) for s in headers: module.add_include('"%s"' % s) module.generate(sys.stdout)
$ python modgen.py hum hum.h > hum_mod.cpp INFO Parsing source file "hum.h" ... INFO gccxml cmd: ""C:\Program Files\gccxml 0.9\bin\gccxml.exe" -I"." "hum.h" -fxml="c:\temp\tmpgm8k3y.xml"" INFO GCCXML version - 0.9
Pythonモジュールのコンパイル
// setup.py from distutils.core import setup, Extension setup( ext_modules = [ Extension( 'hum', ['hum.cpp', 'hum_mod.cpp'], extra_compile_args=['/EHsc']), ])
$ python setup.py build running build running build_ext building 'hum' extension creating build creating build\temp.win32-2.7 creating build\temp.win32-2.7\Release C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN\cl.exe /c /nologo /Ox /MD /W3 /GS- /DNDEBUG -IC:\Python27\include -IC:\Python27\PC /Tphum.cpp /Fobuild\temp.win32-2.7\Release\hum.obj /EHsc hum.cpp C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN\cl.exe /c /nologo /Ox /MD /W3 /GS- /DNDEBUG -IC:\Python27\include -IC:\Python27\PC /Tphum_mod.cpp /Fobuild\temp.win32-2.7\Release\hum_mod.obj /EHsc hum_mod.cpp creating build\lib.win32-2.7 C:\Program Files\Microsoft Visual Studio 9.0\VC\BIN\link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:C:\Python27\libs /LIBPATH:C:\Python27\PCbuild /EXPORT:inithum build\temp.win32-2.7\Release\hum.obj build\temp.win32-2.7\Release\hum_mod.obj /OUT:build\lib.win32-2.7\hum.pyd /IMPLIB:build\temp.win32-2.7\Release\hum.lib /MANIFESTFILE:build\temp.win32-2.7\Release\hum.pyd.manifest ライブラリ build\temp.win32-2.7\Release\hum.lib とオブジェクト build\temp.win32-2.7\Release\hum.exp を作成中 C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\mt.exe -nologo -manifest build\temp.win32-2.7\Release\hum.pyd.manifest -outputresource:build\lib.win32-2.7\hum.pyd;2 $ cp -f build/lib.win32-2.7/hum.pyd hum.pyd
$ pydoc hum Help on module hum: NAME hum FILE c:\work\test\hum.pyd SUBMODULES std CLASSES __builtin__.object Human class Human(__builtin__.object) | Methods defined here: | | __copy__(...) | | __eq__(...) | x.__eq__(y) <==> x==y | | __ge__(...) | x.__ge__(y) <==> x>=y | | __gt__(...) | x.__gt__(y) <==> x>y | | __init__(...) | x.__init__(...) initializes x; see help(type(x)) for signature | | __le__(...) | x.__le__(y) <==> x<=y | | __lt__(...) | x.__lt__(y) <==> x<y | | __ne__(...) | x.__ne__(y) <==> x!=y | | sayHello(...) | | ---------------------------------------------------------------------- | Data and other attributes defined here: | | __new__ = <built-in method __new__ of type object> | T.__new__(S, ...) -> a new object with type S, a subtype of T
Humanが使えるようになっているっぽいですね。
あれ?stdって何だろう?
テスト
$ python >>> from hum import Human >>> human = Human() Human.ctor >>> human.sayHello('hoge') Human: hello, hoge!! >>> del human Human.dtor
動いた!!
gccxmlを使って完全に自動化しているので、もしかしたら何か対応できていないことなどクセがあるのかも。
これは楽ちんだ。しばらく使ってみようと思います。
オマケ
// Makefile .PHONY: test clean test: hum.pyd python test.py hum.pyd: build/lib.win32-2.7/hum.pyd cp -f $< $@ build/lib.win32-2.7/hum.pyd: hum_mod.cpp *.cpp *.h python setup.py build hum_mod.cpp: *.h python modgen.py hum $^ > $@ clean: $(RM) -r build/ *.pyd *_mod.cpp
$ make