在 C 中嵌入 Python:链接错误 - 未定义对 PyString_AsString 的引用

Posted

技术标签:

【中文标题】在 C 中嵌入 Python:链接错误 - 未定义对 PyString_AsString 的引用【英文标题】:Embedding Python in C: Error in linking - undefined reference to PyString_AsString 【发布时间】:2016-07-31 13:10:57 【问题描述】:

我正在尝试在 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 type ‘int’ [-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】:

Python 3 does not have PyString_AsString any more; 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 会有未定义的行为,因此您需要检查是否返回了非NULL 指针)

【讨论】:

感谢您的快速回复。您提供的解决方案有效。我知道 Python3 字符串默认是 unicode 编码的,应该考虑一下。但是,正如您在解决方案中所说的 UTF8String 是 PyObject 并且不能转换为本机字符。如here 所述,应该是对 PyBytes_AsString() 的附加函数调用。我将编辑答案以包含此内容。 啊抱歉 :D 我匆忙写下答案:已修复 @JahanBalasubramaniam 应该是PyUnicode_AsUTF8;这将返回一个指向编码为 UTF-8 的字符串的共享指针,只要 str 本身存在,它就有效。 PyUnicode_AsUTF8 存在于 Python 3.3 中;根本不支持 Python 3.2 是最简单的,因为 Python 3 中 str 的 C-API 发生了很多变化。

以上是关于在 C 中嵌入 Python:链接错误 - 未定义对 PyString_AsString 的引用的主要内容,如果未能解决你的问题,请参考以下文章

嵌入python

在 C 中嵌入 python,未定义符号:PyExc_ImportError

嵌入式 C/C++:现有符号的未定义引用

Python嵌入项目中的VC ++ 6“未解决的外部”

裸机嵌入式 C++:将闪存写入 ram 时未定义对 memcpy 和 memset 的引用

尽管在 CMake 中指定了库,但未定义的引用错误(与 libtorch 链接的问题(C++11 ABI?)