title: How do you extend python with C++?
body: <p>I've successfully extended python with C, thanks to <a href="http://www.nevada.edu/~cwebster/Python/MPWHOWTO/xxmodule.c" rel="noreferrer">this handy skeleton module</a>. But I can't find one for C++, and I have circular dependency trouble when trying to fix the errors that C++ gives when I compile this skeleton module.</p>
  
  <p>How do you extend Python with C++?</p>
  
  <p>I'd rather not depend on Boost (or SWIP or other libraries) if I don't have to. Dependencies are a pain in the butt. Best case scenario, I find a skeleton file that already compiles with C++.</p>
  
  <p>Here's the edited skeleton I've made for C++:</p>
  
  <pre><code>#include &lt;Python.h&gt;
  
  #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)-&gt;ob_type == &amp;Flp_Type)
  
  static FlpObject * newFlpObject(PyObject * arg)
  {
      FlpObject * self;
      self = PyObject_NEW(FlpObject, &amp;Flp_Type);
      if (self == NULL)
          return NULL;
      self-&gt;x_attr = NULL;
      return self;
  }
  
  // Flp methods
  
  static void Flp_dealloc(FlpObject * self)
  {
      Py_XDECREF(self-&gt;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-&gt;x_attr != NULL) {
          PyObject * v = PyDict_GetItemString(self-&gt;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-&gt;x_attr == NULL) {
          self-&gt;x_attr = PyDict_New();
          if (self-&gt;x_attr == NULL)
              return -1;
      }
      if (v == NULL) {
          int rv = PyDict_DelItemString(self-&gt;x_attr, name);
          if (rv &lt; 0)
              PyErr_SetString(PyExc_AttributeError,
                      "delete non-existing Flp attribute");
          return rv;
      }
      else
          return PyDict_SetItemString(self-&gt;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", &amp;i, &amp;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", &amp;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#", &amp;a, &amp;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 = &amp;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);
  }
  </code></pre>
  
  <p>This compiles fine for me, but when I test it:</p>
  
  <pre><code>$ 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.
  &gt;&gt;&gt; import flp
  Traceback (most recent call last):
    File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  ImportError: dynamic module does not define init function (initflp)
  &gt;&gt;&gt; 
  </code></pre>