Использование Cython для связи Python с общей библиотекой

29

Я пытаюсь интегрировать стороннюю библиотеку, написанную в C с моим приложением python, используя Cython. У меня есть весь код python, написанный для теста. У меня возникли проблемы с поиском примера для его настройки.

У меня есть файл pyd/pyx, который я создал вручную. Третья сторона дала мне header file (*.h) и shared library (*.so). Насколько я могу судить, нет других зависимостей. Может ли кто-нибудь предоставить пример того, как установить это, используя Cython и disutils?

Спасибо

Теги:
linker
cython
distutils

1 ответ

50
Лучший ответ

Конечно!

(В дальнейшем я предполагаю, что вы уже знаете, как иметь дело с cimport и взаимодействиями между .pxd и .pyx. Если это не совсем так, просто спросите, и я разработаю эту часть как а)

Образец (взятый из моего проекта С++, но проект C будет работать примерно так же):

1. Файл настройки Distutils:

Предполагая, что созданное расширение будет называться myext, а разделяемая библиотека третьей стороны - libexternlib.so (обратите внимание на префикс lib > )...

# setup.py file
import sys
import os
import shutil

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

# clean previous build
for root, dirs, files in os.walk(".", topdown=False):
    for name in files:
        if (name.startswith("myext") and not(name.endswith(".pyx") or name.endswith(".pxd"))):
            os.remove(os.path.join(root, name))
    for name in dirs:
        if (name == "build"):
            shutil.rmtree(name)

# build "myext.so" python extension to be added to "PYTHONPATH" afterwards...
setup(
    cmdclass = {'build_ext': build_ext},
    ext_modules = [
        Extension("myext", 
                  sources=["myext.pyx",
                           "SomeAdditionalCppClass1.cpp",
                           "SomeAdditionalCppClass2.cpp"
                       ],
                  libraries=["externlib"],          # refers to "libexternlib.so"
                  language="c++",                   # remove this if C and not C++
                  extra_compile_args=["-fopenmp", "-O3"],
                  extra_link_args=["-DSOME_DEFINE_OPT", 
                                   "-L./some/extra/dependency/dir/"]
             )
        ]
)           

Примечание. Внешний файл .so связан с помощью опции libraries:

libraries=["externlib"]   # Without the 'lib' prefix and the '.so' extension...

Примечание: параметр sources может использоваться для компиляции некоторых исходных файлов.

Важно: myext.pxd (не смешивайте с .pyd - материал Windows) и myext.pyx должны находиться в одном каталоге. Во время компиляции файл определения, если он существует, обрабатывается первым (больше).

2. Затем запустите его следующим образом:

После изменения каталога на тот, который содержит ваш myext.pxd, ваш myext.pyx, а также выше setup.py script:

# setup.sh
# Make the "myext" Python Module ("myext.so")
CC="gcc"   \
CXX="g++"   \
CFLAGS="-I./some/path/to/includes/ -I../../../DEPENDENCIES/python2.7/inc -I../../../DEPENDENCIES/gsl-1.15"   \
LDFLAGS="-L./some/path/to/externlib/"   \
    python setup.py build_ext --inplace

Где:

  • Предполагается, что
  • libexternlib.so находится в ./some/path/to/externlib/ Предполагается, что
  • yourheader.h находится в ./some/path/to/includes/

Примечание. CFLAGS также можно было установить с помощью опции extra_compile_args:

extra_compile_args=["-I./some/path/to/includes/", "-fopenmp", "-O3"]

Примечание. LDFLAGS также можно было установить с помощью параметра extra_link_args:

extra_link_args=["-L./some/path/to/externlib/", "-DSOME_DEFINE_OPT", "-L./some/extra/dependency/dir/"]

Как только distutils выполняется со сборкой, вы получите несколько новых файлов, особенно myext.cpp, myext.h и, самое главное, myext.so.

3. После этого вы хорошо пойдете:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./some/path/to/externlib/
export PYTHONPATH=$PYTHONPATH:./some/path/to/myext/

# Run some script requiring "myext.so"
python somescript.py

Если ваше только что созданное расширение Python можно импортировать по его имени:

# somescript.py
import myext
from myext import PySomeFeature
...

Примечание об оптимизации: по умолчанию -O2 используется для компиляции расширения, но это может быть перегружено (см. выше настройки, где указан -O3).

Примечание о путях Cython: если Cython был установлен в настраиваемом каталоге, вы можете добавить его в свою среду, прежде чем все:

PYTHONPATH=$PYTHONPATH:../../../DEPENDENCIES/Cython-0.18 export PYTHONPATH;
PATH=$PATH:../../../DEPENDENCIES/Cython-0.18/bin; export PATH;

Хорошо, надеюсь, что я осветил основные моменты...

  • 0
    Эй, спасибо за вашу помощь. Я получаю следующую ошибку: ld: библиотека не найдена для -lMYLIB, где MYLIB.so - это файл, на который я пытаюсь ссылаться - есть идеи?
  • 0
    забудь об этом, я только что прочитал, что команда gcc -l предполагает, что твоему * .so предшествует lib, поэтому я удалил его, и он нашел его и, кажется, работает.
Показать ещё 7 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню