2010-01-20 4 views
16

Je suis nouveau sur Cython et j'essaye d'utiliser Cython pour envelopper une bibliothèque statique C/C++. J'ai fait un exemple simple comme suit.Enveloppez C++ lib avec 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; 
} 

J'ai ensuite utilisé g ++ pour compiler et construire.

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

J'ai maintenant une bibliothèque statique appelée 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 
) 

Le j'ai appelé:

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

La sortie était:

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[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 

J'ai également essayé d'utiliser libraries = ['test'] au lieu de libraries = ['libtest']. Cela m'a donné les mêmes erreurs.

Des indices à ce sujet?

Merci!

Répondre

2

Je pense que vous pouvez résoudre ce problème spécifique en spécifiant le droit library_dirs (où vous avez réellement mis libtest.a - apparemment, il ne se trouve est), mais je pense que vous aurez un autre problème - votre entrée les points ne sont pas correctement déclarés comme extern "C", donc les noms de la fonction auront été "mutilés" par le compilateur C++ (regardez les noms exportés de votre libtest.a et vous verrez!), donc tout autre langage sauf C++ (y compris C , Cython, etc.) auront du mal à les atteindre. Le correctif consiste à les déclarer comme extern "C".

+0

Où devrais-je déclarer extern "C"?Cependant, je pense que le problème est maintenant que la construction se plaint, elle ne peut pas trouver libtest.a au lieu de l'une de la fonction, c'est-à-dire add() ou mulitpy(). Donc, je ne suis pas sûr que cela fonctionnera. Il est assez bizarre pour moi qu'il se plaint qu'il n'y ait pas libtest.a dans 'build \ temp.win32-2.6 \ Release'. N'est-ce pas le dossier de construction généré par Cython lui-même? Pourquoi Cython a-t-il cherché la libtest.a là? –

+0

'extern" C "' va dans les déclarations des fonctions dans le '.h', et comme je l'ai dit c'est le prochain problème que vous rencontrerez après avoir corrigé le' library_dirs' incorrect (vous dites que les bibliothèques sont "dans le répertoire courant "et le' Release' se trouve être le répertoire courant au moment où le compilateur/éditeur de liens recherche la bibliothèque). –

23

Si votre code C++ est utilisé uniquement par l'emballage, une autre option est de laisser la configuration compiler votre fichier .cpp, comme ceci:

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 
) 

Pour lier à une bibliothèque statique, vous devez utiliser le extra_objects l'argument dans votre 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

Non, j'ai fait 'test.cpp' uniquement pour les tests. Dans le vrai projet, j'ai seulement un fichier head et une bibliothèque statique. –

+3

Il semble que ce que vous voulez est l'option 'extra_objects', la réponse éditée. –

+0

@zyq Alors, comment pouvons-nous continuer une fois que le fichier .so a été créé? – PascalVKooten

4

votre fichier Test.pyx ne fait pas ce que vous attendez. La ligne print add(2,3)ne appelez la fonction C++ add(); vous devez explicitement créer une fonction wrapper pour le faire. Cython ne crée pas de wrappers automatiquement pour vous.

Quelque chose comme ceci est probablement ce que vous voulez:

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) 

Vous pouvez regarder documentation de Cython pour plus de détails.