Python扩展模块调用Mapnik库函数时因符号名单字符差异引发运行时ImportError问题求助
大家好,我最近在开发一个封装Mapnik C++库的Python扩展模块,编译过程完全顺利,但运行时却碰到了ImportError报错,具体信息如下:
ImportError: dlopen(/Users/larsga/cvs-co/fhdb/reports/pymapnik3.cpython-310-darwin.so, 0x0002): symbol not found in flat namespace.
我的运行环境是MacOS,编译器用的是clang。
符号差异分析
我追踪到缺失的是一个超长的C++ mangled符号:
__ZN6mapnik4rule10set_filterERKNSt3__110shared_ptrIN6mapbox4util7variantIJNS_10value_nullEbidN6icu_7113UnicodeStringENS_9attributeENS_16global_attributeENS_23geometry_type_attributeENS4_17recursive_wrapperINS_10unary_nodeINS_4tags6negateEEEEENSC_INS_11binary_nodeINSE_4plusEEEEENSC_INSI_INSE_5minusEEEEENSC_INSI_INSE_4multEEEEENSC_INSI_INSE_3divEEEEENSC_INSI_INSE_3modEEEEENSC_INSI_INSE_4lessEEEEENSC_INSI_INSE_10less_equalEEEEENSC_INSI_INSE_7greaterEEEEENSC_INSI_INSE_13greater_equalEEEEENSC_INSI_INSE_8equal_toEEEEENSC_INSI_INSE_12not_equal_toEEEEENSC_INSD_INSE_11logical_notEEEEENSC_INSI_INSE_11logical_andEEEEENSC_INSI_INSE_10logical_orEEEEENSC_INS_16regex_match_nodeEEENSC_INS_18regex_replace_nodeEEENSC_INS_19unary_function_callEEENSC_INS_20binary_function_callEEEEEEEE
Demangled后的函数签名为:
_mapnik::rule::set_filter(std::__1::shared_ptr<mapbox::util::variant<mapnik::value_null, bool, int, double, icu_71::UnicodeString, mapnik::attribute, mapnik::global_attribute, mapnik::geometry_type_attribute, mapbox::util::recursive_wrapper<mapnik::unary_node<mapnik::tags::negate> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::plus> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::minus> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::mult> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::div> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::mod> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::less> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::less_equal> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::greater> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::greater_equal> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::equal_to> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::not_equal_to> >, mapbox::util::recursive_wrapper<mapnik::unary_node<mapnik::tags::logical_not> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::logical_and> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::logical_or> >, mapbox::util::recursive_wrapper<mapnik::regex_match_node>, mapbox::util::recursive_wrapper<mapnik::regex_replace_node>, mapbox::util::recursive_wrapper<mapnik::unary_function_call>, mapbox::util::recursive_wrapper<mapnik::binary_function_call> > > const&)
随后我查看了安装在/usr/local/lib/libmapnik.dylib中的对应符号,发现有一个几乎完全一致的符号,但存在一处关键差异:
__ZN6mapnik4rule10set_filterERKNSt3__110shared_ptrIN6mapbox4util7variantIJNS_10value_nullEbxdN6icu_7113UnicodeStringENS_9attributeENS_16global_attributeENS_23geometry_type_attributeENS4_17recursive_wrapperINS_10unary_nodeINS_4tags6negateEEEEENSC_INS_11binary_nodeINSE_4plusEEEEENSC_INSI_INSE_5minusEEEEENSC_INSI_INSE_4multEEEEENSC_INSI_INSE_3divEEEEENSC_INSI_INSE_3modEEEEENSC_INSI_INSE_4lessEEEEENSC_INSI_INSE_10less_equalEEEEENSC_INSI_INSE_7greaterEEEEENSC_INSI_INSE_13greater_equalEEEEENSC_INSI_INSE_8equal_toEEEEENSC_INSI_INSE_12not_equal_toEEEEENSC_INSD_INSE_11logical_notEEEEENSC_INSI_INSE_11logical_andEEEEENSC_INSI_INSE_10logical_orEEEEENSC_INS_16regex_match_nodeEEENSC_INS_18regex_replace_nodeEEENSC_INS_19unary_function_callEEENSC_INS_20binary_function_callEEEEEEEE
Demangled后的签名:
_mapnik::rule::set_filter(std::__1::shared_ptr<mapbox::util::variant<mapnik::value_null, bool, long long, double, icu_71::UnicodeString, mapnik::attribute, mapnik::global_attribute, mapnik::geometry_type_attribute, mapbox::util::recursive_wrapper<mapnik::unary_node<mapnik::tags::negate> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::plus> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::minus> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::mult> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::div> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::mod> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::less> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::less_equal> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::greater> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::greater_equal> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::equal_to> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::not_equal_to> >, mapbox::util::recursive_wrapper<mapnik::unary_node<mapnik::tags::logical_not> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::logical_and> >, mapbox::util::recursive_wrapper<mapnik::binary_node<mapnik::tags::logical_or> >, mapbox::util::recursive_wrapper<mapnik::regex_match_node>, mapbox::util::recursive_wrapper<mapnik::regex_replace_node>, mapbox::util::recursive_wrapper<mapnik::unary_function_call>, mapbox::util::recursive_wrapper<mapnik::binary_function_call> > > const&)
核心差异点:我的扩展模块中variant的模板参数是int,而Mapnik库中对应的是long long——反映在mangled符号里就是Ebid vs Ebxd(i对应int类型,x对应long long类型)。
我的困惑
Mapnik库是通过SCons编译后安装到系统路径的,而我的Python扩展是用python3 setup.py build(基于distutils)编译的,两者用的都是clang编译器。我已经通过DYLD_PRINT_LIBRARIES=YES确认了扩展加载的是正确的libmapnik.dylib,但就是出现了符号不匹配的问题。
有没有大佬能指点下,这种类型参数差异可能是由哪些编译选项或配置差异导致的?
备注:内容来源于stack exchange,提问作者Lars Marius Garshol

