0

From reading another post, I am trying to embbed some some Python code into C:

main.c

#include <Python.h>

int callModuleFunc(int array[], size_t size) {
    PyObject *mymodule = PyImport_ImportModule("py_function");
    PyObject *myfunc = PyObject_GetAttrString(mymodule, "printlist");
    PyObject *mylist = PyList_New(size);
    for (size_t i = 0; i != size; ++i) {
        PyList_SET_ITEM(mylist, i, PyInt_FromLong(array[i]));
    }
    PyObject *arglist = Py_BuildValue("(o)", mylist);
    PyObject *result = PyObject_CallObject(myfunc, arglist);
    int retval = (int)PyInt_AsLong(result);
    Py_DECREF(result);
    Py_DECREF(arglist);
    Py_DECREF(mylist);
    Py_DECREF(myfunc);
    Py_DECREF(mymodule);
    return retval;
}

int main(int argc, char *argv[])
{
    int a[] = {1,2,3,4};
    callModuleFunc(a, 4);
    return 0;
}

py_function.py

'''py_function.py - Python source designed to '''
'''demonstrate the use of python embedding'''

def printlist(mylist):
    print mylist

Then I compiled with:

gcc main.c -I/usr/include/python2.7 -lpython2.7

But then I ran the app, it gives me a segmentation fault error:

/a.out
[1]    18890 segmentation fault  ./a.out

Is there something that I am missing?

Community
  • 1
  • 1
FacundoGFlores
  • 7,858
  • 12
  • 64
  • 94
  • You assign a whole bunch of pointers from the return values of function calls, but don't check any of them for validity before using them. You may also be mixing up types - do you get any compilation warnings? (Though in C even the lack of such does not imply there are no such problems) You might also consider running your program under a debugger, and then using the backtrace command or whatever your debugger calls it to examine the stack and see where the failure occurred. – Chris Stratton Jun 07 '16 at 20:05

1 Answers1

4

There were several problems with your code:

  1. Py_Initialize() was not called.
  2. PyImport_ImportModule() failed to find your python file, since in embedded Python you start without an initial module, relative to which the search can work. The fix is to explicitly include the current directory in sys.path.
  3. "(O)" in Py_BuildValue() should use a capital 'O'.
  4. The printlist function should return a value (since that is what the C-code expects).

This should work:

main.c

#include <Python.h>

void initPython()
{
    Py_Initialize();
    PyObject *sysmodule = PyImport_ImportModule("sys");
    PyObject *syspath = PyObject_GetAttrString(sysmodule, "path");
    PyList_Append(syspath, PyString_FromString("."));
    Py_DECREF(syspath);
    Py_DECREF(sysmodule);
}

int callModuleFunc(int array[], size_t size) {
    PyObject *mymodule = PyImport_ImportModule("py_function");
    assert(mymodule != NULL);
    PyObject *myfunc = PyObject_GetAttrString(mymodule, "printlist");
    assert(myfunc != NULL);
    PyObject *mylist = PyList_New(size);
    for (size_t i = 0; i != size; ++i) {
        PyList_SET_ITEM(mylist, i, PyInt_FromLong(array[i]));
    }
    PyObject *arglist = Py_BuildValue("(O)", mylist);
    assert(arglist != NULL);
    PyObject *result = PyObject_CallObject(myfunc, arglist);
    assert(result != NULL);
    int retval = (int)PyInt_AsLong(result);
    Py_DECREF(result);
    Py_DECREF(arglist);
    Py_DECREF(mylist);
    Py_DECREF(myfunc);
    Py_DECREF(mymodule);
    return retval;
}

int main(int argc, char *argv[])
{
    initPython();

    int a[] = {1,2,3,4,5,6,7};
    callModuleFunc(a, 4);
    callModuleFunc(a+2, 5);

    Py_Finalize();
    return 0;
}

py_function.py

'''py_function.py - Python source designed to '''
'''demonstrate the use of python embedding'''

def printlist(mylist):
    print mylist
    return 0
Leon
  • 31,443
  • 4
  • 72
  • 97
  • Hello Leon, it works. Now, I tried to add numpy to in the python source, but it gives me: ` main.c:18: callModuleFunc: Assertion `mymodule != ((void *)0)' failed`. Do you know what I have to do with my C code when I import other libraries in Python? – FacundoGFlores Jun 08 '16 at 13:15
  • 1
    Did you `import numpy` in `py_function.py`? Does it work without problem when you run `py_function.py` with python directly? If so, then the problem is likely to be fixed by correctly populating `sys.path`. – Leon Jun 08 '16 at 13:31
  • The python module works correctly outside my C program. What do you mean by "correctly populating sys.path"? I see the following example: https://github.com/Frogee/PythonCAPI_testing/blob/master/testEmbed.cpp and the he appears not putting anything else but the "sys" module as you put it in the example above. – FacundoGFlores Jun 08 '16 at 19:29
  • 1
    My initial solution contained the same fault as in http://stackoverflow.com/questions/7624529/python-c-api-doesnt-load-module . I fixed it as per the [answer](http://stackoverflow.com/a/8859538/6394138) to that question. – Leon Jun 09 '16 at 04:27
  • I put the new code you have edited (the new initPython function), but when I run the following: `def printlist(mylist): import numpy as np a = np.array(mylyst, dtype=np.float32) print a` it also fails: `a.out: main.c:25: callModuleFunc: Assertion result != ((void *)0)' failed.` – FacundoGFlores Jun 09 '16 at 16:39
  • 1
    I think you misspelled `mylist` in `np.array(mylyst, dtype=np.float32)`. Please test your python code in regular python environment, before trying it in embedded python environment. – Leon Jun 09 '16 at 17:41