【问题标题】:Why does the Python/C API crash on PyRun_SimpleFile?为什么 Python/C API 在 PyRun_SimpleFile 上崩溃?
【发布时间】:2011-04-08 22:52:13
【问题描述】:

我一直在尝试在 C++ 应用程序中嵌入不同的脚本语言,目前我正在尝试 Stackless Python 3.1。我尝试了几个教程和示例,但我能找到的很少,尝试从应用程序运行一个简单的脚本。

Py_Initialize();

FILE* PythonScriptFile = fopen("Python Scripts/Test.py", "r");
if(PythonScriptFile)
{
    PyRun_SimpleFile(PythonScriptFile, "Python Scripts/Test.py");
    fclose(PythonScriptFile);
}

Py_Finalize();

出于某种奇怪的原因,运行这段代码会导致访问冲突:

    PyRun_SimpleFile(PythonScriptFile, "Python Scripts/Test.py");

我在网上搜索了其他有类似问题的人,但只找到了一个。他们唯一的解决方案是只有在旧版本的 Python 中才有可能的解决方法:创建一个 python 文件对象并将该 python 文件对象中的FILE* 返回到PyRun_SimpleFile。然而,此类函数调用不可用,Python 3.1 API 从文件描述符创建文件对象并返回文件描述符,但 PyRun_SimpleFile 函数仍然需要 FILE*

我不知道如何从文件中运行任何脚本,没有手动将整个文件加载到内存中并将其作为一个巨大的字符串运行,这当然不是一个实用的解决方案。

什么给了?如果 API 出现内部错误,我该如何完成这项任务?

更新: 我已经设法从源代码构建 Stackless Python 3.1,但崩溃仍然完全没有改变,尽管使用了相同的 C 运行时库。我的项目和 Stackless Python 3.1 源代码都是使用 Visual Studio 2010 的 C++ 编译器和 C 运行时构建的。我不再知道什么可以解决这个问题,除了修改 Python 以使用文件名而不是 FILE*。另一个糟糕的解决方法。

