Pybind Analyze

作用在于将 C++ 实现的函数封装为 module,供 python 代码调用。

想要理解 pybind 的封装逻辑,还需要理解 python 是如何使用 pybind 生成的内容的,即关键点在于 python 的 import 机制的基本原理。

Python 的模块加载机制

  1. Python 源文件(.py),Python 解释器会加载并执行该文件

  2. 扩展模块(例如 .so、.dll 或 .dylib 文件),Python 解释器会将其当作动态库来加载,并通过相应的 Python C API 或 Python/C++ 接口进行交互。

pybind 对应的就是第二种模式

pybind “hello-world”

  1. 编写供 Python 程序调用的 C++ 代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <pybind11/pybind11.h>

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

PYBIND11_MODULE(example, m) {
	m.doc() = "pybind11 example plugin"; // optional module docstring
	m.def("add", &add, "A function which adds two numbers");
}
  1. C++ 编译为动态库
1
c++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) example.cpp -o example$(python3-config --extension-suffix)
  • $(python3 -m pybind11 --includes): 负责获取 pybind 所需要使用的头文件
  • $(python3-config --extension-suffix): 负责获取文件后缀 .cpython-39-x86_64-linux-gnu.so
  1. 检查使用效果
1
2
3
4
5
6
7
>>> import example

>>> example
<module 'example' from '/work/gaohy/experiments/pybind/example.cpython-39-x86_64-linux-gnu.so'>

>>> example.add(1,2)
3

对于 PYBIND11_MODULE 宏的分析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#define PYBIND11_MODULE(name, variable)                                                           \
    static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name)            \
        PYBIND11_MAYBE_UNUSED;                                                                    \
    PYBIND11_MAYBE_UNUSED                                                                         \
    static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &);                     \
    PYBIND11_PLUGIN_IMPL(name) {                                                                  \
        PYBIND11_CHECK_PYTHON_VERSION                                                             \
        PYBIND11_ENSURE_INTERNALS_READY                                                           \
        auto m = ::pybind11::module_::create_extension_module(                                    \
            PYBIND11_TOSTRING(name), nullptr, &PYBIND11_CONCAT(pybind11_module_def_, name));      \
        try {                                                                                     \
            PYBIND11_CONCAT(pybind11_init_, name)(m);                                             \
            return m.ptr();                                                                       \
        }                                                                                         \
        PYBIND11_CATCH_INIT_EXCEPTIONS                                                            \
    }                                                                                             \
    void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ & (variable))

同 pip 结合

0%