跟踪嵌入式Python解释器

时间:2015-12-03 20:42:29

标签: python c python-3.x python-c-api

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

官方Python文档来到tracing and profiling时似乎有些不足。 例如,没有关于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;
}

但是,编译器输出以下错误:

hello.c:5:26: error: unknown type name ‘PyFrameObject’
 int trace(PyObject *obj, PyFrameObject *frame, int what, PyObject *arg)
                          ^

我在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 -Wall -Wstrict-prototypes -L/usr/lib -lpython3.5m -lpthread -ldl  -lutil -lm  -Xlinker -export-dynamic

我发现我可以用PyFrameObject替换struct _frame,然后编译程序,但每个人都知道这是一个肮脏的黑客,而不是解决方案。

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

line 1
line 2
line 3
line 4
line 5
7

但我希望跟踪脚本的执行流程(即:从第3行开始,然后是4,5,然后由于函数调用,2)。

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

您是否可以推荐一些有关Python C API的其他资源,包括更多信息和对该主题的一些介绍?

我以赏金给出答案,因为它无论如何都会过期。但是,我仍在寻找并感谢上述其他问题的答案。

3 个答案:

答案 0 :(得分:8)

hello.c:5:26: error: unknown type name ‘PyFrameObject’

此错误表示尚未声明PyFrameObject。我做了一个Google search,它在Python源代码树中显示frameobject.h是声明该结构的地方。

我希望你可以添加一行

#include <frameobject.h>

解决此问题。

答案 1 :(得分:0)

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 

获取当前函数名称 和

frame->f_back

在调用堆栈中降低一级。                                         

答案 2 :(得分:-1)

PyFrameObject只是一个_frame结构。只需在函数签名中将PyFrameObject替换为_frame,就不必包含任何其他python标头。