Boost.Python 是 Boost 中的一个组件, 使用它能够大大简化用 C++ 为 Python 写扩展库的步骤,提高开发效率, 虽然目前它对 Python 嵌入 C++ 的支持还不是很多, 但也能提供很大方便。另外, 华宇煜也编写了一份关于 Boost.Python 简明教程。 1 Boost 安装简介在正式开始使用 Boost.Python 之前, 我们必须先编译 Boost。 首先到 Boost 的官方站点 下载 Boost 的源码包, 把它们解压到你喜欢的目录,为编译做好准备。 另外, 在正式安装 Boost.Python 之前, 我们必须先正确安装 Python。 1.1 Linux 下的编译首先切换到 Boost 源码所在的路径, 执行 ./configure --with-python=/usr/bin/python --with-python-version=2.4 --with-python-root=/usr 然后, 和绝大部分 Linux 程序一行, 执行 1.2 使用 MinGW + MSys 在 Windows 下的编译首先需要编译的是 Boost 的编译工具 bjam, 直接到 bjam 所在目录下, 即 Boost 源码包所在目录下的 接下来, 切换到 Boost 源码所在路径, 执行 bjam 进行编译。 我们需要提供关于 Python 的一些参数, 变量 PYTHON_ROOT 指向 Python 运行环境所在的目录,变量 PYTHON_VERSION 的值为 Python 的版本号, 如果你的 Python 安装路径与滇狐不同,请将相应的变量修改为你机器上相应的路径, 编译命令行如下: bjam.exe "-sTOOLS=mingw" "-sPYTHON_ROOT=E:\Python" "-sPYTHON_VERSION=2.4" 编译完毕后, 你将会在你的 2 使用 Boost.Python 嵌入 Python 模块到 C++Boost.Python 目前并没有提供完整的将 Python 模块嵌入到 C++ 的包装库,因此许多工作我们还必须通过 Python C API 来进行。 但是, 利用 Boost.Python 中提供的一些模块, 能够给我们的工作带来极大便利。 2.1 修改模块加载路径,装入 Python 模块与任何一个其它 Python 嵌入 C/C++ 的程序一样, 我们需要在第一条 接下来, 我们便可以开始准备装入 Python 模块了。 为了让 Python 解释器能够正确地找到 Python 模块所在的位置, 我们需要将 Python 模块所在的路径添加到模块搜索路径中,添加搜索路径的 Python 语句如下: import sys if not '/module/path' in sys.path: sys.path.append('/module/path') 我们使用 Python C API 执行类似的语句, 就能将模块的搜索路径添加到 Python 解释器中。 添加了搜索路径后, 就可以通过 #include <boost/python.hpp> ... boost::python::handle<>* _module; // Module handle. std::string path; // Path of the Python module. std::string module; // Module name. ... try { PyRun_SimpleString("import sys"); PyRun_SimpleString((std::string("if not '") + path + "' in sys.path: sys.path.append('" + path + "')").c_str()); _module = new boost::python::handle<>( PyImport_ImportModule((char *) module)); ... } catch (...) { PyErr_Print(); PyErr_Clear(); delete _module; _module = NULL; return false; } ... 需要注意的是, 通过 Python C API 加载的 Python 解释器并没有把当前路径列入默认的搜索路径中。因此, 即使你的 Python 模块就存放在当前路径, 你也必须使用上面的代码将当前路径添加到搜索路径中之后,才能通过 当 Python 模块使用完毕或程序结束时, 请使用 2.2 调用 Python 函数导入了 Python 模块之后, 调用 Python 函数就非常容易了。 Boost.Python 里封装了一个非常好用的模板函数 boost::python::call_method<返回值类型>(模块指针, "Python 函数名", 参数 1, 参数 2, ...); 模块指针可以通过我们前面得到的 ... bool result; std::string config_file; ... try { return boost::python::call_method<bool>(_module->get(), "initialize", config_file); } catch (...) { PyErr_Print(); PyErr_Clear(); ... } ... 2.3 使用 Python 类对象使用 Python C API 调用 Python 函数和调用 Python 类对象是没有太大区别的,我们只需要调用类的构造方法, 得到一个类对象, 然后把该类的指针看做模块指针,按照前面调用普通函数的方法调用类成员方法就可以了。 例如, 下列代码从 ... boost::python::handle<> _yukisession; ... // Retrieve the module handle and namespace handle. boost::python::object main_module(*_module); boost::python::object main_namespace = main_module.attr("__dict__"); // Call the method and get the object handle. _yukisession = boost::python::handle<>((PyRun_String( "YukiSession()", Py_eval_input, main_namespace.ptr(), main_namespace.ptr()))); ... // Compose a list. boost::python::list param; param.append(boost::python::str(_addr.get_host_addr())); param.append(boost::python::str()); // Call the method and retrieve the result. // Method is equivalent to: // "bool __thiscall YukiSession::on_welcome(list param);" result = boost::python::call_method<bool> (_yukisession.get(), "on_welcome", param); // Extract an item from a list. str = boost::python::call_method<std::string> (param.ptr(), "__getitem__", 1); ... 3 在嵌入的 Python 模块中调用 C++ 程序通过动态链接库的方式使用 Boost.Python 导出 C++ 模块到 Python 程序与在 C++ 可执行程序中导出模块给嵌入的 Python 解释器, 编写程序的方式几乎是完全相同的。因此这里只简单介绍导出普通函数的方法, 想详细了解更多高级功能, 如导出 C++ 类、 导出可被 Python 重载的类等, 可以参看华宇煜的 Boost.Python 简明教程或官方 Boost.Python 文档。 3.1 导出 C++ 函数首先使用 const char *yukigettext(const char *id); BOOST_PYTHON_MODULE(yuki) { boost::python::def("gettext", yukigettext, boost::python::args("id"), "Translate message."); } 3.2 为 Python 初始化 C++ 模块使用 ... Py_Initialize(); inityuki(); ... 3.3 在 Python 模块中调用 C++ 模块此时我们在 Python 模块中只需要像普通的 Python 模块那样, 将导入的 C++ 模块用 import yuki ... print yuki.gettext("This is a test!") |
|