pybind11扩展模块缺失pyarrow符号:arrow::py::unwrap_table未定义
用pybind11开发Arrow扩展模块时遇
undefined symbol错误(指向arrow::py::unwrap_table) 问题描述
我用pybind11开发与Arrow交互的扩展模块,需要实现一个接收arrow::Table作为参数的函数。模块编译成功,但运行时触发ImportError,提示未定义符号_ZN5arrow2py12unwrap_tableEP7_object(即arrow::py::unwrap_table)。已知该符号存在于pyarrow的共享对象文件中,但无法让扩展模块正确找到它。
我希望模块直接使用用户安装的pyarrow自带共享库,避免版本不兼容问题,但缺乏扩展模块开发经验,不清楚这类问题的常规解决方式:是否需要静态链接库?或者有没有办法在运行时让Python定位到共享库?
最小复现示例
demo.cc
#include <pybind11/pybind11.h> #include <arrow/api.h> #include <arrow/python/pyarrow.h> int num_rows(pybind11::object const & py_obj) { auto result = arrow::py::unwrap_table(py_obj.ptr()); if (!result.ok()) { throw std::runtime_error("argument must be an Arrow table"); } std::shared_ptr<arrow::Table> table = result.ValueOrDie(); return table->num_rows(); } PYBIND11_MODULE(df_test, m) { arrow::py::import_pyarrow(); m.def("num_rows", &num_rows); }
pyproject.toml
[build-system] requires = [ "setuptools>=42", "pybind11>=2.10", "pyarrow", ] build-backend = "setuptools.build_meta" [project] name = "demo" description = "" version = "0.0.0" dependencies = ["pyarrow"]
setup.py
from setuptools import setup from pybind11.setup_helpers import Pybind11Extension import pyarrow as pa setup( ext_modules=[ Pybind11Extension( name='demo', sources=[ 'demo.cc', ], include_dirs=[pa.get_include()], # 尝试过添加但无效,构建环境的库路径是临时的 #libraries=pa.get_libraries(), #library_dirs=pa.get_library_dirs(), cxx_std=17, ), ], )
错误复现步骤
$ python -m venv venv $ . venv/bin/activate $ pip install . ... Successfully installed demo-0.0.0 numpy-1.26.4 pyarrow-16.1.0 $ python -c "import demo" Traceback (most recent call last): File "<string>", line 1, in <module> ImportError: /home/kale/hacking/snippets/python/pybind11_arrow/venv/lib/python3.12/site-packages/demo.cpython-312-x86_64-linux-gnu.so: undefined symbol: _ZN5arrow2py12unwrap_tableEP7_object
确认符号位置
$ nm -gD venv/lib/python3.12/site-packages/pyarrow/libarrow_python.so | grep unwrap_table 000000000019ad00 T _ZN5arrow2py12unwrap_tableEP7_object
解决方案
方法1:延迟符号解析(推荐,避免版本冲突)
问题根源是:动态链接器加载扩展模块时会立即解析所有未定义符号,但此时arrow::py::import_pyarrow()还未执行,pyarrow的共享库尚未加载。添加延迟解析选项后,符号会在第一次使用时才解析,此时pyarrow已被导入。
修改setup.py中的Pybind11Extension,添加Linux下的延迟解析链接参数:
Pybind11Extension( name='demo', sources=['demo.cc'], include_dirs=[pa.get_include()], cxx_std=17, extra_link_args=['-Wl,-z,lazy'], # 延迟解析未定义符号 )
重新安装测试:
pip install . --force-reinstall python -c "import demo; import pyarrow as pa; tbl = pa.Table.from_arrays([pa.array([1,2,3])], names=['col']); print(demo.num_rows(tbl))"
方法2:显式链接pyarrow共享库
如果方法1不生效,可以显式链接到pyarrow的共享库,并设置运行时库路径。但需注意构建环境与用户环境的路径一致性,可能需要用auditwheel等工具修复wheel包的运行时路径:
Pybind11Extension( name='demo', sources=['demo.cc'], include_dirs=[pa.get_include()], libraries=pa.get_libraries(), library_dirs=pa.get_library_dirs(), runtime_library_dirs=pa.get_library_dirs(), cxx_std=17, )
内容的提问来源于stack exchange,提问作者Kale Kundert
相关产品推荐
相关产品推荐

