Използвайте Cython за обвиване на C/C++-програма в зависимост от множество библиотеки

Имам голям C/C++ проект, който обикновено просто изграждам като самостоятелен изпълним файл. Освен това изисква някои библиотеки (системни библиотеки като pthread, но също и MKL от intel например), които посочвам при компилирането на проекта.

Сега искам да използвам някои функции от този проект в Python. Така че първият ми план беше просто да създам проекта като статична библиотека и след това да я използвам, за да напиша обвивка на cython. т.е.

  1. Създайте c проекта: icc -c src/main.cpp .. options and stuff.. linking to all libraries needed .. -o main.o

  2. Създайте статична библиотека (включително библиотеките, от които се нуждаех в стъпка 1): ar -rc libmain.a main.o ${MKLROOT}/lib/intel64/libmkl_intel_lp64.a ... /usr/lib/x86_64-linux-gnu/libpthread.a ...

  3. Използвам генерираната статична библиотека, за да създам моята обвивка на cython

  4. когато се опитам да изпълня тестов скрипт на python, извикващ произволна функция от моята C програма, получавам тази грешка ImportError: /home/.../main.cpython-37m-x86_64-linux-gnu.so: undefined symbol: __kmpc_ok_to_fork

Изглежда, че трябва да кажа на cython да се свърже отново със съответните библиотеки или нещо подобно, но не съм много сигурен как да разреша това. Също така не искам проектът на python да зависи от някои специални библиотеки, които имам инсталиран на моята система (това се опитвам да постигна чрез добавяне на всички библиотеки в стъпка 2), възможно ли е това изобщо?

Моят setup.py изглежда така

from setuptools import setup, Extension
from Cython.Build import cythonize
import os

os.environ["CC"] = "icc"
os.environ["CXX"] = "icc"
setup(
   ext_modules = cythonize([Extension("test", ["test.pyx"], language="c++",
                                  library_dirs=[r'.'], libraries=['main'])])
)

person user2224350    schedule 18.05.2021    source източник
comment
Бързо търсене подсказва, че __kmpc_ok_to_fork е в libiomp5. Можете ли да опитате да добавите iomp5 към библиотеките?   -  person brm    schedule 18.05.2021
comment
не, за съжаление грешката все още остава непроменена..   -  person user2224350    schedule 19.05.2021
comment
Освен това от добавянето на всички библиотеки полученият файл със статична библиотека става наистина огромен (като почти 1Gb). Трябва да има по-интелигентен начин да направя това.. Ако не включа библиотеките и по някакъв начин успея да кажа на cython да направи цялото свързване, файлът -so, генериран от cython, ще бъде ли независим от всички библиотеки? Мога ли да го копирам на друга машина?   -  person user2224350    schedule 19.05.2021
comment
Проблемът е, че линкерът не може да използва вашата статична библиотека. Правилният начин да го създадете е stackoverflow.com/a/50031940/5769463   -  person ead    schedule 19.05.2021
comment
Но обикновено не използвате статични версии на библиотеки - това може да доведе до странни резултати (тъй като ODR може да бъде нарушено)   -  person ead    schedule 19.05.2021
comment
Ясно, разбрах. Първо трябва да разопаковам .a файловете.. Но ако създаването на статична библиотека не е правилното решение, как бихте постъпили?   -  person user2224350    schedule 19.05.2021
comment
Това може да е възможно решение (разпространение на необходимите споделени библиотеки): stackoverflow.com/q/63804883/5769463   -  person ead    schedule 26.05.2021
comment
Това не е съвсем в духа на въпроса, но силно препоръчвам използването на pybind11 за обвързване на Python/C++. github.com/pybind/pybind11   -  person unddoch    schedule 26.05.2021


Отговори (1)


Създайте споделена библиотека (.so on linux). Python може да поддържа само динамични или споделени библиотеки. Линкерът търси .so не .a.

Така че вашият setup.py ще остане същият,

from setuptools import setup, Extension
from Cython.Build import cythonize
import os

os.environ["CC"] = "icc"
os.environ["CXX"] = "icc"
setup(
   ext_modules = cythonize([Extension("test", ["test.pyx"], language="c++",
                                  library_dirs=[r'.'], libraries=['main'])])
)

Свързани - Използване на Cython за свързване на Python към споделена библиотека.

person Shreyan Avigyan    schedule 25.05.2021
comment
Setup.py не търси библиотеки, той само предава имената на библиотеките към линкера, който ще избере статичната версия (напр. .a), ако няма споделена версия. - person ead; 26.05.2021
comment
Да, setup.py предава името на линкера. Cythonize преобразува Cython в C. И Python може да работи само с C код, който се свързва със споделена библиотека, а не със статична. - person Shreyan Avigyan; 26.05.2021
comment
Ако статичната библиотека е компилирана с код, независим от позицията, няма причина да не може да се използва в разширение на python (и както беше казано, setup.py не прави нищо, за да предотврати това) - person ead; 26.05.2021
comment
@ead Аз съм доброволец в CPython и съм 99% сигурен, че Python не може да работи със статична библиотека. Основният момент е дали кодът сега работи или не. И също така забележете, че редактирах отговора си, за да променя setup.py на линкер. - person Shreyan Avigyan; 26.05.2021
comment
Възможно е дори да се изгради статична библиотека по време на setup.py и да се използва в множество разширения. Вижте например stackoverflow.com/a/57673781/5769463 - person ead; 26.05.2021