2010-05-17 5 views
18

मैंने सफलतापूर्वक सी के साथ पायथन बढ़ाया है, this handy skeleton module के लिए धन्यवाद। लेकिन मुझे सी ++ के लिए कोई नहीं मिल रहा है, और जब मैं इस कंकाल मॉड्यूल को संकलित करता हूं तो त्रुटियों को ठीक करने का प्रयास करते समय मेरे पास सर्कुलर निर्भरता समस्या होती है।आप सी ++ के साथ पायथन कैसे बढ़ाते हैं?

आप सी ++ के साथ पायथन कैसे बढ़ाते हैं?

यदि मुझे ऐसा करने की ज़रूरत नहीं है तो मैं बूस्ट (या एसडब्ल्यूआईपी या अन्य पुस्तकालयों) पर निर्भर नहीं हूं। निर्भरता बट में दर्द है। सबसे अच्छा मामला परिदृश्य, मुझे एक कंकाल फ़ाइल मिलती है जो पहले ही सी ++ के साथ संकलित है।

यहाँ संपादित कंकाल मैं सी के लिए ++ बनाया गया है:

#include <Python.h> 

#include "Flp.h" 

static PyObject * ErrorObject; 

typedef struct { 
    PyObject_HEAD 
    PyObject * x_attr; // attributes dictionary 
} FlpObject; 

static void Flp_dealloc(FlpObject * self); 
static PyObject * Flp_getattr(FlpObject * self, char * name); 
static int Flp_setattr(FlpObject * self, char * name, PyObject * v); 
DL_EXPORT(void) initflp(); 

static PyTypeObject Flp_Type = { 
    /* The ob_type field must be initialized in the module init function 
    * to be portable to Windows without using C++. */ 
    PyObject_HEAD_INIT(NULL) 
    0,   /*ob_size*/ 
    "Flp",   /*tp_name*/ 
    sizeof(FlpObject), /*tp_basicsize*/ 
    0,   /*tp_itemsize*/ 
    /* methods */ 
    (destructor)Flp_dealloc, /*tp_dealloc*/ 
    0,   /*tp_print*/ 
    (getattrfunc)Flp_getattr, /*tp_getattr*/ 
    (setattrfunc)Flp_setattr, /*tp_setattr*/ 
    0,   /*tp_compare*/ 
    0,   /*tp_repr*/ 
    0,   /*tp_as_number*/ 
    0,   /*tp_as_sequence*/ 
    0,   /*tp_as_mapping*/ 
    0,   /*tp_hash*/ 
}; 

#define FlpObject_Check(v) ((v)->ob_type == &Flp_Type) 

static FlpObject * newFlpObject(PyObject * arg) 
{ 
    FlpObject * self; 
    self = PyObject_NEW(FlpObject, &Flp_Type); 
    if (self == NULL) 
     return NULL; 
    self->x_attr = NULL; 
    return self; 
} 

// Flp methods 

static void Flp_dealloc(FlpObject * self) 
{ 
    Py_XDECREF(self->x_attr); 
    PyMem_DEL(self); 
} 

static PyObject * Flp_demo(FlpObject * self, PyObject * args) 
{ 
    if (! PyArg_ParseTuple(args, "")) 
     return NULL; 
    Py_INCREF(Py_None); 
    return Py_None; 
} 

static PyMethodDef Flp_methods[] = { 
    {"demo", (PyCFunction)Flp_demo, 1}, 
    {NULL,  NULL} // sentinel 
}; 

static PyObject * Flp_getattr(FlpObject * self, char * name) 
{ 
    if (self->x_attr != NULL) { 
     PyObject * v = PyDict_GetItemString(self->x_attr, name); 
     if (v != NULL) { 
      Py_INCREF(v); 
      return v; 
     } 
    } 
    return Py_FindMethod(Flp_methods, (PyObject *)self, name); 
} 

static int Flp_setattr(FlpObject * self, char * name, PyObject * v) 
{ 
    if (self->x_attr == NULL) { 
     self->x_attr = PyDict_New(); 
     if (self->x_attr == NULL) 
      return -1; 
    } 
    if (v == NULL) { 
     int rv = PyDict_DelItemString(self->x_attr, name); 
     if (rv < 0) 
      PyErr_SetString(PyExc_AttributeError, 
        "delete non-existing Flp attribute"); 
     return rv; 
    } 
    else 
     return PyDict_SetItemString(self->x_attr, name, v); 
} 
/* --------------------------------------------------------------------- */ 

/* Function of two integers returning integer */ 

