我有一个混合 C++/Python 项目。它使用pybind11包装 Python 的 C++ 代码,并使用 bazel来构建解决方案。我对这个技术栈非常满意。安装 C++ 编译器、Python 发行版和 bazel 后,bazel run命令即可下载依赖项、构建并运行整个 C++/absl/Python/numpy 集团。
但为了让用户的事情变得更简单,我想将我的代码打包为 PyPI 包,以便可以使用pip install. 我希望该包是跨平台的,可以在 Windows、Linux 和 MacOS 上运行。
在生成新版本时,建立构建、打包并将所有内容上传到 PyPI 的管道的最清晰方法是什么?
我理解 C++ 上下文中枚举和枚举类之间的区别,但是在绑定枚举和枚举类的上下文中是否有任何真正的区别?
举例来说:
enum class options {
maybe,
yes,
no,
};
enum words {
hello,
world
};
Run Code Online (Sandbox Code Playgroud)
我刚刚以相同的方式绑定它们(见下文),所以我的问题是,我是否忽略了某些东西,或者在使用 pybind11 将它们绑定到 python 的上下文中,枚举和枚举类实际上是相同的吗?
py::enum_<options>(m, "options")
.value("maybe", options::maybe)
.value("yes", options::yes)
.value("no", options::no);
py::enum_<words>(m, "words")
.value("hello", words::hello)
.value("world", words::world)
Run Code Online (Sandbox Code Playgroud) 我正在为基于 C++ 的加密方案开发一个 python 包装器,其中密钥和密文是非常大的数字(最多 2048 位)。
在 C++ 中,我使用Intel BigNumber 类来存储和处理如此大的数字。
由于 Python 本身支持通过对象“看似”无限位整数,因此我在通过 Python 将此类变量作为参数传递时遇到了麻烦。
py::class_<BigNumber>(m, "BigNumber")
.def(py::init<unsigned int>())
.def(py::init<int>())
.def(py::init<BigNumber>())
.def(py::init([](py::list data) {
size_t length = data.size();
unsigned int* pData = new unsigned int[length];
for (int i = 0; i < length; i++) {
pData[i] = data[i].cast<unsigned int>();
}
return std::unique_ptr<BigNumber>(new BigNumber(pData, length));
}))
.def(py::init([](py::array_t<unsigned int> data) {
py::buffer_info buffer_info = data.request();
unsigned int* pData = static_cast<unsigned int*>(buffer_info.ptr);
std::vector<ssize_t> shape = buffer_info.shape;
return std::unique_ptr<BigNumber>(new BigNumber(pData, …Run Code Online (Sandbox Code Playgroud) 我正在努力使最简单的示例发挥作用。这是我的代码:
// example.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
class B {
public:
int b;
};
class A {
public:
int a;
A(int a) :a(a) {}
A(B b) { a = b.b; }
};
void fn(A) {}
PYBIND11_MODULE(example, m) {
py::class_<A>(m, "A")
.def(
py::init<int>(),
py::arg("a") = 1
);
py::class_<B>(m, "B")
.def(
py::init<int>(),
py::arg("b") = 2
);
py::implicitly_convertible<A, B>();
m.def("fn", &fn,
py::arg("a")
);
}
Run Code Online (Sandbox Code Playgroud)
# test.py
from example import *
a = A()
b = B()
fn(b)
Run Code Online (Sandbox Code Playgroud)
它构建得很好,但输出是:
$ python3.9 test.py …Run Code Online (Sandbox Code Playgroud) 我目前正在尝试定义一个共享库,我的目标是从 Python C++ 扩展以及普通 C++ 应用程序中使用它。
我设法构建了共享库,并尝试将一个简单的 C++ 应用程序链接到它以测试其功能,但共享库的函数之一被链接器视为未定义的引用。检查后nm --demangle --dynamic --defined-only --extern-only libmylib.so,我意识到该函数没有被共享库导出,但我不知道为什么。
该函数的签名如下:
void bootstrap_mylib(std::vector<std::string> python_path,
std::vector<std::string> python_scripts,
std::string interface_module,
std::function<void (pybind11::module_, pybind11::object)> interface_module_initializer);
Run Code Online (Sandbox Code Playgroud)
如果我注释掉最后一个参数,一切都会顺利,所以问题似乎来自于我以某种方式声明与 pybind11 的依赖关系的方式。
以下是我的 CMakeLists.txt 的相关部分:
set(CMAKE_CXX_COMPILER /usr/bin/g++)
project(monilog LANGUAGES CXX VERSION 0.0.1)
set(PYBIND11_PYTHON_VERSION 3.8)
find_package(pybind11 REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
add_library(mylib SHARED MyLib.cc MyLib.h)
set_property(TARGET mylib PROPERTY CXX_STANDARD 17)
target_link_libraries(mylib ${PYTHON_LIBRARIES})
set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})
set_target_properties(mylib PROPERTIES SOVERSION 1)
set_target_properties(mylib PROPERTIES PUBLIC_HEADER MyLib.h)
Run Code Online (Sandbox Code Playgroud)
知道我可能做错了什么吗?
编辑:最小工作示例
这是我的问题的一个最小示例,包含以下文件:
example.h#include <pybind11/stl.h>
namespace Example
{
void simple_func(std::string …Run Code Online (Sandbox Code Playgroud) 我正在开发一个带有 C++ 扩展模块的 python 包,该模块通过 pybind11 与 python 代码进行互操作,并且我正在使用 CMake 构建该包(基于此答案)。
我已将软件包安装为可编辑,以帮助开发pip install -e .
我经常更新 C++ 扩展模块,每次这样做时,让我的更改生效的唯一方法是完全清理每个构建文件,卸载,然后重新安装包,这在很大程度上违背了拥有一个包的目的。用于开发目的的可编辑安装。
有没有一种方法可以使用扩展模块进行可编辑安装,以便我可以在对其进行更改时重建模块,而无需每次都清理并重新安装整个包?
我维护一个大型 C++ 库,我使用 pybind11 部分接触了 python。C++ 库包含单元测试,我有时会在各种清理程序下运行这些测试:asan、tsan 等。这些测试运行干净,但当然测试并不完美,您无法 100% 测试所有边缘情况。
当我使用具有特定设置、特定数据集和各种选项的库时,有一个特定的 jupyter 笔记本会崩溃,这些选项可以在纯 C++ 环境中复制,但这种复制将非常耗费人力、时间并且容易出错。
如果我面前有纯 C++,我会通过 ubsan、asan 等运行笔记本,以确保我没有看到未定义的行为或段错误。有没有办法可以将这些消毒剂(或类似的东西)应用到我的笔记本上,而无需用原始 C++ 重写所有 python 胶水?
我是(相当大的)C++ 模拟工具的开发人员之一。免责声明:我更像是一名物理学家而不是开发人员。我使用 . 为该项目编写了 Python 绑定pybind11。
我设法让 Python 模块可以用cmake. 然后我设法使用它编写了一个setup.py文件skbuild来编译Python模块:
python3 setup.py sdist bdist_wheel
Run Code Online (Sandbox Code Playgroud)
在_skbuild/linux-x86_64-3.9/cmake-build/lib/(和 tar 存档中dist/cytosim-0.0.0.tar.gz)确实有一个已编译的库:cytosim.cpython-39-x86_64-linux-gnu.so。
但是,当我想安装该模块时:
pip3 install dist
Run Code Online (Sandbox Code Playgroud)
我收到错误:
gcc: error: src/py3/dist.c: No such file or directory
Run Code Online (Sandbox Code Playgroud)
我很困惑,因为我没有名为py3in 的目录src。
有什么指针吗?我做错了什么吗?谢谢 !
假设我有一个像这样的 C++ 枚举:
enum class Kind {Kind1 = 1, Kind2, Kind3};
Run Code Online (Sandbox Code Playgroud)
要使用 Pybind11 将此枚举绑定到 Python 枚举中,我正在执行以下操作:
py::enum_<Kind>(py_module, "Kind")
.value("Kind1", Kind::Kind1)
.value("Kind2", Kind::Kind2)
.value("Kind3", Kind::Kind3)
.def("__len__",
[](Kind p) {
return 3;
});
Run Code Online (Sandbox Code Playgroud)
编译代码后,如果我询问枚举的长度,我将收到此错误:
>>> len(Kind)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'pybind11_type' has no len()
Run Code Online (Sandbox Code Playgroud)
我有什么想法可以解决它吗?
编辑1:我在 Visual Studio 2019 (C++17) 上使用 Pybind11 版本 2.10.1。
编辑 2:我希望具有与 Python 枚举中相同的行为:
>>> from enum import Enum
>>> class Kind(Enum):
... kind1 = …Run Code Online (Sandbox Code Playgroud) 使用pybind11,如何将我的代码拆分为多个模块/文件?这样可以加快编译步骤。Pybind11文档介绍了扩展在其他扩展模块(在此处)中声明的类型的特殊情况。但不是更通用/更简单的一种。