python 2.7 ctypes:.so共享库的循环依赖项

时间:2019-04-17 09:44:37

标签: python shared-libraries embedded-linux ctypes circular-dependency

我有一组库要作为在ubuntu派生的ARM linux 64位上的API(关闭源)的一部分加载。 我需要使用python脚本(此刻为2.7)与此库进行交互,因此我正在使用ctypes。 在上一个发行版之前,找到正确的加载顺序后,我便可以毫无问题地进行加载。 但是,在最后一个发行版中,它们建立了两个相互依赖的库libpos.so和libubx。 实际上,当我尝试加载这些库时,我得到:

libubx=CDLL("libubx.so", mode = RTLD_GLOBAL)
libpos=CDLL("libpos.so", mode = RTLD_GLOBAL)

我明白了

Traceback (most recent call last):
  File "testloading.py", line 11, in <module>
    libubx=CDLL("libubx.so", mode = RTLD_GLOBAL)
  File "/usr/lib/python2.7/ctypes/__init__.py", line 362, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: ./v2x-lib/lib/mk5/libubx.so: undefined symbol: GPSRX_UpdatePosition

将加载顺序切换为:

libpos=CDLL("libpos.so", mode = RTLD_GLOBAL)
libubx=CDLL("libubx.so", mode = RTLD_GLOBAL)

我得到

Traceback (most recent call last):
  File "testloading.py", line 11, in <module>
    libpos=CDLL("libpos.so", mode = RTLD_GLOBAL)
  File "/usr/lib/python2.7/ctypes/__init__.py", line 362, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: ./v2x-lib/lib/mk5/libpos.so: undefined symbol: UBX8_ProcessUbxPacket

用nm检查GPSRX_UpdatePosition

duser@10.233.1.70:~/mk5$ nm ./stack/v2x-lib/lib/mk5/*.so | grep "\.so\|GPSRX_UpdatePosition"
...
./stack/v2x-lib/lib/mk5/libpos.so:
000025a5 T GPSRX_UpdatePosition
...
./stack/v2x-lib/lib/mk5/libubx.so:
         U GPSRX_UpdatePosition
...

以及UBX8_ProcessUbxPacket

duser@10.233.1.70:~/mk5$ nm ./stack/v2x-lib/lib/mk5/*.so | grep "\.so\|UBX8_ProcessUbxPacket"
...
./stack/v2x-lib/lib/mk5/libpos.so:
         U UBX8_ProcessUbxPacket
...
./stack/v2x-lib/lib/mk5/libubx.so:
00003801 T UBX8_ProcessUbxPacket
...

如您所见,存在周期性/相互依赖性。 如何管理cdll.LoadLibrary的这个CDLL? 我无法定义加载它们的顺序。

是否存在某种“惰性” .so加载? 还是可以避免符号检查?

我发现RTLD_GLOBAL和RTLD_LOCAL仅在ctypes中定义,没有RTLD_LAZY。 无论如何,强迫

libubx=CDLL("libubx.so", mode = 1)

正常运行而没有错误(因此我认为应该定义UBX8_ProcessUbxPacket)。但是,当我尝试加载libpos之后

libpos=CDLL("libpos.so", mode = RTLD_GLOBAL)

或者也是

libpos=CDLL("libpos.so", mode = 1)

我仍然遇到错误:

Traceback (most recent call last):
  File "testloading.py", line 12, in <module>
    libpos=CDLL("libpos.so", mode = 1)
  File "/usr/lib/python2.7/ctypes/__init__.py", line 362, in __init__
    self._handle = _dlopen(self._name, mode)
OSError: ./v2x-lib/lib/mk5/libpos.so: undefined symbol: UBX8_ProcessUbxPacket

有没有一种方法可以绕过这个并强制加载两个库?

1 个答案:

答案 0 :(得分:0)

好吧,也许我在这里找到了解决问题的灵感:

https://stackoverflow.com/a/53343430/76081

只需将RTLD_LAZY标志定义为1,并与RTLD_GLOBAL一起使用 TOGETHER

因此,代码变为:

from ctypes import *

RTLD_LAZY = 0x0001

LAZYLOAD= RTLD_LAZY | RTLD_GLOBAL


...
libubx=CDLL("libubx.so",mode= LAZYLOAD)
libpos=CDLL("libpos.so",mode= LAZYLOAD)
....

现在它不引发任何异常