首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >pybind11:如何将c++和python代码打包到一个包中?

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

Stack Overflow用户
提问于 2017-12-01 18:11:44
回答 2查看 9.9K关注 0票数 19

我试图用C++和CMake 11将现有的Python代码和新的CMake 11代码打包在一起。我想我遗漏了一些很简单的东西,可以添加到CMake脚本中,但在任何地方都找不到: pybind11示例中只有C++代码,没有Python,其他在线资源相当复杂,没有最新的版本--所以我只是想不出如何将两种语言中的函数打包在一起,并通过Python的import my_package在一行中提供它们.例如,我已经将cmake_example从pybind11和增加了一个多功能中克隆到了cmake_example/mult.py中。

代码语言:javascript
复制
def mult(a, b):
    return a * b

如何使addsubtract一起可见以通过下面的测试?

代码语言:javascript
复制
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

目前,此测试失败..。

谢谢!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-12-05 10:42:29

最简单的解决方案与pybind11本身无关。当作者希望将纯Python和C/Cython/其他本地扩展合并到同一个包中时,他们通常做的事情如下。

创建两个模块。

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

然后,在mymodule中,从_mymoudle导入必要的符号(如果需要的话,返回到纯_mymoudle版本)。

下面是来自纱,纱包的示例:

  1. quoting.py 试试看:从._quoting导入_quote,_unquote引号= _quote _unquote =_unquote,除了ImportError:#杂注:无盖引号= _py_quote
  2. quoting.pyx

更新

下面是脚本。为了重现性,我是针对原始示例做的。

代码语言:javascript
复制
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

代码语言:javascript
复制
"""Root module of your package"""

cmake_example/math.py

代码语言:javascript
复制
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)

代码语言:javascript
复制
#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

代码语言:javascript
复制
cmake_minimum_required(VERSION 2.8.12)
project(cmake_example)

add_subdirectory(pybind11)
pybind11_add_module(_math src/main.cpp)

setup.py

代码语言:javascript
复制
# 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)

现在我们可以建造了。

代码语言:javascript
复制
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 ...):

代码语言:javascript
复制
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
票数 21
EN

Stack Overflow用户

发布于 2017-12-05 03:30:58

一旦您将回购cd克隆到顶级目录`cmake_example‘

更改./src/main.cpp以包含"mult“函数:

代码语言:javascript
复制
#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");

(文件的其余部分相同)

现在让它:

代码语言:javascript
复制
$ cmake -H. -Bbuild
$ cmake --build build -- -j3

导入模块将在./build目录中创建。转到它,然后在python shell中使用您的示例。

对于名称空间导入,可以使用pkgutil执行一些操作。

创建目录结构:

代码语言:javascript
复制
./my_mod
    __init__.py
    cmake_example.***.so

和另一个并行结构

代码语言:javascript
复制
./extensions
    /my_mod
        __init__.py
        cmake_example_py.py

以及在./my_mod/__init__.py中的位置

代码语言:javascript
复制
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

代码语言:javascript
复制
from cmake_example_py import mult

然后将./ my _mod和./ $PYTHONPATH /my_mod都附加到您的中,它可能会工作(在我的示例中是这样)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47599162

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档