在C中嵌入Python,链接失败,未定义引用`Py_Initialize'

时间:2014-12-27 23:57:18

标签: python c python-c-extension

我正在尝试从文档https://docs.python.org/2.7/extending/embedding.html编译示例,我的代码看起来与5.1下的代码完全相同:

#include <Python.h>

int
main(int argc, char *argv[])
{
  Py_SetProgramName(argv[0]);
  Py_Initialize();
  PyRun_SimpleString("from time import time, ctime\n"
                     "print 'Today is', ctime(time())\n");

  Py_Finalize();
  return 0;
}

我使用以下命令编译它,它对我来说很好,并为我提供了所需的目标文件:

gcc -c $(python2.7-config --cflags) embedpy.c

要链接它,我使用以下命令,该命令最终出现以下错误:

gcc $(/usr/bin/python2.7-config --ldflags) embedpy.o
embedpy.o: In function `main':
/home/miguellissimo/embedpy.c:6: undefined reference to `Py_SetProgramName'
/home/miguellissimo/embedpy.c:7: undefined reference to `Py_Initialize'
/home/miguellissimo/embedpy.c:8: undefined reference to `PyRun_SimpleStringFlags'
/home/miguellissimo/embedpy.c:11: undefined reference to `Py_Finalize'
collect2: error: ld returned 1 exit status

我无法找出我做错了什么,或者我忘了让这个例子有效。

PS:python2.7-config命令在我的Xubuntu机器上提供以下输出:

>>> python2.7-config --cflags 
-I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7  -fno-stri
ct-aliasing -D_FORTIFY_SOURCE=2 -g -fstack-protector --param=ssp-buffer-size=
4 -Wformat -Werror=format-security  -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-pr
ototypes

>>> python2.7-config --ldflags
-L/usr/lib/python2.7/config-x86_64-linux-gnu -L/usr/lib -lpthread -ldl  -luti
l -lm  -lpython2.7 -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions 

5 个答案:

答案 0 :(得分:13)

链接时,库必须在目标文件之后,所以:

gcc  embedpy.o $(/usr/bin/python2.7-config --ldflags)

答案 1 :(得分:4)

还将--embed添加到python3-config

在Ubuntu 20.04,Python 3.8上,我还需要将--embed传递给python3-config,如下所示:

gcc -std=c99 -ggdb3 -O0 -pedantic-errors -Wall -Wextra \
  -fpie $(python3-config --cflags --embed) -o 'eval.out' \
  'eval.c' $(python3-config --embed --ldflags)

否则未添加-lpython3.8,这会导致缺少定义。

这是我的测试程序:

eval.c

#define PY_SSIZE_T_CLEAN
#include <Python.h>

int main(int argc, char *argv[]) {
    (void)argc;
    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);
    Py_Initialize();
    PyRun_SimpleString(argv[1]);
    if (Py_FinalizeEx() < 0) {
        exit(120);
    }
    PyMem_RawFree(program);
    return 0;
}

试运行:

./eval.out 'print(2 ** 3)'

答案 2 :(得分:0)

我在Win7机器上运行的Lubuntu14.04 32位虚拟机上复制了同样的问题。

在Eclipse C / C ++ IDE中编写C ++代码的第一个地方,我做了以下事情来复制问题。定义了一个名为“test”的C ++ Eclipse项目。源文件包含以下C ++代码,与Miguellissimo上面提到的相同。

C ++ Code ::

#include "python2.7/Python.h"

int main(int argc, char *argv[]) {

    Py_Initialize();
    PyRun_SimpleString("print \"Hello, world!\"");

    Py_Finalize();
    return 0;
}

错误::

test.o:在函数main': /home/ros/workspace/test/src/test.cpp:15: undefined reference to Py_Initialize'中 /home/ros/workspace/test/src/test.cpp:17:对PyRun_SimpleStringFlags' /home/ros/workspace/test/src/test.cpp:18: undefined reference to Py_Finalize'的未定义引用 collect2:错误:ld返回1退出状态

以下命令的输出与Miguellissimo之前提到的相同,

