Quindi dopo un sacco di tentativi, tentativi ed errori, urlando e strappandomi i capelli, finalmente ho fatto in modo che funzionasse. Per prima cosa, ho dovuto riscrivere il mio C++ in C, che per me ha davvero coinvolto solo la conversione di tutte le mie variabili std::string
in char*
e di tenere traccia di alcune lunghezze.
Una volta terminato, avevo i file .h e .c. Volevo creare una singola funzione dal codice C disponibile in Python. Si scopre che Cython può compilare i tuoi file C nell'estensione per te e collegare tutte le librerie tutto in una volta, quindi a partire dalla mia configurazione.py, ha finito per assomigliare a questo:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules=[
Extension("myext",
["myext.pyx", "../stuff.c"],
libraries=["ssl", "crypto"]
)
]
setup(
name = "myext",
cmdclass = {"build_ext": build_ext},
ext_modules = ext_modules
)
Come si può vedere, il secondo argomento per l'estensione elenca semplicemente tutti i file che devono essere compilati, Cython funziona come compilare loro a seconda della loro estensione, per quanto posso dire. L'array di librerie dice al compilatore di Cython ciò che deve essere collegato (in questo caso stavo avvolgendo alcune cose crittografiche che non riuscivo a imitare direttamente attraverso le librerie Python esistenti).
Per rendere effettivamente disponibile la mia funzione C nel file .pyx, si scrive un piccolo wrapper in .pxd. Il mio myext.pxd sembrava come di seguito:
cdef extern from "../stuff.h":
char* myfunc(char* arg1, char* arg2, char* arg3)
Nella .pyx quindi si utilizza la dichiarazione cimport di importare questa funzione, che è quindi disponibile per l'uso, come se si trattasse di qualsiasi altra funzione Python:
cimport myext
def my_python_func(arg1, arg2, arg3):
result = myext.myfunc(arg1, arg2, arg3)
return result
Quando lo costruisci (almeno su Mac) ottieni un .so che puoi importare in python ed eseguire le funzioni da .pyx. Potrebbe esserci un modo migliore, più corretto, per far funzionare tutto questo, ma che deriva dall'esperienza e questo è stato il primo incontro che sono riuscito a risolvere. Sarei molto interessato a puntatori in cui potrei aver sbagliato.
Aggiornamento:
Dopo ulteriore utilizzo di Cython, ho scoperto che era super semplice da integrare con C++ troppo, una volta che sai quello che stai facendo. Rendere disponibile il string
di C++ è semplice come from libcpp.string cimport string
nella tua pyx/pyd. Dichiarare la classe C++ è analogamente semplice come:
cdef extern from "MyCPPClass.h":
cdef cppclass MyCPPClass:
int foo;
string bar;
Certo bisogna ridichiarare fondamentalmente la definizione .h della classe in un formato Pythonic, ma questo è un piccolo prezzo da pagare per ottenere l'accesso alle funzioni già scritto in C++ .
Se la tua domanda ha avuto risposta, segna questa domanda come risposta. Altrimenti, specifica di nuovo la tua domanda. –
@NiklasR La tua risposta ha coperto alcune delle mie aree di confusione ma non mi ha fatto arrivare fino in fondo. Ti ho dato un voto ma intendevo scrivere una risposta completa degli altri bit che ho elaborato quando ho un po 'di tempo libero. – Endophage