问题
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