在c ++中嵌入python,在“import shutil”上崩溃

时间:2016-09-03 09:47:20

标签: python c++ python-2.7 embed

我有一个关于在c ++中嵌入python的完整示例。我在Linux上针对Python 2.7编译/链接它。

它需要一个参数(文件名),然后加载并执行。

这一切基本上都有效,但如果在代码中有: import shutils

然后执行代码失败并出现总线错误。

这似乎与潜在的“进口馆藏”有关。

当我将它作为python脚本执行时,我加载的代码正常运行。

是否有人提示为什么代码会崩溃?代码由几个示例组成,通常可以正常工作。

这是C ++代码:

#include "Python.h" // must be first
#include "structmember.h"

#include <stdio.h>
#include <stdlib.h>

#define QWE printf("%s %i\n", __FUNCTION__, __LINE__);


#define LIBPY_NAMESPACE "app"
#define LIBPY_TYPE  "App"
#define LIBPY_FQTYPE  LIBPY_NAMESPACE "." LIBPY_TYPE


static PyObject* globals;
static PyObject* locals;

static PyObject* mod;
static PyObject* app_class;

static PyObject* AppError;


typedef struct {
  PyObject_HEAD

} AppObject;


static PyObject* app_func1(AppObject* self, PyObject* args)
{
  PyObject* ret;
  int p1, p2;

  if(PyArg_ParseTuple(args, "dd", &p1, &p2)) {
    //    try {

      ret = Py_BuildValue("(i,i,i,i)", 13, 17, 19, 11 + p1 + p2);

      return ret;
      /*
    }
    catch(RiException& e) {
      PyErr_SetString(RiError, e.what());
    }
      */
  }

  return NULL;
}


static PyObject* app_func2(AppObject* self, PyObject* args)
{
  PyObject* ret;

  ret = Py_BuildValue("(i,i,i,i)", 4, 13, 17, 19);

  return ret;
}


static PyObject* app_filename(AppObject* self, PyObject* args)
{
  PyObject* ret;
  const char* c = "a filename";

  //  ret = Py_BuildValue("(i,i,i,i)", 4, 13, 17, 19);
  ret = Py_BuildValue("s", c);

  return ret;
}


static PyMethodDef app_global_methods[] = {
  {"filename", (PyCFunction)app_filename, METH_VARARGS, "an example for a global function"},
  // get file name

  {NULL, NULL, 0, NULL}
};


static PyMethodDef app_methods[] = {
  {"func1", (PyCFunction)app_func1, METH_VARARGS, "a test function 1."},
  {"func2", (PyCFunction)app_func2, METH_NOARGS, "a test function 2."}
};


static PyMemberDef app_members[] = {
  //  {"width", T_INT, offsetof(RiMem, w), 0, ""},
  {NULL}
};


static PyObject* app_repr(PyObject* par) {
  AppObject* self = (AppObject*)par;

  return PyString_FromFormat("<%s  %i>", "wx Application", 4);
}


static PyObject* app_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
  AppObject *self;

  QWE;
  self = (AppObject *)type->tp_alloc(type, 0);
  if(self != NULL) {
    //    self->app = NULL;
  }

  return (PyObject *)self;
}


static int app_init(AppObject* self, PyObject* args, PyObject* kwds) {
  //  self->app = m_app;

  QWE;
  PyErr_Clear();

  //  PyErr_SetString(RiError, "some error happened");

  return 0;
}


static void app_dealloc(AppObject* self) {
  QWE;
  /*  if(self->app != NULL) {
    // delete the app

    self->app = NULL;
    } */

  self->ob_type->tp_free((PyObject*)self);
}


