PYBIND11:如何将C 和Python代码包装到一个包装中
pybind11: how to package c++ and python code into a single package?
我正在尝试使用CMAKE和PYBIND 11将现有的Python代码和新的C 11代码包装在一起。在任何地方找到它:pybind11示例只有C 代码,没有python,其他在线资源相当令人费解,而不是最新的 - 因此,我只是不知道如何将两种语言包装在一起并使它们可用通过Python的import my_package
沿线...例如,我从pybind11克隆了CMAKE_EXAMPE,并在cmake_example/mult.py
def mult(a, b):
return a * b
如何使其与add
和subtract
一起通过以下测试?
import cmake_example as m
assert m.__version__ == '0.0.1'
assert m.add(1, 2) == 3
assert m.subtract(1, 2) == -1
assert m.mult(2, 2) == 4
目前,此测试失败..
谢谢!
最简单的解决方案与 pybind11 这样无关。作者通常要在同一包装中组合纯Python和C/Cython/其他本机扩展时,通常会做什么。
您创建两个模块。
-
mymodule
是一个公共接口,一个纯Python模块 -
_mymodule
是一个私人实现,一个符合的模块
然后,在mymodule
中,您会从_mymoudle
导入必要的符号(必要时退回到纯Python版本)。
此示例来自YARL软件包:
-
引用.py
try: from ._quoting import _quote, _unquote quote = _quote unquote = _unquote except ImportError: # pragma: no cover quote = _py_quote unquote = _py_unquote
-
_quoting.pyx
更新
这里遵循脚本。为了重现性,我正在使用原始cmake_example进行操作。
git clone --recursive https://github.com/pybind/cmake_example.git
# at the time of writing https://github.com/pybind/cmake_example/commit/8818f493
cd cmake_example
现在创建纯Python模块(内部cmake_example/cmake_example
)。
cmake_example/__init__.py
"""Root module of your package"""
cmake_example/math.py
def mul(a, b):
"""Pure Python-only function"""
return a * b
def add(a, b):
"""Fallback function"""
return a + b
try:
from ._math import add
except ImportError:
pass
现在,让我们修改现有文件以将cmake_example
模块转换为cmake_example._math
。
src/main.cpp
(subtract
为简洁删除)
#include <pybind11/pybind11.h>
int add(int i, int j) {
return i + j;
}
namespace py = pybind11;
PYBIND11_MODULE(_math, m) {
m.doc() = R"pbdoc(
Pybind11 example plugin
-----------------------
.. currentmodule:: _math
.. autosummary::
:toctree: _generate
add
)pbdoc";
m.def("add", &add, R"pbdoc(
Add two numbers
Some other explanation about the add function.
)pbdoc");
#ifdef VERSION_INFO
m.attr("__version__") = VERSION_INFO;
#else
m.attr("__version__") = "dev";
#endif
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.12)
project(cmake_example)
add_subdirectory(pybind11)
pybind11_add_module(_math src/main.cpp)
setup.py
# the above stays intact
from subprocess import CalledProcessError
kwargs = dict(
name='cmake_example',
version='0.0.1',
author='Dean Moldovan',
author_email='dean0x7d@gmail.com',
description='A test project using pybind11 and CMake',
long_description='',
ext_modules=[CMakeExtension('cmake_example._math')],
cmdclass=dict(build_ext=CMakeBuild),
zip_safe=False,
packages=['cmake_example']
)
# likely there are more exceptions, take a look at yarl example
try:
setup(**kwargs)
except CalledProcessError:
print('Failed to build extension!')
del kwargs['ext_modules']
setup(**kwargs)
现在我们可以构建它。
python setup.py bdist_wheel
在我的情况下,它会产生dist/cmake_example-0.0.1-cp27-cp27mu-linux_x86_64.whl
(如果C 汇编失败,则为cmake_example-0.0.1-py2-none-any.whl
)。这是它的内容(unzip -l ...
):
Archive: cmake_example-0.0.1-cp27-cp27mu-linux_x86_64.whl
Length Date Time Name
--------- ---------- ----- ----
0 2017-12-05 21:42 cmake_example/__init__.py
81088 2017-12-05 21:43 cmake_example/_math.so
223 2017-12-05 21:46 cmake_example/math.py
10 2017-12-05 21:48 cmake_example-0.0.1.dist-info/DESCRIPTION.rst
343 2017-12-05 21:48 cmake_example-0.0.1.dist-info/metadata.json
14 2017-12-05 21:48 cmake_example-0.0.1.dist-info/top_level.txt
105 2017-12-05 21:48 cmake_example-0.0.1.dist-info/WHEEL
226 2017-12-05 21:48 cmake_example-0.0.1.dist-info/METADATA
766 2017-12-05 21:48 cmake_example-0.0.1.dist-info/RECORD
--------- -------
82775 9 files
克隆了仓库后,CD到顶级目录`cmake_example'
更改./src/main.cpp以包括一个"多"函数:
#include <pybind11/pybind11.h>
int add(int i, int j) {
return i + j;
}
int mult(int i, int j) {
return i * j;
}
namespace py = pybind11;
PYBIND11_MODULE(cmake_example, m) {
m.doc() = R"pbdoc(
Pybind11 example plugin
-----------------------
.. currentmodule:: cmake_example
.. autosummary::
:toctree: _generate
add
subtract
mult
)pbdoc";
m.def("add", &add, R"pbdoc(
Add two numbers
Some other explanation about the add function.
)pbdoc");
m.def("mult", &mult, R"pbdoc(
Multiply two numbers
Some other explanation about the mult function.
)pbdoc");
(文件的其余部分相同)
现在做到:
$ cmake -H. -Bbuild
$ cmake --build build -- -j3
将在./build目录中创建导入的模块。转到它,然后在Python外壳中您的示例应该起作用。
对于命名空间导入,您可以使用pkgutil
进行操作:
创建目录结构:
./my_mod
__init__.py
cmake_example.***.so
和另一个并行结构
./extensions
/my_mod
__init__.py
cmake_example_py.py
并放在./my_mod/__init__.py
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
from .cmake_example import add, subtract
from .cmake_example_py import mult
在./extensions/my_mod/__init__.py
from cmake_example_py import mult
然后,同时将./my_mod和./extensions/my_mod同时添加到您的$ PythonPath,它可能会起作用(在我的示例中确实如此)
- 包装一个对象并假装它是一个 int
- 如何包装一个函数以适应另一个函数的所需类型
- 用输出参数包装一个c++函数,以便在javascript/node中使用
- 包装一个函数,在 Cython 中返回复杂类型的向量
- 用cython包装一个双** c ++函数
- const std::function 包装一个非 const 运算符() / 可变 lambda
- 包装一个使用char**[in/out]的C函数调用,以在cython中返回一个python列表
- 在Selene中包装一个枚举,以便在Lua中访问
- 有没有办法用C++类包装一个 Objective-C 对象
- 我应该包装一个完全包含在node.js函数中的C++对象吗
- 用swig包装一个大图书馆
- 使用SWIG和Python/C API来包装一个函数,该函数采用C++类实例的Python列表
- Cython:如何包装一个公共成员变量是自定义对象的C++类
- Python ctypes和包装一个c++std:wstring
- 包装一个C API函数返回指针到宏调用
- 如何为python包装一个c++库
- 如何在Objective-C中包装一个巨大的静态c++库
- 如何用C包装一个返回智能指针的C++函数
- 使用jni包装一个c++库
- Boost python包装一个虚方法