ctypes загрузка общей библиотеки c, которая имеет зависимости - PullRequest
22 голосов
/ 24 февраля 2010

В 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 не имеет здесь никакого эффекта. Есть ли способ сделать эти библиотеки зависимостей "загружаемыми"?

Заранее спасибо за помощь.

Ответы [ 6 ]

17 голосов
/ 24 февраля 2010

Казалось бы, libwav.so не объявляет свою зависимость от библиотеки, определяющей ODBCGeneralQuery. Попробуйте запустить ldd path-to-my-lib/libwav.so и посмотрите, чего не хватает. Если вы создаете совместно используемую библиотеку, вы должны добавить -llibname к команде компоновки (например, gcc -shared -o libwav.so a.o b.o c.o) для каждой библиотеки, которую использует код библиотеки. Любые другие библиотеки, на которые ссылается исходная общая библиотека таким образом, также должны автоматически загружаться.

7 голосов
/ 31 января 2012

Вы должны использовать 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)
6 голосов
/ 25 августа 2012

Когда вы компилируете общий объект, обязательно поставьте все -lsomething в конце строковой команды. Для меня это решило проблему.

4 голосов
/ 15 июня 2015

У меня была такая же проблема. Для ее решения потребовались две вещи:

  1. используйте RTLD_GLOBAL, как сказали другие пользователи
  2. Вам нужно загрузить каждую библиотеку, которая используется вашей библиотекой. Так что, если ODBCGeneralQuery определено, скажем, libIDCodbc, вам нужно сначала запустить эту строку:

ctypes.CDLL("libIDCodbc.so", mode = ctypes.RTLD_GLOBAL)

3 голосов
/ 22 декабря 2017

Я обнаружил, что должен был использовать RTLD_LAZY из-за неопределенного символа, который не был связан, потому что он не использовался. Поскольку в моих типах нет ctypes.RTLD_LAZY, мне пришлось использовать:

ctypes.CDLL(libidcwf_path, mode=1)

Я нашел этот режим, проверив /usr/include/bits/dlfcn.h, который, вероятно, не является стандартным. Подсказка к этой теме 2006 в списке рассылки ctypes.

1 голос
/ 09 мая 2019

На основании ответа Уолтера Ниссена выше, вы можете изменить код так:

import os
ctypes.CDLL(libidcwf_path, mode=os.RTLD_LAZY)
...