想要在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  
今天看了近一天关于多线程的应用中,如何安全调用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