C言語アプリケーションに Pythonを組み込む
ネットを ぼ〜っと回っていると、↓こんなのを見つけた。
- Embedding Python in Your C Programs | Linux Journal
http://www.linuxjournal.com/article/8497
そういや、似たようなのを公式ドキュメントでも見たなぁ、と思い出す。あった、あった。
- Python インタプリタの拡張と埋め込み
http://www.python.jp/doc/nightly/ext/ext.html - Python/C API リファレンスマニュアル
http://www.python.jp/doc/release/api/api.html
国内で、参考になる資料は無いかな?と思って ぐぐると MLのが見つかった。
- [Python-ml-jp 325] get class instance from C++ extension?
http://www.python.jp/pipermail/python-ml-jp/2001-June/000324.html
ビルド方法
先のコードを参考に、コードを書いてみる。
#include <stdio.h> #include <Python.h> int main(void) { Py_Initialize(); PyRun_SimpleString("print 'hello python'"); Py_Finalize(); return 0; }
早速ビルドしてみよう。まず、Python 2.4 for Cygwinから。
$ gcc test.cpp -I/usr/include/python2.4 -L/usr/lib/python2.4/config -lpython2.4 $ ls a.exe test.cpp $ ./a.exe hello python
結構簡単ですな。
$ call "C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\vcvars32.bat" $ "C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\vsvars32.bat" Setting environment for using Microsoft Visual Studio .NET 2003 tools. (If you have another version of Visual Studio or Visual C++ installed and wish to use its tools from the command line, run vcvars32.bat for that version.) $ cl test.cpp /GX /IC:\tool2\Python24\include C:\tool2\Python24\libs\python24.lib Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86 Copyright (C) Microsoft Corporation 1984-2002. All rights reserved. test.cpp Microsoft (R) Incremental Linker Version 7.10.3077 Copyright (C) Microsoft Corporation. All rights reserved. /out:test.exe test.obj C:\tool2\Python24\libs\python24.lib $ test hello python
おぉ〜、簡単に動いちゃうよ。
Python 2.4 for Windowsで、VC.NET 2003を使っているのは、Python 2.4のトップディレクトリにある ランタイムライブラリが、msvcr71.dll と msvcp71.dll の、VC.NET 2003のランタイムライブラリだから。
多分、VS2005 Expressでもビルドできると思う。
VC++6.0はどうかな?下位互換性あったっけ?何かオプション付けてライブラリをビルドしてないとダメじゃなかったけな?
実行は、Dependency Walkerに喰わせた所、msvcr71.dllが最低限必要っぽい。
Python & C++ posted from フォト蔵
pythonからアプリ内のC言語関数を呼び出す
C言語アプリケーションとPythonの組み合わせって、アプリケーションのマクロ言語にPythonを使うケースを想定してんだと思うんですよ。
つか、自分がC言語アプリとPythonの組み合わせって言われたら、そんな用途しか思いつかないし。
となると、C言語関数を Pythonから呼び出せないと片手落ちだよね?
早速試してみる。資料としては、「5.4 埋め込まれた Python の拡張」が参考になると思う。
#include <stdio.h> #include <Python.h> static int numargs=0; /* アプリケーションのコマンドライン引数の個数を返す */ static PyObject* emb_numargs(PyObject *self, PyObject *args) { if(!PyArg_ParseTuple(args, ":numargs")) return NULL; return Py_BuildValue("i", numargs); } static PyMethodDef EmbMethods[] = { {"numargs", emb_numargs, METH_VARARGS, "Return the number of arguments received by the process."}, {NULL, NULL, 0, NULL} }; int main(int argc, char* argv[]) { Py_Initialize(); numargs = argc; Py_InitModule("emb", EmbMethods); static const char* CODES = "import emb\n" "print 'Number of arguments', emb.numargs()\n" ; PyRun_SimpleString(CODES); Py_Finalize(); return 0; }
$ gcc test.cpp -I/usr/include/python2.4 -L/usr/lib/python2.4/config -lpython2.4 $ ./a.exe 1 2 3 4 5 6 Number of arguments 7
$ cl test.cpp /GX /IC:\tool2\Python24\include C:\tool2\Python24\libs\python24.lib Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86 Copyright (C) Microsoft Corporation 1984-2002. All rights reserved. test.cpp Microsoft (R) Incremental Linker Version 7.10.3077 Copyright (C) Microsoft Corporation. All rights reserved. /out:test.exe test.obj C:\tool2\Python24\libs\python24.lib $ test 1 2 3 4 5 6 Number of arguments 7
ほんま、簡単ですなぁ。
ちなみに、CODESん所に、"help(emb)"を突っ込むと、↓こんなのが表示される。
Help on module emb: NAME emb FILE (built-in) FUNCTIONS numargs(...) Return the number of arguments received by the process.
なるほど、なるほど。
boost.pythonで簡単に記述する
一応、C言語アプリとPythonのコラボが実現できた訳なんだけど、C言語側のコードが煩雑なんですよね。
例えば、「5.3 純粋な埋め込み」に示されている、Pythonコードを呼び出す C言語コード。えらい長いじゃん?
見ると、オブジェクトの生成と破棄、リファレンスカウンタの管理と異常処理に手間喰っているみたいなんですわ。
…そういうのって、C++使えば解消しますよね?(そういうクラスライブラリを用意すれば、だけど)
gcc / VC++の両方共、C++ が使えるんだから、そういう面倒な処理は、言語&ライブラリ(道具)に やらせるべきだと思うんですよ。別の新しい事に挑戦してみませんか?旦那。
2011/09/11 追記:表現がキツかったようですので、勝手ながら手直しさせてもらいました。
という訳で、調べてみると 我らが boostに 解決してくれる便利なライブラリがありました。
これを元に、コードを書いてみませぅ。
#include <stdio.h> #include <Python.h> #include <boost/python.hpp> using namespace boost::python; int main(int argc, char* argv[]) { Py_Initialize(); handle<> main_module(borrowed( PyImport_AddModule("__main__") )); handle<> main_namespace(borrowed( PyModule_GetDict(main_module.get()) )); static const char* CODES = "print 'hello boost::python'\n" ; handle<>( PyRun_String(CODES, Py_file_input, main_namespace.get(), main_namespace.get()) ); Py_Finalize(); return 0; }
早速コンパイル。Python 2.4 for Windowsね。
$ cl test.cpp /GX /IC:\tool2\Python24\include C:\tool2\Python24\libs\python24.lib /IC:\Boost\include\boost-1_33 C:\Boost\lib\boost_python-vc71-mt.lib Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86 Copyright (C) Microsoft Corporation 1984-2002. All rights reserved. test.cpp Microsoft (R) Incremental Linker Version 7.10.3077 Copyright (C) Microsoft Corporation. All rights reserved. /out:test.exe test.obj C:\tool2\Python24\libs\python24.lib C:\Boost\lib\boost_python-vc71-mt.lib $ test hello boost::python
なお、boost.pythonは、ヘッダをインクルードするだけじゃダメで、bjam使ってライブラリをビルドする必要があります。
後、実行パスに、boost_python-vc71-mt-1_33.dll を置いておく必要があるよ。(静的リンクすればDLLを組み込む必要ないけどね)
(Cygwin版なんだけど、セットアップパッケージに boost と boost-devel があるんだけど、これ入れるだけじゃ boost_python が入ってくれない。何か設定悪いのかな?)
boost.pythonで、アプリ内部の関数を呼び出す
更に、アプリ内部の関数を呼び出してみよう。
#include <stdio.h> #include <Python.h> #include <boost/python.hpp> using namespace boost::python; class HelloCls { public: HelloCls(){ puts("ctor HelloCls"); } char const* greet(){ return "hello python"; } }; BOOST_PYTHON_MODULE(Hello) { class_<HelloCls>("HelloCls") .def("greet", &HelloCls::greet) ; } int main(int argc, char* argv[]) { if(PyImport_AppendInittab("Hello", initHello) == -1) puts("helloモジュールのセットアップに失敗"); Py_Initialize(); handle<> main_module(borrowed( PyImport_AddModule("__main__") )); handle<> main_namespace(borrowed( PyModule_GetDict(main_module.get()) )); static const char* CODES = "import Hello\n" "o = Hello.HelloCls()\n" "print o.greet()\n" ; handle<>( PyRun_String(CODES, Py_file_input, main_namespace.get(), main_namespace.get()) ); Py_Finalize(); return 0; }
早速実行。
$ cl test.cpp /GX /IC:\tool2\Python24\include C:\tool2\Python24\libs\python24.lib /IC:\Boost\include\boost-1_33 C:\Boost\lib\boost_python-vc71-mt.lib Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86 Copyright (C) Microsoft Corporation 1984-2002. All rights reserved. test.cpp Microsoft (R) Incremental Linker Version 7.10.3077 Copyright (C) Microsoft Corporation. All rights reserved. /out:test.exe test.obj C:\tool2\Python24\libs\python24.lib C:\Boost\lib\boost_python-vc71-mt.lib $ test ctor HelloCls hello python
お〜いえ〜。
まぁ、このように、boost.pythonを使えば、PythonとC++の境界を適当にラップしてくれるので非常に便利。
ところで、最初、グローバルな関数を BOOST_PYTHON_MODULE に突っ込んでいたのだけど、うまくいかなかったので、色々ぐぐるってみた。
- [c++/Python] Passer une instance c++ a un script python - C++ - Programmation - FORUM HardWare.fr
http://forum.hardware.fr/hardwarefr/Programmation/Python-Passer-instance-script-python-sujet-77782-1.htm - RE: [C++-sig] Re: Using .add_property with make_getter. :: ASPN Mail Archive :: cpp-sig
http://aspn.activestate.com/ASPN/Mail/Message/cpp-sig/1683261 - embed_test.cpp
http://www-eleves-isia.cma.fr/documentation/BoostDoc/boost_1_29_0/libs/python/test/submod_subclass_api.cpp - [C++-sig] Exception second time loaded
http://mail.python.org/pipermail/c++-sig/2003-June/004449.html
国内では、サンプルコードは見つからなかった。
唯一、id:eto3dcgさんが、リンク集を紹介していた。
- eto3dcg - Boost.Pythonを使ってPythonとC,C++を連携させる
http://d.hatena.ne.jp/we_memo/20051222/p1