Wrap С++ lib с Cython
Я новичок в Cython и пытаюсь использовать Cython для создания статической библиотеки C/C++. Я сделал простой пример следующим образом.
test.h:
#ifndef TEST_H
#define TEST_H
int add(int a, int b);
int multipy(int a, int b);
#endif
test.cpp
#include "test.h"
int add(int a, int b)
{
return a+b;
}
int multipy(int a, int b)
{
return a*b;
}
Затем я использовал g++ для компиляции и сборки.
g++ -c test.cpp -o libtest.o
ar rcs libtest.a libtest.o
Так что теперь у меня есть статическая библиотека с именем libtest.a
.
Test.pyx:
cdef extern from "test.h":
int add(int a,int b)
int multipy(int a,int b)
print add(2,3)
Setup.py:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("test",
["test.pyx"],
language='c++',
include_dirs=[r'.'],
library_dirs=[r'.'],
libraries=['libtest']
)]
setup(
name = 'test',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
Я звонил:
python setup.py build_ext --compiler=mingw32 --inplace
Выход был:
running build_ext
cythoning test.pyx to test.cpp
building 'test' extension
creating build
creating build\temp.win32-2.6
creating build\temp.win32-2.6\Release
C:\Program Files\pythonxy\mingw\bin\gcc.exe -mno-cygwin -mdll -O -Wall -I. -IC:\
Python26\include -IC:\Python26\PC -c test.cpp -o build\temp.win32-2.6\Release\test.o
writing build\temp.win32-2.6\Release\test.def
C:\Program Files\pythonxy\mingw\bin\g++.exe -mno-cygwin -mdll -static --entry _D
[email protected] --output-lib build\temp.win32-2.6\Release\libtest.a --def build\temp.w
in32-2.6\Release\test.def -s build\temp.win32-2.6\Release\test.o -L. -LC:\Python
26\libs -LC:\Python26\PCbuild -ltest -lpython26 -lmsvcr90 -o test.pyd
g++: build\temp.win32-2.6\Release\libtest.a: No such file or directory
error: command 'g++' failed with exit status 1
Я также попытался использовать libraries=['test']
вместо libraries=['libtest']
. Это дало мне те же ошибки.
Есть какие-нибудь подсказки по этому поводу?
Ответы
Ответ 1
Если ваш код на С++ используется только оболочкой, другой параметр должен позволить программе скомпилировать ваш .cpp файл, например:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("test",
["test.pyx", "test.cpp"],
language='c++',
)]
setup(
name = 'test',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
Для ссылки на статическую библиотеку вы должны использовать аргумент extra_objects в Extension
:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("test",
["test.pyx"],
language='c++',
extra_objects=["libtest.a"],
)]
setup(
name = 'test',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
Ответ 2
Ваш файл Test.pyx
не выполняет то, что вы ожидаете. Строка print add(2,3)
не будет вызывать функцию add()
C++; Вы должны явно создать функцию-обертку, чтобы сделать это. Cython не создает обертки для вас автоматически.
Что-то вроде этого, вероятно, то, что вы хотите:
cdef extern from "test.h":
int _add "add"(int a,int b)
int _multiply "multiply"(int a,int b)
def add(a, b):
return _add(a, b)
def multiply(a, b):
return _multiply(a, b)
print add(2, 3)
Вы можете посмотреть документацию Cython для более подробной информации.
Ответ 3
Я думаю, вы можете исправить эту конкретную проблему, указав правильную library_dirs
(где вы на самом деле поместите libtest.a - видимо, ее не нашли), но я думаю, что тогда у вас будет другая проблема - ваши точки входа не объявлены как extern "C"
, поэтому имена функций будут "искалечены" компилятором С++ (посмотрите на имена, экспортированные из вашего libtest.a, и вы увидите!), поэтому любой другой язык, кроме С++ (включая C, Cython и т.д.), будет иметь проблемы с их получением. Исправление состоит в том, чтобы объявить их как extern "C"
.