2010-01-20 10 views
16

Soy nuevo en Cython y estoy tratando de usar Cython para envolver una biblioteca estática de C/C++. Hice un ejemplo simple como siguiente.Wrap C++ lib con Cython

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; 
} 

Luego utiliza g ++ para compilar y construirlo.

g++ -c test.cpp -o libtest.o 
ar rcs libtest.a libtest.o 

Así que ahora tengo una biblioteca estática llamada 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 
) 

La llamé:

python setup.py build_ext --compiler=mingw32 --inplace 

La salida fue:

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 

También traté de usar libraries = ['test'] en lugar de libraries = ['libtest']. Me dio los mismos errores.

¿Alguna pista sobre eso?

Gracias!

Respuesta

2

Creo que se puede solucionar este problema específico, especificando la derecha library_dirs (donde realmente se pone libtest.a - al parecer no está consiguiendo encontrado), pero creo que entonces tendrá otro problema - su entrada los puntos no se declaran correctamente como extern "C", por lo que el compilador C++ habrá "destrozado" los nombres de la función (¡mire los nombres exportados de libtest.a y verá!), por lo que cualquier otro idioma excepto C++ (incluyendo C , Cython, etc.) tendrán problemas para llegar a ellos. La solución es declararlos como extern "C".

+0

¿Dónde debería declarar extern "C"?Sin embargo, creo que el problema ahora es que la compilación se queja de que no puede encontrar libtest.a en lugar de una de las funciones, es decir, add() o mulitpy(). Entonces no estoy seguro de si esto funcionará. Es bastante raro para mí que se haya quejado de que no hay libtest.a en 'build \ temp.win32-2.6 \ Release'. ¿No es esa la carpeta de compilación generada por Cython? ¿Por qué Cython intentó buscar la libtest.a allí? –

+0

'extern" C "' va en las declaraciones de las funciones en '.h', y como he dicho, ese es el siguiente problema al que se enfrentarán después de arreglar los' 'library_dirs' incorrectos (usted dice que las bibliotecas están" en el directorio actual "y el 'Release' resulta ser el directorio actual en el momento en que el compilador/enlazador busca la biblioteca). –

23

Si su código C++ sólo se utiliza por la envoltura, otra opción es dejar que la configuración de compilar su archivo .cpp, así:

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 
) 

para ligarse a una biblioteca estática que tiene que utilizar el extra_objects argumento en su 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 
) 
+1

No, hice 'test.cpp' solo para probar. En el proyecto real, solo tengo un archivo principal y una biblioteca estática. –

+3

Parece que lo que quieres es la opción 'extra_objects', respuesta editada. –

+0

@zyq Entonces, ¿cómo continuamos una vez que se ha creado el archivo .so? – PascalVKooten

4

su archivo Test.pyx no está haciendo lo que se espera. La línea print add(2,3)no llamará a la función C++ add(); tienes que crear explícitamente una función de envoltura para hacer eso. Cython no crea contenedores para usted automáticamente.

Algo como esto es probablemente lo que quiere:

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) 

Usted puede mirar en Cython de documentation para más detalles.