嵌入式Python解释器中的代码执行跟踪

嵌入式Python解释器中的代码执行跟踪,python,c,python-3.x,python-c-api,Python,C,Python 3.x,Python C Api,我想创建一个具有嵌入式python解释器和基本调试功能的应用程序。 现在,我正在搜索API中的函数,这些函数可以用来逐步运行代码,并获得当前正在(或即将)执行的代码行的编号 说到Python官方文档,我觉得有点不够成熟。 例如,没有关于Py_tracefunc返回值含义的信息 到目前为止,我已经完成了以下工作: #include <Python.h> static int lineCounter = 0; int trace(PyObject *obj, PyFrameObjec

我想创建一个具有嵌入式python解释器和基本调试功能的应用程序。 现在,我正在搜索API中的函数,这些函数可以用来逐步运行代码,并获得当前正在(或即将)执行的代码行的编号

说到Python官方文档,我觉得有点不够成熟。 例如,没有关于
Py_tracefunc
返回值含义的信息

到目前为止,我已经完成了以下工作:

#include <Python.h>

static int lineCounter = 0;

int trace(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg)
{
    if(what == PyTrace_LINE)
    {
        lineCounter += 1;
        printf("line %d\n", lineCounter);
    }
    return 0;
}

int main(int argc, char *argv[])
{
    wchar_t *program = Py_DecodeLocale(argv[0], NULL);
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
        exit(1);
    }
    Py_SetProgramName(program);  /* optional but recommended */
    Py_Initialize();
    PyEval_SetTrace(trace, NULL);
    char *code = "def adder(a, b):\n"
                 " return a + b\n"
                 "x = 3\n"
                 "y = 4\n"
                 "print(adder(x, y))\n";
    PyRun_SimpleString(code);
    Py_Finalize();
    PyMem_RawFree(program);
    return 0;
}
我正在操作ManjaroLinux,并使用以下内容编译上述内容:

gcc-o hello hello.c-I/usr/include/python3.5m-Wno unused result-Wsign compare-Wunreachable code-march=x86-64-mtune=generic-O2-pipe-fstack-protector-strong-param=ssp buffer size=4-DNDEBUG-g-fwrapv-O3.5m-Wstrict原型-L/usr/lib-lpython3.5m-lpthread-ldl-lutil-lm-Xlinker-export动态导出
我发现我可以用
struct\u frame
替换
PyFrameObject
,然后程序编译,但每个人都知道这是一个肮脏的黑客行为,不是解决方案

可执行文件输出以下内容:

#include <Python.h>

static int lineCounter = 0;

int trace(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg)
{
    if(what == PyTrace_LINE)
    {
        lineCounter += 1;
        printf("line %d\n", lineCounter);
    }
    return 0;
}

int main(int argc, char *argv[])
{
    wchar_t *program = Py_DecodeLocale(argv[0], NULL);
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0]\n");
        exit(1);
    }
    Py_SetProgramName(program);  /* optional but recommended */
    Py_Initialize();
    PyEval_SetTrace(trace, NULL);
    char *code = "def adder(a, b):\n"
                 " return a + b\n"
                 "x = 3\n"
                 "y = 4\n"
                 "print(adder(x, y))\n";
    PyRun_SimpleString(code);
    Py_Finalize();
    PyMem_RawFree(program);
    return 0;
}
第1行
第2行
第3行
第4行
第5行
7.
但我希望跟踪遵循脚本的执行流程(即:从第3行开始,然后是第4行、第5行,然后,由于函数调用的原因,是第2行)。

我找不到关于逐步执行的任何信息。

您能推荐一些关于Python C API的其他源代码,并提供更多信息和对该主题的一些介绍吗

我悬赏了这个答案,因为它无论如何都会过期的。不过,我仍在寻找,如果您能回答上面的其他问题,我将不胜感激

此错误表示未声明
PyFrameObject
。我做了一个测试,它在Python源代码树中显示了声明该结构的位置

我希望您可以添加这一行

#include <frameobject.h>
#包括

为了解决这个问题。

PyFrameObject
只是一个
\u frame
结构。只需将函数签名中的
PyFrameObject
替换为
\u frame
,就不必包含任何附加的python头。

PyFrameObject具有

int f_lineno;
场。 你可以用它。但显然,它并不总是存储正确的值。因此,您可能应该使用以下函数:

/* Return the line of code the frame is currently executing. */
int PyFrame_GetLineNumber(PyFrameObject *);      
然后,你可以使用

frame->f_code->co_filename 
获取当前文件名

frame->f_code->co_name 
获取当前函数名的步骤 及

在调用堆栈中降低一级。
.

这可能有助于跟踪功能:除此之外,请使用源代码,Luke@SvenMarnach:你是说Python头文件?所有的CPython源代码,实际上,不仅仅是头文件。您在这里处理的是CPython解释器的实现细节,在这些情况下,除了文档之外,通常还需要查看源代码(至少是有帮助的)。例如,有关返回值的含义,请参见。阅读源代码。此处调用跟踪函数:。您可以查找此函数的调用者(在同一文件中),并在返回错误时查看其行为(它不会进入帧)。如果您不想发生这种情况,您可能不想抛出异常。我在互联网上的某个地方读到,光是Python.h就足够了。文档中的示例也仅包括Python.h。您是否可以提供任何声称frameobject.h应单独包含的源代码?我从您发布的错误消息中推断出来。您可以通过阅读源代码自行确定。阅读Python.h并按照各种include查看其中/是否包含frameobject.h。它甚至可能是基于已定义的预处理器标记的有条件的。糟糕的是,这些文件都很挑剔。但这个简单的编译错误并不是我最大的担忧,正如你可能猜到的那样。@Luke
Python.h
应该足够了。然而,这可能是python源代码中的一个bug
frame->f_back