跳转至

pybind11原理分析,使用案例

104_Pybind11

2. 基本使用

2.1. 安装pybind11

一、pybind11是什么? pybind11是一个只有头文件的轻量级库,它在导出C++类型到Python的同时,也导出Python类型到C++中,其主要目的是建立现有C++代码的Python绑定。它与David Abrahams的Boost.Python库目的和语法相似,都是通过编译期内省来推断类型信息,以最大程度地降低传统扩展模块中的重复样板代码。

二、如何安装

Bash
pip install pybind11

三、pybind11的头文件路径的查询方法如下:

Bash
parallels@ubuntu-linux-20-04-desktop:/$ python3 -m pybind11 --includes
-I/usr/local/include/python3.8 -I/home/parallels/.local/lib/python3.8/site-packages/pybind11/include

四、pybind11头文件中的内容:

Bash
parallels@ubuntu-linux-20-04-desktop:/$ tree /home/parallels/.local/lib/python3.8/site-packages/pybind11/include
/home/parallels/.local/lib/python3.8/site-packages/pybind11/include
└── pybind11
    ├── attr.h
    ├── buffer_info.h
    ├── cast.h
    ├── chrono.h
    ├── common.h
    ├── complex.h
    ├── detail
       ├── class.h
       ├── common.h
       ├── descr.h
       ├── init.h
       ├── internals.h
       ├── type_caster_base.h
       └── typeid.h
    ├── eigen
       ├── common.h
       ├── matrix.h
       └── tensor.h
    ├── eigen.h
    ├── embed.h
    ├── eval.h
    ├── functional.h
    ├── gil.h
    ├── iostream.h
    ├── numpy.h
    ├── operators.h
    ├── options.h
    ├── pybind11.h
    ├── pytypes.h
    ├── stl
       └── filesystem.h
    ├── stl_bind.h
    ├── stl.h
    └── type_caster_pyobject_ptr.h

4 directories, 31 files

2.2. Python使用C++

一、编写绑定代码:example.cpp

C++
1
2
3
4
5
6
7
8
9
#include <pybind11/pybind11.h>

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(example, m) {
    m.def("add", &add, "A function which adds two numbers");
}

二、通过g++编译生成so 上面的源码使用到了头文件#include <pybind11/pybind11.h>,所以下面编译时需要指pybind11头文件所在的目录

Bash
# python3 -m pybind11 --includes即是获取pybind11头文件的绝对路径
g++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)

三、也可以通过python生成so,本质跟上述g++一样 编写编译脚本:

Python
from setuptools import setup, Extension


# pip install pybind11
# pybind11包中有include目录,用于编译出so
functions_module = Extension(
    name='example',
    sources=['example.cpp'],
    extra_compile_args=["-O3","-fPIC"],
    include_dirs=['/home/parallels/.local/lib/python3.8/site-packages/pybind11/include'],
)


# 效果等同于:g++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
setup(ext_modules=[functions_module])


# python setup.py build 可以看到产生了build文件夹,并且里面有生成的so动态库,用于python import使用c++
使用python执行编译:
Bash
# 可以看到产生了build文件夹,并且里面有生成的so动态库,用于python import使用c++
python setup.py build

# 查看build目录
parallels@ubuntu-linux-20-04-desktop:~/blogs/code/1_pybind11$ tree build/
build/
├── lib.linux-aarch64-3.8
   └── example.cpython-38-aarch64-linux-gnu.so
└── temp.linux-aarch64-3.8
    └── example.o

2 directories, 2 files

四、运行查看结果 运行脚本:

Python
1
2
3
4
5
6
7
8
9
# 导入so文件
import example

# 输出模块的文件地址
module_path = example.__file__
print(f"模块路径:{module_path}")

rst = example.add(1, 2)
print(f"运行结果:{rst}")
运行结果:
Bash
1
2
3
parallels@ubuntu-linux-20-04-desktop:~/blogs/code/1_pybind11$ python test_example.py 
模块路径:/home/parallels/blogs/code/1_pybind11/example.cpython-38-aarch64-linux-gnu.so
运行结果:3

2.3. C++使用Python

一、编写调用程序test_example.cpp

C++
#include <pybind11/embed.h>
#include <iostream>  

namespace py = pybind11;

int main() {

    // start the interpreter and keep it alive
    py::scoped_interpreter guard{}; 

    py::module t = py::module::import("example");
    py::object result = t.attr("add")(1, 2);
    std::cout << "Result is: " << result.cast<int>() << std::endl;

    return 0;
}

二、编译libpython3.8.so

Bash
cd /home/parallels/software
wget -c https://www.python.org/ftp/python/3.8.10/Python-3.8.10.tgz
tar -zxvf Python-3.8.10.tgz

# 制作python共享库,需要加上--enable-shared
./configure --enable-shared
sudo make
sudo make install


# 查看libpython3.8.so的路径
parallels@ubuntu-linux-20-04-desktop:~/software$ ls -lt /usr/local/lib/
total 40580
drwxr-xr-x  2 root root      4096 Oct  2 16:01 pkgconfig
drwxrwsr-x 36 root staff     4096 Oct  2 16:01 python3.8
lrwxrwxrwx  1 root root        19 Oct  2 16:01 libpython3.8.so -> libpython3.8.so.1.0
-rwxr-xr-x  1 root root  19907680 Oct  2 16:01 libpython3.8.so.1.0
-rwxr-xr-x  1 root root      8032 Oct  2 16:01 libpython3.so
drwxr-xr-x 36 root root     12288 Oct  2 15:59 python3.9
lrwxrwxrwx  1 root root        19 Oct  2 15:59 libpython3.9.so -> libpython3.9.so.1.0
-rwxr-xr-x  1 root root  21608808 Oct  2 15:59 libpython3.9.so.1.0
drwxrwsr-x  4 root staff     4096 Oct  1 19:04 python2.7

三、编译出可执行文件

Bash
1
2
3
4
g++ -std=c++11 $(python3 -m pybind11 --includes) test_example.cpp -Wl,-rpath,$(python3-config --prefix)/lib $(python3-config --prefix)/lib/libpython3.8.so -o test_example && ./test_example

# 输出结果:
Result is: 3

3. 参考

https://www.hbblog.cn/python%26C%2B%2B/python%E5%92%8CC%E7%9A%84%E4%BA%A4%E4%BA%92/#251 GitHub - pybind/pybind11: Seamless operability between C++11 and Python 00.%E4%BB%8B%E7%BB%8D.md


最后更新: 2024-04-14