在C语言中嵌入Python:链接错误 - undefined reference to PyString_AsString

7
我正在尝试在C程序中嵌入一个Python程序。我的操作系统是Ubuntu 14.04。
我尝试将Python 2.7和Python 3.4解释器嵌入到同一C代码库中(作为单独的应用程序)。当嵌入Python 2.7时,编译和链接工作正常,但是对于Python 3.4,则在链接阶段失败。
这是我的C代码(仅为示例,非真实代码): simple.c
#include <stdio.h>
#include <Python.h>

int main(int argc, char *argv[])
{
    PyObject *pName, *pModule, *pFunc, *pValue;
    char module[] = "get_version";
    char func[] = "get_version";
    char module_path[] = ".";

    Py_Initialize();
    PyObject *sys_path = PySys_GetObject("path");
    PyList_Append(sys_path, PyUnicode_FromString(module_path));

    pName = PyUnicode_FromString(module);
    pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if(pModule != NULL)
    {
        pFunc = PyObject_GetAttrString(pModule, func);
        if (pFunc && PyCallable_Check(pFunc))
        {
            pValue = PyObject_CallObject(pFunc, NULL);
            if (pValue != NULL) {
                printf("Python version: %s\n", PyString_AsString(pValue));
                Py_DECREF(pValue);
            }
            else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
                fprintf(stderr,"Call failed\n");
                return 1;
            }
        }
    }

    Py_Finalize();
    return 0;
}

get_version.py

import sys

def get_version():
    version = '.'.join(str(v) for v in sys.version_info[:3])
    print("version: ", version)
    return version

我使用gcc编译程序。首先,将编译和链接标志设置为Python 2.7,然后使用以下命令运行编译和链接:

gcc `python-config --cflags` simple.c `python-config --ldflags`

标志扩展为:

python-config --cflags:-I/usr/include/python2.7 -I/usr/include/x86_64-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

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

它在没有任何问题的情况下正常工作。但是,当我尝试使用python3.4标志编译相同的内容时,它会失败:

gcc `python3-config --cflags` simple.c `python3-config --ldflags`

旗帜的含义如下: python-config --cflags: -I/usr/include/python3.4m -I/usr/include/python3.4m -Wno-unused-result -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes python-config --ldflags: -L/usr/lib/python3.4/config-3.4m-x86_64-linux-gnu -L/usr/lib -lpython3.4m -lpthread -ldl -lutil -lm -Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions 错误信息:
simple.c: In function ‘main’:
simple.c:27:17: warning: implicit declaration of function ‘PyString_AsString’ [-Wimplicit-function-declaration]
                 printf("Python version: %s\n", PyString_AsString(pValue));
                 ^
simple.c:27:17: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has typeint’ [-Wformat=]
/tmp/ccaoMdTo.o: In function `main':
/home/vagrant/c_python_api/simple.c:27: undefined reference to `PyString_AsString'
collect2: error: ld returned 1 exit status

我尝试通过更改链接器对象的指定顺序来解决问题。但是没有成功。您有什么想法为什么会出现这种情况吗?

感谢您的帮助!

1个回答

12

Python 3不再有PyString_AsString;Python 3中的str对应于Python 2中的unicode对象;Python 3中处理str的函数名称在C-API中以PyUnicode_为前缀。

因此,这行代码:

printf("Python version: %s\n", PyString_AsString(pValue));

可以在Python 3上使用PyUnicode_AsUTF8来进行更改:

#if PY_MAJOR_VERSION >= 3
printf("Python version: %s\n", PyUnicode_AsUTF8(pValue));
#else
printf("Python version: %s\n", PyString_AsString(pValue));
#endif

(需要注意的是,将NULL传递给printf%s会产生未定义的行为,因此您需要检查是否返回了非空指针)


谢谢您的快速回复。您提供的解决方案有效。我知道Python3字符串默认为Unicode编码,应该考虑过这一点。但是,正如您所说,在您的解决方案中,UTF8String是PyObject,无法转换为本机字符。如此处所述,应该有额外的函数调用PyBytes_AsString()。我将编辑答案以包括此内容。 - Jahan Balasubramaniam
啊,抱歉:D我匆忙作答,已经修正。 - Antti Haapala -- Слава Україні
@JahanBalasubramaniam 应该是 PyUnicode_AsUTF8;这将返回一个指向以 UTF-8 编码的字符串的共享指针,只要 str 本身存在,它就是有效的。 - Antti Haapala -- Слава Україні
PyUnicode_AsUTF8 存在于 Python 3.3 及以后的版本中;最好不要支持 Python 3.2,因为在 Python 3 中 str 的 C-API 发生了很多变化。 - Antti Haapala -- Слава Україні

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接