想要在c++ 中嵌入script 代码, 除了自己写脚本引擎外, lua, python 都可以在c++ 中使用, 另外 MonoBind, AngelScript library 都是一些c++ script library, 可以嵌入到c++ 中使用 .
今天在c++ 中试着嵌入 python 代码 (示例代码在 Python-2.5.2\Demo\embed\ 下)
#include <Python.h>
int main(int argc, char *argv[])
{
// Py_NoSiteFlag = 1;
// Py_SetPythonHome("D:\\usr\\Python"); // PYTHONHOME
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print 'Today is',ctime(time())\n");
Py_Finalize();
return 0;
}
在运行时可能会产生类似 'import site' failed; use -v for traceback 的错误, 原因是python 在import module 的时候的路径问题. 有3种方法可以解决(以前通过设置环境变量 PYTHONPATH 好像在2.5 已经无效了).
0. 取消注释 Py_NoSiteFlag = 1;
这个只是取消import site , 当然如果在代码中要import 啥的话, 还是会出现错误的.
a. 设置环境变量 PYTHONHOME = D:\usr\Python
b. 在调用 Py_Initialize 之前调用函数
Py_SetPythonHome("D:\\usr\\Python"); // 参数是python 的安装目录
2. 其他一些有用的资源
Python/C API Reference Manual (API 参考) , Extending and Embedding the Python Interpreter (扩展及嵌入Python解释器, 主要说明了如何扩展Python, 给Python 写扩展, 其中 5. Embedding Python in Another Application 一章讲述了在C++中嵌入/调用Python 代码 )
使用C/C++扩展Python 对文 Extending and Embedding the Python Interpreter 作了精简, 很不错的一篇文章, 但是跳过了一些基础 .
Building Hybrid Systems with Boost.Python 介绍了使用boost.python 方便python 插件开发, python绑定c++程序 是其中文版本.
Embedding Python in Multi-Threaded C/C++ Applications 讲了c++在多线程环境如何使用Python , 文 C++多线程中调用python api函数 提供了一个多线程的封装.
SCXX - A Simple Python/C++ API
http://davidf.sjsoft.com/mirrors/mcmillan-inc/scxx.html
C++扩展和嵌入Python应用 (介绍了一些Python/C API 函数, 以及ext 例子, 一般般)
http://hi.baidu.com/yunsweet/blog/item/20b08aeebaa2b1282cf534c7.html
3. Python 多线程的使用
zz http://blog.csdn.net/liguangyi/archive/2007/06/20/1659697.aspx
今天看了近一天关于多线程的应用中,如何安全调用python方面的资料,开始的时候看的简直头大如斗,被python语言的全局锁(Global Interpreter Lock)、线程状态(Thread State )等都有点绕晕了,后来经过各方面文章和帮助文档的相互参考,发现对于2.4/2.5版本,提供了PyGILState_Ensure, PyGILState_Release,哎,这下可方便大发了。
一、首先定义一个封装类,主要是保证PyGILState_Ensure, PyGILState_Release配对使用,而且这个类是可以嵌套使用的。
#include <python.h>
class PyThreadStateLock
{
public:
PyThreadStateLock(void)
{
state = PyGILState_Ensure( );
}
~PyThreadStateLock(void)
{
PyGILState_Release( state );
}
private:
PyGILState_STATE state;
};
二、在主线程中,这样处理
// 初始化
Py_Initialize();
// 初始化线程支持
PyEval_InitThreads();
// 启动子线程前执行,为了释放PyEval_InitThreads获得的全局锁,否则子线程可能无法获取到全局锁。
PyEval_ReleaseThread(PyThreadState_Get());
// 其他的处理,如启动子线程等
......
// 保证子线程调用都结束后
PyGILState_Ensure();
Py_Finalize();
// 之后不能再调用任何python的API
三、在主线程,或者子线程中,调用python本身函数的都采用如下处理
{
class PyThreadStateLock PyThreadLock;
// 调用python的API函数处理
......
}
呵呵,看这样是否非常简单了。
另外还有两个和全局锁有关的宏,Py_BEGIN_ALLOW_THREADS 和 Py_END_ALLOW_THREADS。这两个宏是为了在较长时间的C函数调用前,临时释放全局锁,完成后重新获取全局锁,以避免阻塞其他python的线程继续运行。这两个宏可以这样调用
{
class PyThreadStateLock PyThreadLock;
// 调用python的API函数处理
......
Py_BEGIN_ALLOW_THREADS
// 调用需要长时间的C函数
......
Py_END_ALLOW_THREADS
// 调用python的API函数处理
......
}
4. 可能的错误及解决
a. 在vs 200x 下 debug 模式出现链接问题
extmodule.obj : error LNK2019: unresolved external symbol __imp___Py_Dealloc referenced in function _PySwigObject_format
extmodule.obj : error LNK2019: unresolved external symbol __imp___Py_NegativeRefcount referenced in function _PySwigObject_format
extmodule.obj : error LNK2001: unresolved external symbol __imp___Py_RefTotal
extmodule.obj : error LNK2019: unresolved external symbol __imp___PyObject_DebugFree referenced in function _PySwigObject_dealloc
extmodule.obj : error LNK2019: unresolved external symbol __imp___PyObject_DebugMalloc referenced in function _PySwigObject_New
extmodule.obj : error LNK2019: unresolved external symbol __imp__Py_InitModule4TraceRefs referenced in function _init_extmodule
主要是因为 Py_DEBUG/Py_TRACE_REFS 引起, 修改 Python\include 下的 pyconfig.h, object.h 两个文件就行了 ... 详见 http://www.nabble.com/link-error-in-debug-mode-td3126668.html