如何使用存根构建和分发 Pybind11 扩展? 也许是康达?

问题描述

我正在尝试创建和分发(使用 pip)一个包含 Python 代码和 C++ 代码的 Python 包,使用 Pybind11(使用 Visual Studio 2019)编译为 .pyd 文件。我还想包含 .pyi 存根文件,用于 VScode 和其他编辑器。我找不到太多关于正确执行此操作的文档。

我希望喜欢能够像往常一样通过 pip 安装包,并像普通的 Python 包一样编写 from mymodule.mysubmodule import myfunc 等,包括自动完成、类型注释、VScode 智能感知等使用我编写的 .pyi 文件

我的 C++ 代码在多个 cpp 和头文件中。它使用一些标准库,一些外部库(例如 boost)。它定义了一个模块和 2 个子模块。我希望能够在 Windows 和 Linux 以及 x86 和 x64 上分发它。我目前的目标是 Python 3.9 和 c++17 标准。

我应该如何构建和分发这个包?我是否包含 c++ 源文件,并创建类似于 Pybind11 example 的 setup.py?如果是这样,我如何包含外部库?以及如何构建 .pyi 存根文件?这是否意味着尝试安装我的软件包的人也需要 C++ 编译器?

或者,我应该将我的 C++ 编译为每个平台和架构的 .pyd/.so 文件吗?如果是这样,有没有办法指定通过 pip 安装哪个?再说一次,我将如何构建 .pyi 存根?

解决方法

生成 .pyi 存根

pybind11 issue 提到了一些工具(12)来为二进制模块生成存根。可能还有更多,但我不知道其他人。不幸的是,两者都远非完美,因此您可能仍需要手动检查和调整生成的存根。

.pyi 存根的分布

在修正存根之后,您只需将那些 .pyi 文件包含在您的发行版中(例如在轮子中或作为源)以及 py.typed 指示文件,或者,将它们作为独立包单独分发(例如 { {1}})。

建造轮子

Wheels 允许您的库的用户以二进制形式安装它,即无需编译。 Wheels 使用较旧的编译器来兼容更多的系统/平台,因此您可能会遇到 C++17 库的一些问题。 (C++11 已经够老了,轮子应该没有问题)。

为各种平台构建轮子很乏味,pybind11 的 python_example 使用 cibuildwheels 包来做到这一点,如果你已经在使用 CI,我会推荐这条路线。

如果目标平台缺少轮子,pip 将尝试从源安装。这需要已安装您正在使用的编译器和第 3 方库。

也许是康达?

如果您的设置很复杂并且需要许多 3rd 方库,那么编写一个 conda recipe 并使用 conda-forge 来生成包的二进制版本可能是值得的。 Conda 优于 pip,因为它也可以管理非 Python 依赖项。