Pybind11 绑定编译失败 - shared_ptr of Eigen::Matrix 的静态断言失败
Pybind11 binding compilation fails - Static assertion fails with shared_ptr of Eigen::Matrix
我正在尝试为 OpenVSLAM/Stella_vslam 的开源项目编译 these Python bindings。
根据存储库说明,我执行以下命令:
/usr/bin/g++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) -I/usr/local/include/openvslam/3rd/json/include -DUSE_DBOW2 /home/user/OpenVSLAM-Python-bindings/openvslam_bindings.cpp -o openvslam$(python3-config --extension-suffix) -lopenvslam
但是编译失败 following error:
In file included from /home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/../attr.h:13,
from /home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/class.h:12,
from /home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/pybind11.h:13,
from /home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/stl.h:12,
from /home/squiro/Desktop/OpenVSLAM-Python-bindings/openvslam_bindings.cpp:6:
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/../cast.h: In instantiation of ‘struct pybind11::detail::copyable_holder_caster<Eigen::Matrix<double, 4, 4>, std::shared_ptr<Eigen::Matrix<double, 4, 4> >, void>’:
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/../cast.h:826:7: required from ‘class pybind11::detail::type_caster<std::shared_ptr<Eigen::Matrix<double, 4, 4> >, void>’
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/pybind11.h:242:63: recursively required by substitution of ‘template<class Return> struct pybind11::detail::return_value_policy_override<Return, typename std::enable_if<std::is_base_of<pybind11::detail::type_caster_generic, pybind11::detail::type_caster<typename pybind11::detail::intrinsic_type<T>::type> >::value, void>::type> [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >]’
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/pybind11.h:242:63: required from ‘void pybind11::cpp_function::initialize(Func&&, Return (*)(Args ...), const Extra& ...) [with Func = pybind11::cpp_function::cpp_function(Return (Class::*)(Arg ...), const Extra& ...) [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Class = stella_vslam::system; Arg = {const cv::Mat&, double, const cv::Mat&}; Extra = {pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg_v}]::<lambda(stella_vslam::system*, const cv::Mat&, double, const cv::Mat&)>; Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Args = {stella_vslam::system*, const cv::Mat&, double, const cv::Mat&}; Extra = {pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg_v}]’
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/pybind11.h:108:9: required from ‘pybind11::cpp_function::cpp_function(Return (Class::*)(Arg ...), const Extra& ...) [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Class = stella_vslam::system; Arg = {const cv::Mat&, double, const cv::Mat&}; Extra = {pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg_v}]’
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/pybind11.h:1578:22: required from ‘pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(const char*, Func&&, const Extra& ...) [with Func = std::shared_ptr<Eigen::Matrix<double, 4, 4> > (stella_vslam::system::*)(const cv::Mat&, double, const cv::Mat&); Extra = {pybind11::arg, pybind11::arg, pybind11::arg_v}; type_ = stella_vslam::system; options = {}]’
/home/squiro/Desktop/OpenVSLAM-Python-bindings/openvslam_bindings.cpp:357:134: required from here
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/../cast.h:753:61: error: static assertion failed: Holder classes are only supported for custom types
753 | static_assert(std::is_base_of<base, type_caster<type>>::value,
| ^~~~~
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/../cast.h:1408:55: error: ‘pybind11::detail::enable_if_t<(! std::is_void<_Yp>::value), Return> pybind11::detail::argument_loader<Args>::call(Func&&) && [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Guard = pybind11::detail::void_type; Func = pybind11::cpp_function::cpp_function(Return (Class::*)(Arg ...), const Extra& ...) [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Class = stella_vslam::system; Arg = {const cv::Mat&, double, const cv::Mat&}; Extra = {pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg_v}]::<lambda(stella_vslam::system*, const cv::Mat&, double, const cv::Mat&)>&; Args = {stella_vslam::system*, const cv::Mat&, double, const cv::Mat&}; pybind11::detail::enable_if_t<(! std::is_void<_Yp>::value), Return> = std::shared_ptr<Eigen::Matrix<double, 4, 4> >]’, declared using local type ‘pybind11::cpp_function::cpp_function(Return (Class::*)(Arg ...), const Extra& ...) [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Class = stella_vslam::system; Arg = {const cv::Mat&, double, const cv::Mat&}; Extra = {pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg_v}]::<lambda(stella_vslam::system*, const cv::Mat&, double, const cv::Mat&)>’, is used but never defined [-fpermissive]
1408 | enable_if_t<!std::is_void<Return>::value, Return> call(Func &&f) && {
| ^~~~
这是line 356 of openvslam_bindings.cpp中定义的:
.def("feed_monocular_frame", &system::feed_monocular_frame, py::arg("img"), py::arg("timestamp"), py::arg("mask") = cv::Mat{})
为了更清楚起见,feed_monocular_frame 是一个 returns a std:shared_ptrEigen::Matrix4d 的函数,如图this image.
我对 Pybind11 一般不熟悉,所以尽管我尝试了,但我无法找到解决此问题的方法。最近几天我一直在寻找答案,研究 pybind 的源代码......但仍然无法解决这个问题。
郑重声明,我使用的是 Ubuntu 20.04; Pybind 2.9.2 和 Eigen 3.3.0.
感谢任何帮助。
在这里回答自己,因为我在做更多研究后设法找到了解决方案。
我发现 a message on Gitter 与错误密切相关。我引用用户 YannickJadoul:
Don't return a std::shared_ptrEigen::ArrayXd, because pybind11 does
not know what to do with it, because Eigen matrices get converted into
np.ndarray and there's no way to hide the std::shared_ptr refcounting
in there
这就是在尝试构建绑定时触发静态断言错误的原因。
我找到了两种解决方法:
- 要么修改库的源代码,改变return类型...
- 或者我们可以将绑定包装在 return 矩阵(而不是指向它的指针)的 lambda 函数中。
我选择了第二种解决方案,因为它不涉及修改库。
这是绑定的原始定义:
.def("feed_monocular_frame", &system::feed_monocular_frame, py::arg("img"), py::arg("timestamp"), py::arg("mask") = cv::Mat{})
这是解决问题的修改版本:
.def("feed_monocular_frame",
[](stella_vslam::system &self, const cv::Mat &img, const double timestamp, const cv::Mat& mask = cv::Mat{}) {
std::shared_ptr<Mat44_t> matrix = self.feed_monocular_frame(img, timestamp, mask);
if (matrix)
return *matrix;
else
{
Eigen::Matrix4d m(4,4);;
return m;
}
},
py::arg("img"), py::arg("timestamp"), py::arg("mask") = cv::Mat{})
请记住,空指针检查与此问题无关。如果需要,您可以直接 return 矩阵(但如果指针为空,您可能会以分段错误结束,考虑一下!)。
我正在尝试为 OpenVSLAM/Stella_vslam 的开源项目编译 these Python bindings。
根据存储库说明,我执行以下命令:
/usr/bin/g++ -O3 -Wall -shared -std=c++11 -fPIC $(python3 -m pybind11 --includes) -I/usr/local/include/openvslam/3rd/json/include -DUSE_DBOW2 /home/user/OpenVSLAM-Python-bindings/openvslam_bindings.cpp -o openvslam$(python3-config --extension-suffix) -lopenvslam
但是编译失败 following error:
In file included from /home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/../attr.h:13,
from /home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/class.h:12,
from /home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/pybind11.h:13,
from /home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/stl.h:12,
from /home/squiro/Desktop/OpenVSLAM-Python-bindings/openvslam_bindings.cpp:6:
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/../cast.h: In instantiation of ‘struct pybind11::detail::copyable_holder_caster<Eigen::Matrix<double, 4, 4>, std::shared_ptr<Eigen::Matrix<double, 4, 4> >, void>’:
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/../cast.h:826:7: required from ‘class pybind11::detail::type_caster<std::shared_ptr<Eigen::Matrix<double, 4, 4> >, void>’
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/pybind11.h:242:63: recursively required by substitution of ‘template<class Return> struct pybind11::detail::return_value_policy_override<Return, typename std::enable_if<std::is_base_of<pybind11::detail::type_caster_generic, pybind11::detail::type_caster<typename pybind11::detail::intrinsic_type<T>::type> >::value, void>::type> [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >]’
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/pybind11.h:242:63: required from ‘void pybind11::cpp_function::initialize(Func&&, Return (*)(Args ...), const Extra& ...) [with Func = pybind11::cpp_function::cpp_function(Return (Class::*)(Arg ...), const Extra& ...) [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Class = stella_vslam::system; Arg = {const cv::Mat&, double, const cv::Mat&}; Extra = {pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg_v}]::<lambda(stella_vslam::system*, const cv::Mat&, double, const cv::Mat&)>; Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Args = {stella_vslam::system*, const cv::Mat&, double, const cv::Mat&}; Extra = {pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg_v}]’
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/pybind11.h:108:9: required from ‘pybind11::cpp_function::cpp_function(Return (Class::*)(Arg ...), const Extra& ...) [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Class = stella_vslam::system; Arg = {const cv::Mat&, double, const cv::Mat&}; Extra = {pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg_v}]’
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/pybind11.h:1578:22: required from ‘pybind11::class_<type_, options>& pybind11::class_<type_, options>::def(const char*, Func&&, const Extra& ...) [with Func = std::shared_ptr<Eigen::Matrix<double, 4, 4> > (stella_vslam::system::*)(const cv::Mat&, double, const cv::Mat&); Extra = {pybind11::arg, pybind11::arg, pybind11::arg_v}; type_ = stella_vslam::system; options = {}]’
/home/squiro/Desktop/OpenVSLAM-Python-bindings/openvslam_bindings.cpp:357:134: required from here
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/../cast.h:753:61: error: static assertion failed: Holder classes are only supported for custom types
753 | static_assert(std::is_base_of<base, type_caster<type>>::value,
| ^~~~~
/home/squiro/.local/lib/python3.8/site-packages/pybind11/include/pybind11/detail/../cast.h:1408:55: error: ‘pybind11::detail::enable_if_t<(! std::is_void<_Yp>::value), Return> pybind11::detail::argument_loader<Args>::call(Func&&) && [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Guard = pybind11::detail::void_type; Func = pybind11::cpp_function::cpp_function(Return (Class::*)(Arg ...), const Extra& ...) [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Class = stella_vslam::system; Arg = {const cv::Mat&, double, const cv::Mat&}; Extra = {pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg_v}]::<lambda(stella_vslam::system*, const cv::Mat&, double, const cv::Mat&)>&; Args = {stella_vslam::system*, const cv::Mat&, double, const cv::Mat&}; pybind11::detail::enable_if_t<(! std::is_void<_Yp>::value), Return> = std::shared_ptr<Eigen::Matrix<double, 4, 4> >]’, declared using local type ‘pybind11::cpp_function::cpp_function(Return (Class::*)(Arg ...), const Extra& ...) [with Return = std::shared_ptr<Eigen::Matrix<double, 4, 4> >; Class = stella_vslam::system; Arg = {const cv::Mat&, double, const cv::Mat&}; Extra = {pybind11::name, pybind11::is_method, pybind11::sibling, pybind11::arg, pybind11::arg, pybind11::arg_v}]::<lambda(stella_vslam::system*, const cv::Mat&, double, const cv::Mat&)>’, is used but never defined [-fpermissive]
1408 | enable_if_t<!std::is_void<Return>::value, Return> call(Func &&f) && {
| ^~~~
这是line 356 of openvslam_bindings.cpp中定义的:
.def("feed_monocular_frame", &system::feed_monocular_frame, py::arg("img"), py::arg("timestamp"), py::arg("mask") = cv::Mat{})
为了更清楚起见,feed_monocular_frame 是一个 returns a std:shared_ptrEigen::Matrix4d 的函数,如图this image.
我对 Pybind11 一般不熟悉,所以尽管我尝试了,但我无法找到解决此问题的方法。最近几天我一直在寻找答案,研究 pybind 的源代码......但仍然无法解决这个问题。
郑重声明,我使用的是 Ubuntu 20.04; Pybind 2.9.2 和 Eigen 3.3.0.
感谢任何帮助。
在这里回答自己,因为我在做更多研究后设法找到了解决方案。
我发现 a message on Gitter 与错误密切相关。我引用用户 YannickJadoul:
Don't return a std::shared_ptrEigen::ArrayXd, because pybind11 does not know what to do with it, because Eigen matrices get converted into np.ndarray and there's no way to hide the std::shared_ptr refcounting in there
这就是在尝试构建绑定时触发静态断言错误的原因。
我找到了两种解决方法:
- 要么修改库的源代码,改变return类型...
- 或者我们可以将绑定包装在 return 矩阵(而不是指向它的指针)的 lambda 函数中。
我选择了第二种解决方案,因为它不涉及修改库。
这是绑定的原始定义:
.def("feed_monocular_frame", &system::feed_monocular_frame, py::arg("img"), py::arg("timestamp"), py::arg("mask") = cv::Mat{})
这是解决问题的修改版本:
.def("feed_monocular_frame",
[](stella_vslam::system &self, const cv::Mat &img, const double timestamp, const cv::Mat& mask = cv::Mat{}) {
std::shared_ptr<Mat44_t> matrix = self.feed_monocular_frame(img, timestamp, mask);
if (matrix)
return *matrix;
else
{
Eigen::Matrix4d m(4,4);;
return m;
}
},
py::arg("img"), py::arg("timestamp"), py::arg("mask") = cv::Mat{})
请记住,空指针检查与此问题无关。如果需要,您可以直接 return 矩阵(但如果指针为空,您可能会以分段错误结束,考虑一下!)。