强制执行扩展加载顺序

Enforcing the order of extension loading

我有两个 python 扩展(动态库),比如 a.so 和 b.so。在这两者中,a.so 依赖于 b.so,具体来说,它使用了 b.so.

中定义的类型

在python,我可以放心地做

import b
import a
# work

但是当我这样做的时候

import a
import b

导入没问题,但是当运行代码时,它报告a中的类型b.the_type不是b中的b.the_type。对 gdb 的仔细检查让我发现 a.so 和 b.so 中那种类型的 PyTypeObject 有两个不同的地址(和不同的 refcnt)。

我的问题是如何执行加载顺序,或确保两种方式都有效。


为了让熟悉共享库但不python的人能够帮助我,这里有一些额外的信息。在 python 扩展中,python 类型本质上是一个唯一的全局变量,在其模块(.so 文件)中初始化。类型必须在使用前进行初始化(这是通过调用 python API 完成的)。这些所需的初始化包含在具有特定名称的特定函数中。 Python 加载扩展时将调用此函数。

我的猜测是,由于 OS 知道 a.so 依赖于 b.so,当 python 时系统加载 b(而不是 python) ] 仅请求 a.so。然而调用模块初始化函数是 python 的责任,而 python 不知道 a 依赖于 b,所以 OS 只加载 b 而没有初始化。在 import b 上,当 python 实际调用模块初始化函数时,它会产生不同的 PyTypeObject。

如果解决方案依赖于平台,我的项目目前在 linux (archlinux) 上 运行。

您似乎链接 ab 以导入 b 定义的类型。不要这样做。

相反,像导入任何其他 Python 模块一样导入 b。换句话说,对 b 的依赖应该完全由 Python 二进制文件处理,而不是由 OS 的动态库加载结构处理。

使用C-API import functions导入b。到那时, 如何导入 b 应该无关紧要;从那时起,它只是一堆 Python 个对象。

这并不是说 b 不能为那些对象生成 C 级 API(NumPy 也这样做),你只需要确保它是 Python 加载扩展,而不是你的库。顺便说一句,NumPy 定义了为您导入的辅助函数,请参阅 the import_umath() code generator 示例。