Обернуть C ++ lib с Cython - PullRequest
       18

Обернуть C ++ lib с Cython

18 голосов
/ 21 января 2010

Я новичок в 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
llMain@12 --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']. Это дало мне те же ошибки.

Есть какие-нибудь подсказки по этому поводу?

Ответы [ 3 ]

24 голосов
/ 21 января 2010

Если ваш код C ++ используется только оболочкой, другой вариант - позволить программе установки скомпилировать ваш файл .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
)
4 голосов
/ 29 января 2014

Ваш 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 .

2 голосов
/ 21 января 2010

Я думаю, что вы можете решить эту конкретную проблему, указав правильное library_dirs (где вы на самом деле поместите libtest.a - очевидно, он не найден), но я думаю, что тогда у вас будет другая проблема - ваши точки входа неправильно объявлены как extern "C", поэтому имена функций будут «искажены» компилятором C ++ (посмотрите на имена, экспортированные из вашего libtest.a, и вы увидите!), так что любой у других языков, кроме C ++ (включая C, Cython и т. д.), будут проблемы с их получением. Исправление - объявить их как extern "C".

...