alexroat
alexroat

Reputation: 1727

python 2.7 ctypes: circular dependencies of .so shared libraries

I've a set of libraries to load as part of an API (close source) on a ARM linux 64bit, ubuntu derived. I need to interact with this libraries using a python script (2.7 for the moment) so I'm using ctypes. Before the last release, I was able to load all the so without problems after I found the correct loading order. In the last release, however, they have build up two libraries, libpos.so and libubx, with a mutual dependency. Infact, when I try to load these libraries I get:

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

I get

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

switching the loading order as:

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

i get

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

inspecting with nm for GPSRX_UpdatePosition

[email protected]:~/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
...

and for the UBX8_ProcessUbxPacket

[email protected]:~/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
...

As you see, there is a cyclical/mutual dependency. How can manage this wit CDLL of cdll.LoadLibrary ? I cannot define an order to load them.

Is there a sort of "lazy" .so loading ? Or is it possible to avoid the symbol checking?

I found that RTLD_GLOBAL, and RTLD_LOCAL only are defined in ctypes, no RTLD_LAZY. anyway, forcing

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

is going fine without errors ( so i suppose the UBX8_ProcessUbxPacket should be defined). But, when immediately after i try to load the libpos

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

or also

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

I'm still getting the error:

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

Is there a way to bypass this and force the loading of both libraries ?

Upvotes: 1

Views: 624

Answers (1)

alexroat
alexroat

Reputation: 1727

Ok, probably I found an inspiration to solve the problem here:

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

Simply define the RTLD_LAZY flag as 1 and the use it TOGETHER with RTLD_GLOBAL.

So the code becomes something like:

from ctypes import *

RTLD_LAZY = 0x0001

LAZYLOAD= RTLD_LAZY | RTLD_GLOBAL


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

and now it raises no exceptions

Upvotes: 2

Related Questions