ros@rosPC:~/workspace/test/src$ python2.7-config --cflags

-I/usr/include/python2.7 -I/usr/include/i386-linux-gnu/python2.7  -fno-strict-aliasing -D_FORTIFY_SOURCE=2 -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security  -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes

ros@rosPC:~/workspace/test/src$ python2.7-config --ldflags

-L/usr/lib/python2.7/config-i386-linux-gnu -L/usr/lib -lpthread -ldl  -lutil -lm  -lpython2.7 -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions

C ++ Eclipse Project的Project Properties,标题为“test”::

在里面,我有以下C ++ Build Settings

GCC C ++编译器

Command: g++

All options: -I/opt/ros/indigo/include -O0 -g3 -Wall -c -fmessage-length=0

Command line pattern: ${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}

Includes
    include paths: /opt/ros/indigo/include

GCC C编译器

Command: gcc

All options: -I/opt/ros/indigo/include -I/usr/lib/python2.7/config-i386-linux-gnu -O0 -g3 -Wall -c -fmessage-length=0

Command line pattern: ${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}

Includes
    include paths: /opt/ros/indigo/include
                   /usr/lib/python2.7/config-i386-linux-gnu

GCC C ++链接器

Command: g++

All options: Command line pattern: ${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}

Libraries:

    Libraries(-I): 

    Library search path(-L): 

解::

在C ++ Eclipse Project的“项目属性”中指定以下C ++构建设置“test”

GCC C ++编译器

Command: g++

All options: -I/opt/ros/indigo/include -I/usr/include/python2.7 -O0 -g3 -Wall -c -fmessage-length=0

Command line pattern: ${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}

Includes
    include paths: /opt/ros/indigo/include
                   /usr/include/python2.7

GCC C编译器

Command: gcc

All options: -I/opt/ros/indigo/include -I/usr/include/python2.7 -O0 -g3 -Wall -c -fmessage-length=0

Command line pattern: ${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}

Includes
    include paths: /opt/ros/indigo/include
                   /usr/include/python2.7

GCC C ++链接器

Command: g++

All options: -L/usr/lib/python2.7/config-i386-linux-gnu

Command line pattern: ${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}

Libraries:

    Libraries(-I): python2.7

    Library search path(-L): /usr/lib/python2.7/config-i386-linux-gnu

结果::以前编译C ++ Eclipse项目导致的链接器错误不再发生。

答案 3 :(得分:0)

在WSL,Ubuntu 18.04,Python3.8,g ++ 7.5上出现相同的错误。 感谢Ciro Santilli的评论,在--embed中添加了python3.8-config选项可以解决未解决的符号问题,但是之后我得到了以下错误:

g++ `python3.8-config --cflags --embed` -o cpython.out cpython.cpp `python3.8-config --ldflags --embed`
lto1: fatal error: bytecode stream in file ‘/home/rpovelik/installed/miniconda3/envs/cython/lib/python3.8/config-3.8-x86_64-linux-gnu/libpython3.8.a’ generated with LTO version 6.0 instead of the expected 6.2
compilation terminated.
lto-wrapper: fatal error: g++ returned 1 exit status
compilation terminated.
/usr/bin/ld: error: lto-wrapper failed
collect2: error: ld returned 1 exit status

我想有些人将面临同样的问题,所以我检查了类似的症状here,其中conda人说类似“不要使用默认编译器-g++-之类的东西,因为它可能会引起兼容性”问题-使用特定于conda的编译器”。

顺便说一句,添加-fno-lto解决了系统范围的g++ 7.5的问题。可能您可以尝试更改编译器的版本。

答案 4 :(得分:0)

接受的答案使用系统的默认库位置。

如果您在anaconda环境中,则可能找不到库位置。我倾向于在链接过程中更明确地给出位置,例如:

gcc embedpy.o -L$(python-config --prefix)/lib $(python-config --ldflags)

在64位库中的anaconda环境之外,此方法将不起作用,在这种情况下:

gcc embedpy.o -L$(python-config --prefix)/lib64 $(python-config --ldflags)