Search code examples
cpython-3.xsetuptoolspython-extensions

Compiling python3 C extensions


I wrote the following code for my CPython extension :

#include <Python.h>
static PyObject *greeting(PyObject* self)
{
        return Py_BuildValue("s" , "Hello python modules!!!");
}

static char *my_docstring = "This is a sample docstring";

static PyMethodDef greeting_funcs[] = {
    {"greeting" , (PyCFunction)greeting , METH_NOARGS , my_docstring} , {NULL}
};

void initModule(void){
    Py_InitModule3("greeting" , greeting_funcs , "Module example!!!");
}

And when I execute the following in IPython3 shell

from setuptools import setup , Extension
modules = [Extension('mod', sources=["/home/spm/python_module/mod.c"])] 
setup(ext_modules=modules) 

I get the error :

SystemExit: usage: ipython3 [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts]
or: ipython3 --help [cmd1 cmd2 ...]
or: ipython3 --help-commands
or: ipython3 cmd --help

error: no commands supplied

Any help is appreciated.
Thanks.


Solution

  • First of all, your mod.c won't compile. Py_InitModule3 is removed in Python 3; you have to create a PyModuleDef struct and add an init function named PyInit_{library name} that passes the PyModuleDef reference to PyModule_Create to initialize the module:

    #include <Python.h>
    #define MY_DOCSTRING "This is a sample docstring"
    
    static PyObject *greeting(PyObject* self)
    {
        return Py_BuildValue("s" , "Hello python modules!!!");
    }
    
    static PyMethodDef greeting_funcs[] = {
        {"greeting" , (PyCFunction)greeting , METH_NOARGS , MY_DOCSTRING} , {NULL}
    };
    
    
    // python module definition
    static struct PyModuleDef greetingModule = {
        PyModuleDef_HEAD_INIT, "greeting", "Module example!!!", -1, greeting_funcs
    };
    
    // register module namespace
    PyMODINIT_FUNC PyInit_mod(void)
    {
        PyObject *module;
    
        module = PyModule_Create(&greetingModule);
        if (module == NULL)
            return NULL;
    
        return module;
    }
    

    And when I execute the following in IPython3 shell I get the error

    This code is usually not invoked from IPython. It is put in a script named setup.py and then executed from terminal, supplying the tasks the setup function should invoke, e.g.

    $ python setup.py build_ext --inplace
    

    to build the extension module and place it into current directory.

    Of course, you can mimic this in IPython too:

    In [1]: import sys                                                                                                                                                                                                 
    
    In [2]: sys.argv.extend(["build_ext", "--inplace"])                                                                                                                                                                
    
    In [3]: from setuptools import setup, Extension                                                                                                                                                                    
    
    In [4]: modules = [Extension('mod', sources=["mod.c"])]                                                                                                                                                            
    
    In [5]: setup(ext_modules=modules)                                                                                                                                                                                 
    running build_ext
    ...
    
    In [6]: sys.argv = sys.argv[:1]
    

    However, a better solution is to write the setup code into the setup.py script. You can then execute it in IPython via the %run magic:

    In [1]: %run setup.py build_ext --inplace                                                                                                                                                                          
    running build_ext
    building 'mod' extension
    ...