static PyTypeObject AppType = {
  PyObject_HEAD_INIT(NULL)

  0, /*ob_size*/
  LIBPY_FQTYPE, /*tp_name*/
  sizeof(AppObject), /*tp_basicsize*/
  0, /*tp_itemsize*/
  (destructor)app_dealloc, /*tp_dealloc*/
  0, /*tp_print*/
  0, /*tp_getattr*/
  0, /*tp_setattr*/
  0, /*tp_compare*/
  app_repr, /*tp_repr*/
  0, /*tp_as_number*/
  0, /*tp_as_sequence*/
  0, /*tp_as_mapping*/
  0, /*tp_hash */
  0, /*tp_call*/
  0, /*tp_str*/
  0, /*tp_getattro*/
  0, /*tp_setattro*/
  0, /*tp_as_buffer*/
  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
  "An example application", /* tp_doc */
  0, /* tp_traverse */
  0, /* tp_clear */
  0, /* tp_richcompare */
  0, /* tp_weaklistoffset */
  0, /* tp_iter */
  0, /* tp_iternext */
  app_methods, /* tp_methods */
  app_members, /* tp_members */
  0, /* tp_getset */
  0, /* tp_base */
  0, /* tp_dict */
  0, /* tp_descr_get */
  0, /* tp_descr_set */
  0, /* tp_dictoffset */
  (initproc)app_init, /* tp_init */
  0, /* tp_alloc */
  app_new, /* tp_new */
};


void init_py(void) {
  Py_SetProgramName("qwe");
  Py_Initialize();

#if 0
  globals = PyDict_New();
  PyDict_SetItemString(globals, "__builtins__", PyEval_GetBuiltins());
#else
  globals = PyModule_GetDict(PyImport_AddModule("__main__"));
#endif

  printf("globals %p\n", globals);

  /*  if (PyType_Ready(&AppType) < 0) {
    return;
    } */

  mod = Py_InitModule3(LIBPY_NAMESPACE, app_global_methods, "an example app module");
  locals = PyModule_GetDict(mod);

  Py_INCREF(&AppType);
  PyModule_AddObject(mod, LIBPY_TYPE, (PyObject *)&AppType);

  PyModule_AddIntConstant(mod, "CONST1", 11);
  PyModule_AddIntConstant(mod, "CONST2", 13);

  app_class = PyObject_GetAttrString(mod, LIBPY_TYPE);

  AppError = PyErr_NewException((char*)LIBPY_FQTYPE "Error", NULL, NULL);
  Py_INCREF(AppError);
  PyModule_AddObject(mod, LIBPY_TYPE "Error", AppError);

  //  PyRun_SimpleString("from time import time,ctime\nprint 'Today is',ctime(time())\n");
  //  Py_Finalize();

}

char* load_file(const char* fname) {
  FILE* fd;
  long pos;
  size_t len;
  char* data;

  fd = fopen(fname, "rb");
  assert(fd != NULL);
  fseek(fd, 0, SEEK_END);
  pos = ftell(fd);
  fseek(fd, 0, SEEK_SET);

  data = (char*)malloc(pos+1);
  assert(data != NULL);

  len = fread(data, 1, pos, fd);
  assert(len == (size_t)pos);

  data[pos] = 0;

  return data;
}


int main(int argc, char** argv) {
  char* c;
  PyObject* val;

  printf("Hi there\n");

  if(argc != 2) {
    printf("need one parameter\n");
    exit(-1);
  }

  init_py();

  c = load_file(argv[1]);
  printf("script <%s>\n", c);

  QWE;

#if 1
  PyRun_SimpleString(c);
#else
  val = PyRun_String(c, Py_file_input, globals, locals);
  QWE;
  if(val == NULL) {
    PyErr_Print();
  }
  else {
    Py_DECREF(val);
  }
#endif

  QWE;

  return 0;
}

失败的Python脚本是:

#! /usr/bin/python
#coding: latin-1

#from app import *

import os
import shutil

import sys
import stat
import fnmatch
import collections


#print filename()

因此,在编译代码然后使用参数(包含python代码的文件)调用代码时,会导致总线错误。

将上面的代码编译为C或C ++会得到相同的结果。我有兴趣让它与C ++一起使用。

至少有人可以重现这个问题吗?

2 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

我在上面的代码中发现了2个错误,其中一个是app_methods没有结束条目告诉python在哪里停止解释列表。

另一个是确实需要调用PyType_Ready(&amp; AppType)。我之前和之后使用过上面的代码(我认为使用Python 2.6)使用PyType_Ready()创建了一个总线错误。

编译代码时使用pythonx.y-config --cflags / --ldflags也很重要。