static PyObject * flp_foo(PyObject * self, PyObject * args) 
{ 
    long i, j; 
    long res; 
    if (!PyArg_ParseTuple(args, "ll", &i, &j)) 
     return NULL; 
    res = i+j; /* flpX Do something here */ 
    return PyInt_FromLong(res); 
} 


/* Function of no arguments returning new Flp object */ 

static PyObject * flp_new(PyObject * self, PyObject * args) 
{ 
    FlpObject *rv; 

    if (!PyArg_ParseTuple(args, "")) 
     return NULL; 
    rv = newFlpObject(args); 
    if (rv == NULL) 
     return NULL; 
    return (PyObject *)rv; 
} 

/* Example with subtle bug from extensions manual ("Thin Ice"). */ 

static PyObject * flp_bug(PyObject * self, PyObject * args) 
{ 
    PyObject *list, *item; 

    if (!PyArg_ParseTuple(args, "O", &list)) 
     return NULL; 

    item = PyList_GetItem(list, 0); 
    /* Py_INCREF(item); */ 
    PyList_SetItem(list, 1, PyInt_FromLong(0L)); 
    PyObject_Print(item, stdout, 0); 
    printf("\n"); 
    /* Py_DECREF(item); */ 

    Py_INCREF(Py_None); 
    return Py_None; 
} 

/* Test bad format character */ 

static PyObject * flp_roj(PyObject * self, PyObject * args) 
{ 
    PyObject *a; 
    long b; 
    if (!PyArg_ParseTuple(args, "O#", &a, &b)) 
     return NULL; 
    Py_INCREF(Py_None); 
    return Py_None; 
} 


/* List of functions defined in the module */ 

static PyMethodDef flp_methods[] = { 
    {"roj",  flp_roj,  1}, 
    {"foo",  flp_foo,  1}, 
    {"new",  flp_new,  1}, 
    {"bug",  flp_bug,  1}, 
    {NULL,  NULL}  /* sentinel */ 
}; 


/* Initialization function for the module (*must* be called initflp) */ 

DL_EXPORT(void) initflp() 
{ 
    PyObject *m, *d; 

    /* Initialize the type of the new type object here; doing it here 
    * is required for portability to Windows without requiring C++. */ 
    Flp_Type.ob_type = &PyType_Type; 

    /* Create the module and add the functions */ 
    m = Py_InitModule("flp", flp_methods); 

    /* Add some symbolic constants to the module */ 
    d = PyModule_GetDict(m); 
    ErrorObject = PyErr_NewException("flp.error", NULL, NULL); 
    PyDict_SetItemString(d, "error", ErrorObject); 
} 

यह मेरे लिए ठीक संकलित, लेकिन जब मैं यह परीक्षण:

$ python 
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41) 
[GCC 4.4.3] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import flp 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ImportError: dynamic module does not define init function (initflp) 
>>> 
+2

शायद आप कह सकते हैं कि आप सी ++ के साथ कौन सी त्रुटियां प्राप्त कर रहे हैं - समाधान कुछ समझदार रूप से 'बाहरी' सी ''के रूप में सरल हो सकता है। –

+0

यह एक अच्छा विचार है। – andrewrk

+0

क्या SWIG सिर्फ इसके लिए डिज़ाइन नहीं किया गया है? – rossipedia

उत्तर

13

सबसे पहले, भले ही आप अतिरिक्त निर्भरता पेश नहीं करना चाहते हैं, मैं आपको PyCXX पर एक नज़र डालने का सुझाव देता हूं। अपने वेबपृष्ठ का उद्धरण:

CXX/ऑब्जेक्ट्स पाइथन एक्सटेंशन लिखना आसान बनाने के लिए सी ++ सुविधाओं का एक सेट है। मुख्य तरीका जिसमें पीईसीईओक्स पाइथन एक्सटेंशन लिखना आसान बनाता है, यह संभावना है कि आपका प्रोग्राम संदर्भ-गिनती त्रुटि नहीं करेगा और उसे पाइथन सी एपीआई से लगातार त्रुटि रिटर्न की जांच नहीं करनी पड़ेगी। CXX/ऑब्जेक्ट्स इन तरीकों से सी ++ के साथ पायथन को एकीकृत करता है:

  • सी ++ अपवाद हैंडलिंग त्रुटियों का पता लगाने और साफ करने के लिए निर्भर है। एक जटिल कार्य में यह अक्सर सीसी में लिखते समय एक जबरदस्त समस्या होती है। पीईसीईसीओ के साथ, हम संकलक को ट्रैक करते हैं कि त्रुटि होने पर किस ऑब्जेक्ट को संदर्भित किया जाना चाहिए।
  • मानक टेम्पलेट लाइब्रेरी (एसटीएल) और इसके कई एल्गोरिदम प्लग और पाइथन कंटेनर जैसे सूचियों और टुपल्स के साथ खेलते हैं।
  • वैकल्पिक CXX/एक्सटेंशन सुविधा आपको ऑब्जेक्ट्स और विधि कॉल के साथ बेकार सी टेबल को प्रतिस्थापित करने की अनुमति देती है जो आपके मॉड्यूल और एक्सटेंशन ऑब्जेक्ट को परिभाषित करती है।

