利用boost.python库实现C++与Python的整合

3,728 阅读5分钟

boost.python 库提供了便捷的方法来将 C++ 中的函数、类等导入到 Python 中使用,我们只需要添加少量代码,就能 C++ 与 Python 的整合。

将 C++ 代码借助 boost.python 编译成 Python 模块之后,我们可以像导入标准模块那样,将该模块导入,在 Python 中使用 C++ 中的类来创建变量,并调用其方法。总之,我们可以很方便地在 Python 中调用 C++ 实现的功能,两者的结合,既提高了程序的运行效率,也提高了编程的效率。

boost.python 库的安装和使用的具体步骤如下。

开发环境:Windows 10、Visual Studio 2015
版本:boost.python 1.64.0
下载地址:www.boost.org/users/histo…

一、编译 boost.python 库

1、将下载下来的 boost.python 压缩包解压到 D 盘,得到 D:\boost_1_64_0

2、运行目录下的 bootstrap.bat 批处理文件,等待一会儿。
创建配置文件,用于静态库的编译,内容如下:

# Configure specific Python version.
 using python : 2.7
 : C:/Python27/python.exe
 : C:/Python27/include #directory that contains pyconfig.h
 : C:/Python27/libs    #directory that contains python27.lib
 : <toolset>msvc ;

这里用的是 Python2.7 版本,你需要将其中的 C:/Python27 改为你电脑中 Python 的安装路径,msvc 表示使用 Visual Studio 的工具箱。

3、打开命令行,通过 cd 命令将工作目录切换到 D:\boost_1_64_0 目录下,然后执行命令:

b2 toolset=msvc-14.0 --with-python variant=debug runtime-debugging=on link=static --user-config=user-config.jam stage

该命令会根据上面的配置文件,生成需要用到的静态库文件。

二、VS 工程配置

在 Visual Studio 中打开 工程属性 -> 配置属性 -> C/C++

在右侧的“附加包含目录”中添加 D:\boost_1_64_0;C:\Python27\include,这两个目录存放了需要的头文件。

打开 工程属性 -> 配置属性 -> 链接器 -> 常规

在右侧的“附加库目录”中添加 C:\Python27\libs;D:\boost_1_64_0\stage\lib,这两个目录存放链接阶段需要用到的库文件。

三、添加 C++ 代码

编译完 boost.python 库,并设置好VS工程项目之后,就可以对 C++ 代码进行封装了。

首先,我们需要在 C++ 代码添加一个宏定义,用于告诉 VS 我们要使用的是已经编译好的 boost.python 静态链接库,该宏定义需要放在所有代码之前(包括 #include 语句)。

#define BOOST_PYTHON_STATIC_LIB

例如有这么一个 C++ 函数:

char const* greet()
{
   return "hello, world";
}

我们需要添加如下代码:

#include <boost/python.hpp>
using namespace boost::python;

BOOST_PYTHON_MODULE(hello_ext)
{
    def("greet", greet);
}

注意,代码中的 hello_ext 是目标 Python 模块的名称,模块名需与文件名相对应。

该代码可以单独放在一个源文件中,通过 #include 来关联,也可以直接添加到已有的源代码中。如果源代码已经编译成 .lib 文件,这种情况下就可以在单独的源文件中写接口。

四、生成 dll 文件

打开 工程属性 -> 配置属性 -> 常规,在右侧的 项目默认值 -> 配置类型 中选择“动态库(.dll)”,这将使 VS 生成 dll 动态库文件,而非 exe 可执行文件。

选择 生成 -> 生成解决方案,生成 .dll 文件,将该文件复制到 Python 项目目录下,将后缀改为 .pyd,得到 hello_ext.pyd 文件,该文件即为 Python 的库文件,可直接通过 import 导入。

五、在 Python 中调用

我们可以像调用标准 Python 库那样调用我们自己生成的模块:

>>> import hello_ext
>>> print hello_ext.greet()
hello, world

附:类包装器

上面所给的例子是函数包装器的示例,如果要导出的是 C++ 中的类,则需要使用类包装器来封装接口。

例如我们要导出如下的 C++ 类给 Python 使用:

class World
{
    void set(std::string msg) { this->msg = msg; }
    std::string greet() { return msg; }
    std::string msg;
};

我们需要在原有代码中添加以下包装器,从而将接口提供给 Python:

#include <boost/python.hpp>
using namespace boost::python;

BOOST_PYTHON_MODULE(hello)
{
    class_<World>("World")
        .def("greet", &World::greet)
        .def("set", &World::set)
    ;
}

然后按照上述的步骤生成 .pyd 模块文件,在 Python 中调用:

>>> import hello
>>> planet = hello.World()
>>> planet.set('howdy')
>>> planet.greet()
'howdy'

总结

boost.python 库还是非常方便的,正常情况下,我们无需改变原有的代码就能将数据结构和函数导出到 Python 中。比起自己使用 python.h 库来实现 C++ 与 Python 的整合,不仅仅是一般的高效。最让我感到惊喜的是,boost.python 库还提供了诸如 boost::python::list 的数据类型,我们可以直接在 C++ 中像在 Python 中使用列表那样,将不同的数据类型添加到一个 list 中。我们也可以借助 list 类型,方便地将多个数据以列表的形式传递给 Python。

上面的步骤中,最容易出现问题的是“生成 dll 文件”这一步,可能会有库文件找不到的情况,或者符号加载失败等情况。如果遇到这些问题,请检查是否正确编译了 boost.python 库、是否在工程属性中的添加了正确的头文件路径和附加库路径、安装的 python 版本的位数与VS配置的位数是否一致等等。如果实在解决不了,可以通过 Google 来搜索解决方案,StackOverflow 上有许多关于这些问题的解决办法,也欢迎给我留言,针对遇到的问题进行交流讨论。

更多关于 boost.python 的使用说明,可以参考:Boost.Python Tutorial - 1.64.0

版权声明

作者:Wray Zheng
原文链接: www.codebelief.com/article/201…