【问题标题】:Minimal example of Python interpreter embedding segfaultsPython解释器嵌入段错误的最小示例
【发布时间】:2018-09-08 03:13:40
【问题描述】:

我从这里复制的示例:https://docs.python.org/3.5/extending/embedding.html

#include <Python.h>

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();
    PyRun_SimpleString("from time import time,ctime\n"
                       "print('Today is', ctime(time()))\n");
    Py_Finalize();
    PyMem_RawFree(program);
    return 0;
}

如果像这样编译和链接:

gcc -fno-diagnostics-color -Wall -Wno-unused-function -fPIC -ggdb \
    -I. -I/usr/include/python3.5m -c test_embed.c -o test_embed.o
gcc -fno-diagnostics-color -Wall -Wno-unused-function -fPIC -ggdb \
    -I. -I/usr/include/python3.5m -shared -lpython3.5m ./test_embed.o \
    -o test_embed

运行时出现段错误并将堆栈破坏到无法弄清楚发生了什么的程度。我需要任何特定的设置来编译它吗?


当我使用/usr/bin/python3.5-config --cflags/usr/bin/python3.5-config --ldconfig 给出的编译器选项时,该示例将无法构建,因为它在共享对象中找不到符号。


根据要求,这里是编译和链接命令以及错误输出:

$ gcc $(python3.5-config --cflags) -c test_embed.c -o test_embed.o
$ gcc $(python3.5-config --ldflags) ./test_embed.o -o test_embed
./test_embed.o: In function `main':
redacted/test_embed.c:6: undefined reference to `Py_DecodeLocale'
redacted/test_embed.c:11: undefined reference to `Py_SetProgramName'
redacted/test_embed.c:12: undefined reference to `Py_Initialize'
redacted/test_embed.c:13: undefined reference to `PyRun_SimpleStringFlags'
redacted/test_embed.c:15: undefined reference to `Py_Finalize'
redacted/test_embed.c:16: undefined reference to `PyMem_RawFree'
collect2: error: ld returned 1 exit status
$ python3.5-config --ldflags
-L/usr/lib/python3.5/config-3.5m-x86_64-linux-gnu -L/usr/lib -lpython3.5m -lpthread -ldl  -lutil -lm  -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions

【问题讨论】:

  • 这个 python3.5m 是来自一个包(如 apt 或 rpm),还是你从源代码配置和编译的?
  • @MarkPlotnick 抱歉,它是从 Ubuntu PPA 安装的。我也有从源代码编译的 Python 3.6,但这个不是我的。

标签: python c build


【解决方案1】:

您的 test_embed 二进制文件有段错误,因为不打算运行使用 --shared(共享库)构建的二进制文件。

诊断导致您在链接器命令行中错误使用--shared 的构建问题可能需要更多详细信息,例如您使用的特定gcc 命令和运行它们的错误消息,或@987654327 的输出@ 在您的系统上,也许两者兼而有之。如果我使用以下命令编译您的测试程序,它不会出现段错误(它会打印预期的输出)。

gcc $(python3.5-config --cflags) -c test_embed.c -o test_embed.o
gcc $(python3.5-config --ldflags) ./test_embed.o -o test_embed

在我的系统上,python3.5-config --ldflags 的输出不包括 --shared

构建Building C and C++ Extensions 的文档在其distutils 部分中包含示例编译命令。那里的示例链接命令包括它生成的.so 文件的--shared,但该.so 文件旨在导入python 解释器,而不是作为命令调用。

【讨论】:

  • 我想我是通过复制粘贴命令行setuptools 来添加--shared 在编译C 模块时生成的。但是,我还记得 gcc 抱怨 -fPIC(它希望它在那里),而它不在标志中。 Python真的不使用这个选项吗? (我知道其他一些解释器不这样做是因为他们如何管理自己的运行时,但如果 Python 也这样做,那么这也意味着嵌入程序也应该这样做......
  • 在为 python 模块编译 C 代码时使用--shared 是有意义的。以这种方式生成的二进制文件通常以.so 作为其后缀,并且不打算作为可执行文件调用。如果您尝试将对象模块链接到共享对象中,即仅当您在链接命令中指定 --shared 时,就会出现推荐 -fPIC 的投诉。
  • 那么,Python编译时一定要不带-fPIC吗?这对我来说不是什么大问题,因为这种嵌入仅用于单独测试 C 模块。但这难道不是每个使用 CPython 的人都关心的问题吗?
  • 另外,当我这样做时,链接不起作用:&lt;Python.h&gt; 中包含的所有内容都是未定义的。
  • 也许您可以编辑问题以指定失败的链接命令及其错误输出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-08
  • 2012-09-19
  • 1970-01-01
  • 2019-08-30
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
相关资源
最近更新 更多