मुझे लगता है कि PyCXX BSD लाइसेंस, जिसका मतलब है कि आप बस के रूप में अच्छी अपने विस्तार के वितरित टारबॉल में PyCXX की पूरी स्रोत कोड आपके एक्सटेंशन में एक समान लाइसेंस के तहत जारी किया जाएगा शामिल कर सकते हैं अंतर्गत लाइसेंस प्राप्त है ।

तुम सच में और पूरी तरह से PyCXX या किसी अन्य तृतीय-पक्ष लाइब्रेरी पर निर्भर नहीं करना चाहते हैं, तो मुझे लगता है कि आप केवल wrap कार्यों कि extern "C" { और } में अजगर दुभाषिया द्वारा बुलाया जाएगा नाम mangling से बचने के लिए किया है।

#include <Python.h> 

#include "Flp.h" 

static PyObject * ErrorObject; 

typedef struct { 
    PyObject_HEAD 
    PyObject * x_attr; // attributes dictionary 
} FlpObject; 

extern "C" { 
    static void Flp_dealloc(FlpObject * self); 
    static PyObject * Flp_getattr(FlpObject * self, char * name); 
    static int Flp_setattr(FlpObject * self, char * name, PyObject * v); 
    DL_EXPORT(void) initflp(); 
} 

static PyTypeObject Flp_Type = { 
    /* The ob_type field must be initialized in the module init function 
    * to be portable to Windows without using C++. */ 
    PyObject_HEAD_INIT(NULL) 
    0,   /*ob_size*/ 
    "Flp",   /*tp_name*/ 
    sizeof(FlpObject), /*tp_basicsize*/ 
    0,   /*tp_itemsize*/ 
    /* methods */ 
    (destructor)Flp_dealloc, /*tp_dealloc*/ 
    0,   /*tp_print*/ 
    (getattrfunc)Flp_getattr, /*tp_getattr*/ 
    (setattrfunc)Flp_setattr, /*tp_setattr*/ 
    0,   /*tp_compare*/ 
    0,   /*tp_repr*/ 
    0,   /*tp_as_number*/ 
    0,   /*tp_as_sequence*/ 
    0,   /*tp_as_mapping*/ 
    0,   /*tp_hash*/ 
}; 

#define FlpObject_Check(v) ((v)->ob_type == &Flp_Type) 

static FlpObject * newFlpObject(PyObject * arg) 
{ 
    FlpObject * self; 
    self = PyObject_NEW(FlpObject, &Flp_Type); 
    if (self == NULL) 
     return NULL; 
    self->x_attr = NULL; 
    return self; 
} 

// Flp methods 

static void Flp_dealloc(FlpObject * self) 
{ 
    Py_XDECREF(self->x_attr); 
    PyMem_DEL(self); 
} 

static PyObject * Flp_demo(FlpObject * self, PyObject * args) 
{ 
    if (! PyArg_ParseTuple(args, "")) 
     return NULL; 
    Py_INCREF(Py_None); 
    return Py_None; 
} 

static PyMethodDef Flp_methods[] = { 
    {"demo", (PyCFunction)Flp_demo, 1}, 
    {NULL,  NULL} // sentinel 
}; 

static PyObject * Flp_getattr(FlpObject * self, char * name) 
{ 
    if (self->x_attr != NULL) { 
     PyObject * v = PyDict_GetItemString(self->x_attr, name); 
     if (v != NULL) { 
      Py_INCREF(v); 
      return v; 
     } 
    } 
    return Py_FindMethod(Flp_methods, (PyObject *)self, name); 
} 

static int Flp_setattr(FlpObject * self, char * name, PyObject * v) 
{ 
    if (self->x_attr == NULL) { 
     self->x_attr = PyDict_New(); 
     if (self->x_attr == NULL) 
      return -1; 
    } 
    if (v == NULL) { 
     int rv = PyDict_DelItemString(self->x_attr, name); 
     if (rv < 0) 
      PyErr_SetString(PyExc_AttributeError, 
        "delete non-existing Flp attribute"); 
     return rv; 
    } 
    else 
     return PyDict_SetItemString(self->x_attr, name, v); 
} 
/* --------------------------------------------------------------------- */ 

