Ctypes загружает c общую библиотеку с зависимостями
В Linux у меня есть c-библиотека, которая зависит от других библиотек. LD_LIBRARY_PATH правильно настроен, чтобы позволить компоновщику загружать все библиотеки. Когда я это сделаю:
libgidcwf = ctypes.cdll.LoadLibrary(libidcwf_path)
Я получаю следующую ошибку:
Traceback (most recent call last):
File "libwfm_test.py", line 12, in <module>
libgidcwf = ctypes.cdll.LoadLibrary(libidcwf_path)
File "/usr/lib/python2.5/ctypes/__init__.py", line 431, in LoadLibrary
return self._dlltype(name)
File "/usr/lib/python2.5/ctypes/__init__.py", line 348, in __init__
self._handle = _dlopen(self._name, mode)
OSError: path-to-my-lib/libwav.so: undefined symbol: ODBCGeneralQuery
Кажется, что LD_LIBRARY_PATH здесь не действует.
Есть ли способ, чтобы библиотека зависимостей "загружалась"?
Заранее благодарим за помощь.
Ответы
Ответ 1
Казалось бы, libwav.so не объявляет его зависимость от библиотеки, определяющей ODBCGeneralQuery. Попробуйте запустить ldd path-to-my-lib/libwav.so
и посмотрите, нет ли чего-то. Если это общая библиотека, которую вы строите, вы должны добавить -llibname
к команде связывания (той, которая похожа на gcc -shared -o libwav.so a.o b.o c.o
) для каждой библиотеки, используемой в библиотечном коде. Любые другие библиотеки, на которые ссылается исходная разделяемая библиотека таким образом, также должны автоматически загружаться.
Ответ 2
Вы должны использовать RTLD_GLOBAL. У меня смешанная платформа, поэтому мой код выглядит примерно так:
import numpy, ctypes
try:
if "Linux" in esmfos:
_ESMF = ctypes.CDLL(libsdir+'/libesmf.so',mode=ctypes.RTLD_GLOBAL)
else:
_ESMF = numpy.ctypeslib.load_library('libesmf',libsdir)
except:
traceback.print_exc(file=sys.stdout)
sys.exit(ESMP_ERROR_SHAREDLIB)
Ответ 3
При компиляции общего объекта обязательно поставьте все -lsomething
в конце строки. Для меня это решило проблему.
Ответ 4
У меня была та же проблема.
Для его решения потребовались две вещи:
- используйте
RTLD_GLOBAL
, как говорят другие пользователи.
- Вам нужно загрузить каждую библиотеку, используемую вашей библиотекой. Так что если
ODBCGeneralQuery
определено в let say libIDCodbc
, вам нужно сначала запустить эту строку:
ctypes.CDLL("libIDCodbc.so", mode = ctypes.RTLD_GLOBAL)
Ответ 5
Я обнаружил, что мне пришлось использовать RTLD_LAZY
из-за символа undefined, который не был связан, потому что он не использовался. Поскольку в моих типах нет ctypes.RTLD_LAZY
, мне пришлось использовать:
ctypes.CDLL(libidcwf_path, mode=1)
Я нашел этот режим, проверив /usr/include/bits/dlfcn.h
, который, вероятно, не является стандартным. Перейти к этой теме thread в списке рассылки ctypes.
Ответ 6
Основываясь на ответе Вальтера Ниссена выше, вы можете изменить код так:
import os
ctypes.CDLL(libidcwf_path, mode=os.RTLD_LAZY)