将Python代码转换为共享对象
我想从一个Python模块准备一个共享对象(.so文件)。我发现了Cython,它的工作流程是:首先把一个*.pyx模块转换成*.c代码,然后再把这个*.c代码转换成共享对象(.so文件)。Cython的所有例子都说明了如何在Python中导入这个.so文件。
但是,我想知道如何从C代码中读取这个共享对象。当我写了一段示例C代码来读取一个.so文件时,它报错了,提示在.pyx中实际存在的方法在.so对象中找不到。
我想了解: a) 是否可以从Cython的共享对象在其他语言(比如C)中读取 b) 如果上面的说法是对的,我需要在我的代码中做哪些更改,才能从C中读取共享对象。
谢谢,
Python代码(保存为square_number.pyx)
def square_me(int x):
return x * x
对应的Cython的setup.py文件
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_modules=cythonize("square_number.pyx"),
)
将上面的.pyx文件转换为.so文件的命令行语句(通过cython)
python setup.py build_ext --inplace
这会在同一个文件夹中创建一个square_number.so文件。现在,我把它重命名为libSquareNumber.so
用于读取.so文件的C代码
#include<stdio.h>
int main(int argc,char *argv[])
{
int result;
result=square_me(2);
printf("Sum of entered numbers = %d\n",result);
return 0;
}
当我尝试从上面的命令编译并构建一个可执行文件时,我遇到了一个错误
C代码的编译:
gcc -L/home/USRNAME/work/cython-codes/squaring/ -Wall -o test so_reader_in_c.c -lSquareNumber
错误
so_reader_in_c.c: In function ‘main’:
so_reader_in_c.c:11:4: warning: implicit declaration of function ‘square_me’ [- Wimplicit-function-declaration]
result=square_me(2);
^
/tmp/ccE5vIOH.o: In function `main':
so_reader_in_c.c:(.text+0x1a): undefined reference to `square_me'
collect2: error: ld returned 1 exit status
3 个回答
把字节码转换成汇编代码并不需要用到C语言。可能会有一些类是被C调用的,或者以类似C的方式调用其他C类。但无论如何,它们还是字节码或者汇编代码。你不能把从来没有的东西反向转换。可以使用 objectdump -d -M
来列出这些类,如果你还需要的话,再手动把这些类转换成C语言,最后要感谢我们有Python可以帮我们做这些事情。
我不太记得具体细节了,等我想起来后可能能给出更详细的答案。不过基本的情况是,Cython在导出可以和C语言兼容的共享库(SO文件)之前,会对Python函数进行一个名字处理。Python在导入Cython模块时也能理解这个名字处理,因此可以调用到正确的函数。
你需要做的是使用一个SO扫描库来查看Cython模块中的函数实际叫什么。为了简单起见,可以试试运行以下命令:
readelf my_cython_so.so
这个命令会显示共享库的内容,包括函数的入口点和链接器使用的名称。然后你就可以用这些名称在你的代码中找到正确的函数来调用。如果想在你的C代码中自动化这个过程,可以使用libelf来实现。
把 square_number.pyx 文件改成这样:
cdef public int square_me(int x):
return x * x
运行 "setup.py" 后,会生成一个头文件 "square_number.h"。把这个文件包含到你的主应用程序里。具体如下:
把你的 "main" 函数改成类似下面的样子:
#include <Python.h>
#include "square_number.h"
int main()
{
Py_Initialize();
initsquare_number();
printf("%d",square_me( 4 ) );
Py_Finalize();
return 0;
}
在编译的时候,确保链接 libpython.so 和 libsquare_number.so。你还需要通过给 gcc 加上 -I 参数来处理 "Python.h" 的包含目录搜索路径。
想了解更多信息,可以查看: http://docs.cython.org/src/userguide/external_C_code.html