【问题讨论】:

    标签: c++ python scripting python-stackless cross-language


    【解决方案1】:

    以下代码将执行 test.py 模块。 Python 将在路径集中搜索模块。所以应该先处理路径。

    Py_Initialize();
    
    string path = "Python Scripts/";
    
    //Set the path
    PyRun_SimpleString("import sys");
    string str = "sys.path.append('" + path + "')";
    PyRun_SimpleString(str.c_str());
    
    //Dont use test.py as it actually searches sub module test>>py
    PyObject * moduleName = PyUnicode_FromString("test");
    PyObject * pluginModule = PyImport_Import(moduleName);
    
    if (pluginModule == nullptr)
    {
        PyErr_Print();
        return "";
    }
    
    //Do the executions here
    
    //clean up
    Py_DECREF(moduleName);
    Py_DECREF(pluginModule);
    Py_DECREF(transformFunc);
    Py_DECREF(result);
    
    Py_Finalize();
    

    【讨论】:

      【解决方案2】:

      那么这个解决方案呢:

      Py_SetProgramName(argv[0]);
      Py_Initialize();
      PyRun_SimpleString("execfile(\"ex30.py\")");
      Py_Finalize();
      

      ex30.py 是我正在运行的 python 脚本的名称。

      【讨论】:

        【解决方案3】:

        这适用于我在 Python 3 上:

         PyObject *obj = Py_BuildValue("s", "test.py");
         FILE *file = _Py_fopen_obj(obj, "r+");
         if(file != NULL) {
             PyRun_SimpleFile(file, "test.py");
         }
        

        希望对你有用。

        【讨论】:

        • 对我有用,但稍作修改: FILE *file = _Py_fopen( "test.py", "r+" ); PyRun_SimpleFile(文件,“test.py”);这应该被标记为答案。
        • @MasterMind:答案的 OP 显然想调用 _Py_fopen_obj-function 而不是 _Py_fopen-function。我相应地编辑了答案(因此答案中的代码现在应该可以开箱即用)。不过,您的解决方案似乎更容易/更轻量级。出于某种原因,如果我在Py_Initialize()-函数之后声明了const char* 文件路径变量 或者如果我像你一样直接放入字符串,这两种解决方案 有效在你的例子中做了。 (说实话:Python C++ 包装器很痛苦,而且可以简单得多)
        【解决方案4】:

        如果您使用 VC 2010 构建测试,您肯定会遇到问题 - VC9 (VS 2008) 和 VC10 (VS 2010) 具有通常需要的相互不兼容的支持 DLL(实现 printf、文件 i/o 和那种事物)。如果它们包含标准库,则不能混合使用它们,python 构建会这样做。

        您始终可以选择使用 gcc(例如 Cygwin 或 mingw)或下载 Visual Studio 2008 express,这应该可以很好地用于 python 嵌入的实验。我在标准 Python 2.7.6 版本中都使用过。

        【讨论】:

          【解决方案5】:

          我遇到了类似的崩溃并执行了以下操作:

             PyObject* PyFileObject = PyFile_FromString("test.py", "r");
             PyRun_SimpleFileEx(PyFile_AsFile(PyFileObject), "test.py", 1);
          

          请注意,这是在 python 2.7 中。我不知道 API 在 3.x 中是否发生了变化。

          【讨论】:

            【解决方案6】:

            您的代码在我安装的 Python 2.6 版本上正常运行。我还从源代码构建了 stackless 3.1.2,它工作正常。这是 Ubuntu 10.04 上的 g++ 4.4.3。如果您使用的是 Windows,您可能需要检查无堆栈和您的代码是针对同一个 C 运行时构建的。

            【讨论】:

            • 嗯,这就是我遇到麻烦的地方。我知道 C 运行时是不同的。我正在使用 Visual Studio 2010,并且我很确定大多数 Python 二进制文件都是使用 Visual Studio 2008 构建的。我一直在尝试构建 Stackless Python 3.1 源代码,但我不完全确定哪些库、DLL 和头文件是需要的。更不用说由于缺少文件而导致某些扩展模块无法构建的一些问题。提供的用于构建它们的批处理文件取决于其他几个缺失的文件,例如安装了 SVN。
            • @Sion:不幸的是,除了说“检查文档”和“祝你好运”之外,我真的没有什么能提供的了。我无法访问 Windows 开发机器,更不用说 VS2010。有没有办法为使用正确的 Visual Studio 版本构建的 stdio 的相关部分编写一个小包装器?
            • 帮助仍然受到赞赏,尽管此时即使是相同的编译器和运行时也无法解决问题。我可能不得不尝试直接联系开发人员或其他 Python 专家。
            • 很好地捕捉到不同的运行时,这是 Windoze 上的一个常见问题,使用混合和匹配编译器。
            • 在尝试使用 2.7 执行此操作时,我遇到了不同的运行时问题。我正在调用使用一个运行时的 fopen。然后 Python 使用 FILE* 并使用不同的运行时,导致崩溃。 _Py_fopen 在 2.7 中不可用
            【解决方案7】:

            这听起来像是 API 不匹配的问题。如果您的代码和 Python 运行时是使用不同的编译器甚至不同的编译器选项编译的,那么访问 FILE* 可能会导致访问冲突。您能否再次检查您是否正确构建了 C 代码?

            您提到您将 Python 嵌入到您的 C++ 应用程序中。请记住,Python 是 C 代码,编译为 C 代码。也许这就是问题的根源?

            【讨论】:

            • 是的,Stackless Python 3.1 库不是我自己构建的。我读到这个问题很可能是使用来自不同运行时的 FILE,因此解决方法是允许 Python 库创建 FILE 并将其返回以用作功能。那么,除了获取源代码并自己构建 Stackless Python 3.1 之外,我别无选择?
            • 如果您可以构建您的 C 代码,那么使用 Stackless 代码应该不会有任何困难。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-07-23
            • 1970-01-01
            • 1970-01-01
            • 2014-08-12
            • 2021-06-15
            • 2013-04-05
            相关资源
            最近更新 更多