Embedding python in C++, Segmentation fault

末鹿安然 提交于 2019-12-12 01:27:01

问题


I am trying to embed python script in a c++ application. To try out the integration, I made a pilot code:

// c++ code

int main(int argc, char *argv[])
{
    PyObject *pName, *pModule, *pDict, *pFunc, *pValue;

    if (argc < 3) 
    {
        printf("Usage: exe_name python_source function_name\n");
        return 1;
    }

    // Initialize the Python Interpreter
    Py_Initialize();

    // Build the name object
    pName = PyBytes_FromString(argv[1]);
    //std::to_string(argv[1]).encode(

    // Load the module object
    pModule = PyImport_Import(pName);

    // pDict is a borrowed reference 
    pDict = PyModule_GetDict(pModule);

    // pFunc is also a borrowed reference 
    pFunc = PyDict_GetItemString(pDict, argv[2]);

    if (PyCallable_Check(pFunc)) 
    {
        PyObject_CallObject(pFunc, NULL);
    } 
    else 
    {
        PyErr_Print();
    }

    // Clean up
    Py_DECREF(pModule);
    Py_DECREF(pName);

    // Finish the Python Interpreter
    Py_Finalize();

    return 0;
}


# Python script
def multiply():
    c = 12345*6789
    print ('The result of 12345 x 6789 :' + str(c))

I came across the posts that suggest to use boost. Is boost simpler than this? Def of simple: less code, straight forward, largely used by community.

I am interested in these questions because the real code we are going to integrate is pretty complex (because not following the coding ethics), and it needs to communicate with Python code at many times, hence there is synchronization issue as well.


回答1:


It might be easier to use boost::python or the code generated by cython.

The main culprit seems to be the missing

PySys_SetArgv(argc, wargs);

where wargs contains the arguments as wide character strings. Without it, relative imports do not work.

The following code (compiled with gcc, g++ would require some casts in case of malloc()) seems to work.

#include <Python.h>
#include <string.h>

int to_wide_args(wchar_t **argsw[], int argc, char *argv[])
{
    int i;
    size_t len;
    wchar_t *wstr;
    wchar_t **tmp = NULL;
    tmp = malloc(sizeof(wchar_t **) * argc);

    for (i = 0; i < argc; i++) {
        /* In case of python 3.5, see Py_DecodeLocale */
        len = mbstowcs(NULL, argv[i], 0);
        wstr = malloc(sizeof(wchar_t) * (len + 1));
        if (len != mbstowcs(wstr, argv[i], len + 1)) {
            return -1;
        }
        tmp[i] = wstr;
    }
    *argsw = tmp;
    return 0;
}

int main(int argc, char *argv[])
{
    PyObject *dict = 0;
    PyObject *func = 0;
    PyObject *module = 0;

    wchar_t **wargs = NULL;
    int rc = 0;

    if (argc < 3) {
        printf("Usage: exe_name python_source function_name\n");
        return 1;
    }

    if (to_wide_args(&wargs, argc, argv) < 0) goto error;

    Py_SetProgramName(wargs[0]);
    Py_Initialize();
    PySys_SetArgv(argc, wargs);

    if (PyErr_Occurred()) goto error;

    module = PyImport_ImportModule(argv[1]);
    printf("Module ptr: %p\n", module);
    if (module == NULL || PyErr_Occurred()) goto error;

    dict = PyModule_GetDict(module);
    printf("Module dict ptr: %p\n", dict);
    if (dict == NULL || PyErr_Occurred()) goto error;

    func = PyDict_GetItemString(dict, argv[2]);
    printf("Function ptr: %p\n", func);
    if (func == NULL || PyErr_Occurred()) goto error;

    if (PyCallable_Check(func)) {
        PyObject_CallObject(func, NULL);
    } else {
        goto error;
    }
    goto ok;

error:
    PyErr_Print();
    rc = 1;
ok:
    Py_XDECREF(module);
    Py_Finalize();

    return rc;
}


来源:https://stackoverflow.com/questions/38745999/embedding-python-in-c-segmentation-fault

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!