pybind11:如何将 c++ 和 python 代码打包到一个包中?

2024-05-11

我正在尝试使用 CMake 和 pybind 11 将现有的 Python 代码和新的 C++ 11 代码打包在一起。我认为我缺少一些可以添加到 CMake 脚本中的简单内容,但在任何地方都找不到它:pybind11 示例只有 C++ 代码和没有Python,其他在线资源相当复杂而且不是最新的——所以我只是不知道如何将两种语言的函数打包在一起并通过Python提供它们import my_package下线...作为示例,我从 pybind11 克隆了 cmake_example 并添加了多功能 https://github.com/seninp/cmake_example into cmake_example/mult.py

def mult(a, b):
    return a * b

我怎样才能让它可见add and 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

目前,本次测试fails.. https://travis-ci.org/seninp/cmake_example/jobs/311687281

Thanks!


最简单的解决方案与pybind11像这样。当作者想要将纯 Python 和 C/Cython/其他本机扩展组合在同一个包中时,通常会这样做,如下所示。

您创建两个模块。

  1. mymodule是一个公共接口,一个纯Python模块
  2. _mymodule是一个私有实现,一个编译模块

Then in mymodule您从中导入必要的符号_mymoudle(如果需要的话,可以回退到纯Python版本)。

这是来自的示例yarl https://pypi.python.org/pypi/yarl包裹:

  1. 引用.py https://github.com/aio-libs/yarl/blob/2bdb8bc/yarl/quoting.py#L163

    try:
        from ._quoting import _quote, _unquote
        quote = _quote
        unquote = _unquote
    except ImportError:  # pragma: no cover
        quote = _py_quote
        unquote = _py_unquote
    
  2. _引用.pyx https://github.com/aio-libs/yarl/blob/master/yarl/_quoting.pyx

Update

以下是脚本。为了可重复性,我是根据原始内容来做的cmake_示例 https://github.com/pybind/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='[email protected] /cdn-cgi/l/email-protection',
    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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pybind11:如何将 c++ 和 python 代码打包到一个包中? 的相关文章

随机推荐