/* Function of two integers returning integer */ 

static PyObject * flp_foo(PyObject * self, PyObject * args) 
{ 
    long i, j; 
    long res; 
    if (!PyArg_ParseTuple(args, "ll", &i, &j)) 
     return NULL; 
    res = i+j; /* flpX Do something here */ 
    return PyInt_FromLong(res); 
} 


/* Function of no arguments returning new Flp object */ 

static PyObject * flp_new(PyObject * self, PyObject * args) 
{ 
    FlpObject *rv; 

    if (!PyArg_ParseTuple(args, "")) 
     return NULL; 
    rv = newFlpObject(args); 
    if (rv == NULL) 
     return NULL; 
    return (PyObject *)rv; 
} 

/* Example with subtle bug from extensions manual ("Thin Ice"). */ 

static PyObject * flp_bug(PyObject * self, PyObject * args) 
{ 
    PyObject *list, *item; 

    if (!PyArg_ParseTuple(args, "O", &list)) 
     return NULL; 

    item = PyList_GetItem(list, 0); 
    /* Py_INCREF(item); */ 
    PyList_SetItem(list, 1, PyInt_FromLong(0L)); 
    PyObject_Print(item, stdout, 0); 
    printf("\n"); 
    /* Py_DECREF(item); */ 

    Py_INCREF(Py_None); 
    return Py_None; 
} 

/* Test bad format character */ 

static PyObject * flp_roj(PyObject * self, PyObject * args) 
{ 
    PyObject *a; 
    long b; 
    if (!PyArg_ParseTuple(args, "O#", &a, &b)) 
     return NULL; 
    Py_INCREF(Py_None); 
    return Py_None; 
} 


/* List of functions defined in the module */ 

static PyMethodDef flp_methods[] = { 
    {"roj",  flp_roj,  1}, 
    {"foo",  flp_foo,  1}, 
    {"new",  flp_new,  1}, 
    {"bug",  flp_bug,  1}, 
    {NULL,  NULL}  /* sentinel */ 
}; 


/* Initialization function for the module (*must* be called initflp) */ 

DL_EXPORT(void) initflp() 
{ 
    PyObject *m, *d; 

    /* Initialize the type of the new type object here; doing it here 
    * is required for portability to Windows without requiring C++. */ 
    Flp_Type.ob_type = &PyType_Type; 

    /* Create the module and add the functions */ 
    m = Py_InitModule("flp", flp_methods); 

    /* Add some symbolic constants to the module */ 
    d = PyModule_GetDict(m); 
    ErrorObject = PyErr_NewException("flp.error", NULL, NULL); 
    PyDict_SetItemString(d, "error", ErrorObject); 
} 
+0

इसके अलावा, मुझे 'PyMemject_FREE (self) 'में dealloc फ़ंक्शन में' PyMem_DEL (self);' बदलना पड़ा; संभवतः इससे संबंधित है? https://bugs.launchpad.net/ubuntu/feisty/+source/python-fam/+bug/115655 – andrewrk

1

क्या Boost::Python के बारे में?

संपादित करें: क्षमा करें, मैंने देखा कि आप बूस्ट पर निर्भर नहीं रहना चाहते हैं, लेकिन मुझे लगता है कि यह अभी भी सबसे अच्छे विकल्पों में से एक हो सकता है।

5

उपयोग extern सी सभी कार्य ऐसे नाम हैं जो अजगर से कहा जाता हो रैप करने के लिए:

यहाँ को सही कोड है। चूंकि सी ++ कंपाइलर्स 'नाम मैंगलिंग' नामक कुछ का उपयोग करते हैं (ओवरलोडिंग से निपटने के लिए आवश्यक), पायथन सी ++ पुस्तकालयों को पढ़ नहीं सकता है।लेकिन बाहरी सी आपकी समस्याओं का समाधान करेगा। इसे इस तरह करें:

 
// most of your code can go whereever 
void cpp_function() {} 
extern "C" { 
    // all functions that python calls directly must go in here 
    void python_function() {} 
} 

अतिरिक्त सुनिश्चित करें कि आप बाहरी ब्लॉक के अंदर प्रत्येक फ़ंक्शन पायथन की ज़रूरतें हैं। आप अभी भी फ़ंक्शंस के अंदर सी ++ फीचर्स का उपयोग कर सकते हैं, यह सिर्फ इतना है कि नाम 'नाम मैंगलिंग' के बिना निर्यात किए जाएंगे।

संबंधित मुद्दे