Le problème:Cython: ne peut pas convertir pointeur vers l'objet Python après le module partagé
Error compiling Cython file:
------------------------------------------------------------
...
cpdef Py_GetRemoteDevice(PyChannel Chan):
ret_val = mod_one.PyRemoteDevice()
cdef core.RemoteDevice * tmp
with nogil:
tmp = core.GetRemoteDevice(Chan.__instance)
ret_val.__set_ptr(tmp)
^
------------------------------------------------------------
core/mod_two.pyx:11589:25: Cannot convert 'RemoteDevice *' to Python object
Contexte: J'ai une bibliothèque C assez grand, je suis emballage avec Cython. Initialement, j'ai avait tout dans deux fichiers, core.pyx et core.pxd. Cependant, plus la bibliothèque encapsulée est grande, plus le fichier core.c généré est grand. 2,5 millions de lignes et de comptage. L'heure de compilation et l'utilisation de la mémoire sont devenues lourdes . J'ai décidé de diviser les choses en plusieurs fichiers .pyx. C'est alors que les choses qui ont utilisé ont cessé de fonctionner.
Avertissement: Veuillez garder à l'esprit que j'ai grandement simplifié les choses pour cette question. La bibliothèque encapsulée est assez grande et propriétaire.
Les détails:
core.pxd - contient tous les composants nécessaires à la bibliothèque C
J'emballage. Aussi une simple déclaration de classe wrapper Void *.
cdef class Void:
cdef void *__void
cdef __set_ptr(self, void *ptr)
cdef extern from "core.h":
ctypedef unsigned char U8
ctypedef unsigned int U32
void OS_MemSet(U8 *dest, U8 byte, U32 len) nogil
cdef extern from "mod_one.h":
cdef struct _RemoteDevice
ctypedef _RemoteDevice RemoteDevice
cdef extern from "mod_two.h":
cdef struct _Channel
ctypedef _Channel Channel
core.pyx - pas beaucoup est nécessaire ici, vraiment est juste la mise en œuvre de l'emballage Void *.
cdef class Void:
cdef __set_ptr(self, void *ptr):
self.__void = ptr
mod_one.pxd - déclare la classe wrapper pour le RemoteDevice C struct
cimport core
cdef class PyRemoteDevice:
cdef core.RemoteDevice *__instance
cdef __set_ptr(self, core.RemoteDevice *ptr)
mod_one.pyx - définit la classe wrapper RemoteDevice. Notez la fonction __set_ptr, qui est cdef'd et prend une RemoteDevice *
from cpython.mem cimport PyMem_Malloc, PyMem_Free
import core
cimport core
cdef class PyRemoteDevice:
def __cinit__(self):
self.__instance = <core.RemoteDevice *>PyMem_Malloc(sizeof(core.RemoteDevice))
def __init__(self):
core.OS_MemSet(<core.U8 *>self.__instance, <core.U8>0, sizeof(core.RemoteDevice))
cdef __set_ptr(self, core.RemoteDevice *ptr):
self.__instance = ptr
def __dealloc__(self):
if self.__instance is not NULL:
PyMem_Free(self.__instance)
self.__instance = NULL
mod_two.pxd - déclare la classe wrapper de canal, que je ne montrant ici parce qu'il est utilisé dans la fonction me cause des problèmes.
cimport core
cimport mod_one
cdef class PyChannel:
cdef core.Channel *__instance
cdef __set_ptr(self, core.Channel *ptr)
mod_two.pyx - définit la classe wrapper Channel, et déclare la fonction de Py_GetRemoteDevice, qui enveloppe la fonction GetRemoteDevice de la bibliothèque C.
from cpython.mem cimport PyMem_Malloc, PyMem_Free import core cimport core import mod_one cimport mod_one
cdef class PyChannel:
def __cinit__(self):
self.__instance = <core.Channel *>PyMem_Malloc(sizeof(core.Channel))
def __init__(self):
core.OS_MemSet(<core.U8 *>self.__instance, <core.U8>0, sizeof(core.Channel))
cdef __set_ptr(self, core.Channel *ptr):
self.__instance = ptr
def __dealloc__(self):
if self.__instance is not NULL:
PyMem_Free(self.__instance)
self.__instance = NULL
cpdef Py_GetRemoteDevice(PyChannel Chan):
ret_val = mod_one.PyRemoteDevice()
cdef core.RemoteDevice * tmp
with nogil:
tmp = core.GetRemoteDevice(Chan.__instance)
ret_val.__set_ptr(tmp)
return ret_val
Le problème que je reçois est que lorsque Cythonizing mod_two, je reçois le erreur suivant:
Error compiling Cython file:
------------------------------------------------------------
...
cpdef Py_GetRemoteDevice(PyChannel Chan):
ret_val = mod_one.PyRemoteDevice()
cdef core.RemoteDevice * tmp
with nogil:
tmp = core.GetRemoteDevice(Chan.__instance)
ret_val.__set_ptr(tmp)
^
------------------------------------------------------------
core/mod_two.pyx:11589:25: Cannot convert 'RemoteDevice *' to Python object
Je suis un peu confus, parce que cela utilisé pour travailler quand j'avais tout un module .Une différence que je peux voir est que toutes mes classes wrapper étaient entièrement définies dans core.pyx parce que je n'avais pas besoin de les partager entre les modules. Maintenant, je dois les partager, donc je les ai séparés en fichiers .pyx et .pxd.
Quelqu'un peut-il me diriger dans la bonne direction? J'ai parcouru les docs Cython et Google mais jusqu'ici je n'ai rien trouvé qui réponde à ma question.
Merci, et s'il vous plaît laissez-moi savoir si des informations supplémentaires sont nécessaires!
Vous avez besoin d'une annotation de type sur 'ret_val'? – chrisb
@ chrisb, je me demandais à ce sujet mais je n'ai pas réussi à le faire fonctionner. Probablement parce que je ne suis pas sûr de ce à quoi ça devrait ressembler. J'ai essayé mod_one.PyRemoteDevice ret_val = mod_one.PyRemoteDevice() sans aucune chance. Je vais essayer encore, juste pour être sûr. – rahvin74
Ok, @ chrisb, vous avez raison. Dès que j'ai tapé mon dernier commentaire, j'ai réalisé mon erreur. J'avais besoin de 'cdef' devant ce que j'ai posté en dernier, donc ce serait' cdef mod_one.PyRemoteDevice ret_val = mod_one.PyRemoteDevice() '. Je me sens un peu bête! Si vous faites votre commentaire dans une réponse, je l'accepterai. – rahvin74