2010-01-20 14 views
16

Sono un neofita di Cython e sto cercando di utilizzare Cython per racchiudere una libreria statica C/C++. Ho fatto un semplice esempio come segue.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; 
} 

poi ho usato g ++ per compilare e costruirlo.

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

Così ora ho ottenuto una libreria statica chiamata 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 
) 

L'ho chiamato:

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

L'uscita era:

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 

Ho anche provato a usare le librerie = ['test'] invece delle librerie = ['libtest']. Mi ha dato gli stessi errori.

Qualsiasi indizio su questi?

Grazie!

risposta

2

Penso che si possa risolvere questo problema specifico specificando il diritto library_dirs (dove effettivamente mette libtest.a - a quanto pare non è sempre trovato), ma penso che allora avrete un altro problema - la voce i punti non sono dichiarati correttamente come extern "C", quindi i nomi della funzione saranno "storpiati" dal compilatore C++ (guarda i nomi esportati dal tuo libtest.a e vedrai!), quindi qualsiasi altra lingua eccetto C++ (incluso C , Cython, ecc.) Avranno problemi nel trovarli. La correzione è dichiararli come extern "C".

+0

Dove devo dichiarare extern "C"?Tuttavia, penso che il problema ora sia che la build si lamenta di non poter trovare libtest.a invece di una funzione, ad esempio add() o mulitpy(). Quindi non sono sicuro se questo funzionerà. Per me è piuttosto strano lamentarsi che non esiste libtest.a in 'build \ temp.win32-2.6 \ Release'. Non è la cartella build generata da Cython stesso? Perché Cython ha provato a cercare il libtest.a lì? –

+0

'extern" C "' entra nelle dichiarazioni delle funzioni nel '.h', e come ho detto questo è il prossimo problema che dovrai affrontare dopo aver corretto il' library_dirs' errato (dici che le librerie sono "nella directory corrente "e il' Release' sembra essere la directory corrente al momento in cui il compilatore/linker sta cercando la libreria). –

23

Se il codice vostro C++ è utilizzato solo dal wrapper, un'altra opzione è quella di lasciare che la configurazione compilare il file cpp, in questo modo:

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 
) 

Per il collegamento a una libreria statica è necessario utilizzare il extra_objects argomento a vostra 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, ho effettuato "test.cpp" solo per il test. Nel progetto reale, ho solo un file head e una libreria statica. –

+3

Sembra che quello che vuoi sia l'opzione 'extra_objects', la risposta modificata. –

+0

@zyq Quindi come procedere una volta creato il file .so? – PascalVKooten

4

Il file Test.pyx non sta facendo quello che vi aspettate. La riga print add(2,3)non chiama chiama la funzione add() C++; devi creare esplicitamente una funzione wrapper per farlo. Cython non crea automaticamente wrapper per te.

Qualcosa di simile a questo è probabilmente quello che si vuole:

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) 

Potete guardare Cython di documentation per maggiori dettagli.