6

尝试加载使用 boost python 编译的 python 模块时出现以下导入错误。

ImportError: /path/to/library/libxml2.so.2: symbol gzopen64, version ZLIB_1.2.3.3 not defined in file libz.so.1 with link time reference

奇怪的是,如果这是要导入的非标准模块,我看不到这个错误。即,如果我先导入其他模块,然后再导入此模块,则会因导入错误而失败。不知道出了什么问题或如何调试。

编辑:要准确显示问题:

$ python -c 'import json, libMYBOOST_PY_LIB' # DOES NOT WORK!!!
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: path/to/xml_library/libxml2.so: symbol gzopen64, version ZLIB_1.2.3.3 not defined in file libz.so.1 with link time reference
$ python -c 'import libMYBOOST_PY_LIB, json' # WORKS NOW!!!
$

它不仅仅是 json,在我的模块之前导入时,很少有其他模块也会导致同样的问题。例如。urllib2

4

2 回答 2

5

import语句的顺序很重要。

如python语言参考中所述

一旦知道模块的名称(除非另有说明,术语“模块”将指包和模块),就可以开始搜索模块或包。首先检查的是sys.modules,之前已经导入的所有模块的缓存。如果在那里找到模块,则在导入的步骤 (2) 中使用它。

任何模块都可以更改:

他们也可以更改导入钩子:

导入钩子可以让您从 zip 文件、任何类型的存档文件、网络等加载模块。


import libMYBOOST_PY_LIB

该语句sys.modules肯定会修改,将其依赖项加载到模块缓存中。也可以修改sys.path。实际上,框架(例如boost, zope, django, requests...)附带电池/它们所依赖的模块的副本是很常见的。

  • django附带json
  • requests附带urllib3

要准确查看库将加载的内容,您可以使用:

python -v -c 'import libMYBOOST_PY_LIB'
于 2013-08-15T16:22:03.683 回答
3

问题

问题出在操作系统上。Linux 库(动态链接的共享对象库)可以依赖于其他库(可以再次依赖于其他库等等)。如果这些依赖库未正确解析,您将收到您描述的错误。

什么是共享库(so)

您可以通过获取多个目标文件并将它们链接在一起来创建共享库。链接器在创建共享库时会保留大量元数据:

  1. 重定位表
  2. 导出符号列表(其他人可以访问的函数和变量)
  3. 导入符号列表(此库从其他库使用的函数和变量)
  4. 其他库的文件名列表,可用于满足导入的符号

使用该库时,系统会加载该库,更改重定位表引用的地址,然后尝试查找导入的符号。对于这些,系统首先检查已加载的库。如果这不满足所有符号,它会尝试查找库中列出的文件名并检查是否存在具有该名称的文件,它是否是有效的库以及是否导出所需的符号。

通常这里的“系统”是动态加载器,它运行在用户空间,而不是内核空间。

您如何检查程序使用了哪些库

您可以使用命令检查库的内容ldd

如果要检查正在运行的可执行文件,请尝试lsof过滤*.so并检查/proc/[pid]/maps.

如何调试您的问题

在您的情况下,请在加载相关库之前直接保留程序(例如,从控制台插入读取或睡眠命令)。然后检查当前加载的库。您会发现,在好的情况下,已经加载了一个库来导出相关符号。在错误情况下,该库未加载,系统将在下一步尝试加载错误的依赖库(例如,缺少所需符号的库的不同版本)。

图书馆的顺序重要吗

通常不会,但这取决于细节。当不同版本需要相同的库或系统在所有情况下都无法解析共享库时,它可能变得很重要。不幸的是,这些问题很难调试。在 Windows 上你有 DLL 地狱,在 Linux 上它与共享对象类似。祝你调试问题好运!

于 2013-08-19T13:15:06.877 回答