Cython: вызов функции C выдает "неопределенный символ"
Я пытаюсь использовать LMDB C API с Cython.
Я хочу импортировать следующие определения из файла заголовка:
typedef struct MDB_env MDB_env;
int mdb_env_create(MDB_env **env);
Итак, я создал .pxd
файл:
cdef extern from 'lmdb.h':
struct MDB_env:
pass
int mdb_env_create(MDB_env **env)
И я использую его в скрипте Cython:
cdef MDB_env *e
x = mdb_env_create(&e)
Этот код компилируется нормально, но если я его запусту, я получу:
ImportError: /home/me/.cache/ipython/cython/_cython_magic_15705c11c6f56670efe6282cbabe4abc.cpython-36m-x86_64-linux-gnu.so: undefined symbol: mdb_env_create
Это происходит как в Cython .pyx
+ .pxd
настройки и в прототипе набраны в IPython.
Если я импортирую другой символ, скажем, константу, я могу получить к нему доступ. Кажется, я смотрю на правильный заголовочный файл.
Я не вижу никаких расхождений между моим синтаксисом и документацией, но я явно что-то делаю не так. Может кто-нибудь дать мне подсказку?
Благодарю.
1 ответ
Чтобы скомпилировать его с помощью IPythons-magic (было бы неплохо, если бы вы прямо упомянули об этом в своем вопросе), вы должны указать путь к библиотеке (через -L
-option) и имя библиотеки (через -l
-option) встроенной библиотеки c, которую вы хотите обернуть, смотрите также документацию:
%%cython -L=<path to your library> -l=<your_library>
Библиотека, которую вы пытаетесь обернуть, не является библиотекой только для заголовков. Это означает, что некоторые символы (например, mdb_env_create
) только объявлены, но не определены в заголовке. Когда вы создаете библиотеку, определения этих символов можно найти в результирующем артефакте, который должен быть предоставлен компоновщику при сборке вашего расширения. Эти определения необходимы для запуска программы.
Если вы этого не сделаете, в Linux произойдет следующее: *.so
-file), компоновщик допускает неопределенные символы по умолчанию - так что этот шаг является "успешным" - но ошибка только откладывается. Когда расширение загружается через import
, Python загружает соответствующий *.so
с помощью ldopen
и на этом этапе загрузчик проверяет, что определения всех символов известны. Но мы не дали определение mdb_env_create
Итак, загрузчик не работает с
неопределенный символ: mdb_env_create
Это различно для символов, которые определены в заголовочном файле, например, перечисления MDB_FIRST
&Co - скомпилированная библиотека не нужна, и, следовательно, расширение может быть загружено, так как нет неопределенных символов.