【发布时间】:2016-06-09 21:45:02
【问题描述】:
我正在尝试使用 CFFI 加载共享库。该代码旨在实例化 C 结构,打印并销毁它。
#!/usr/bin/env python
from cffi import FFI
ffi = FFI()
ffi.cdef("""
typedef struct
{
int numero;
const char* message;
}STRUCTURE, *PSTRUCTURE;
PSTRUCTURE CreateStructure();
int PrintStructure( PSTRUCTURE );
int FreeStructure( PSTRUCTURE );
""")
lib = ffi.dlopen("./lib/libstructure.so")
structure = lib.CreateStructure()
lib.PrintStructure( structure )
lib.FreeStructure( structure )
但我收到此错误:
用户名@Ubuntu1204VB:~/tests/cffi_tests/structure$ python main.py
回溯(最近一次通话最后一次):
文件“main.py”,第 22 行,在
结构 = lib.CreateStructure()
文件“/usr/local/lib/python2.7/dist-packages/cffi/api.py”,第 810 行,在 __getattr__ make_accessor(name)
文件“/usr/local/lib/python2.7/dist-packages/cffi/api.py”,第 806 行,在 make_accessor accessors[name](name)
文件“/usr/local/lib/python2.7/dist-packages/cffi/api.py”,第 751 行,在 accessor_function 中引发 AttributeError('%s: %s' % (name, e))
AttributeError:CreateStructure:“在库'./lib/libstructure.so'中找不到函数'CreateStructure':./lib/libstructure.so:未定义符号:CreateStructure”
所以,我检查了 ./lib/libstructure.so 里面的内容,使用 nm -DC:
@Ubuntu1204VB:~/tests/cffi_tests/structure$ nm -DC ./lib/libstructure.so
................................ w _Jv_RegisterClasses
0000000000000731 T FreeStructure(STRUCTURE*)
0000000000000702 T PrintStructure(STRUCTURE*)
00000000000006bc T CreateStructure()
0000000000201028 A __bss_start
................................ w __cxa_finalize
................... w __gmon_start__
0000000000201028 一个_eddata
0000000000201040 结束
0000000000000788 T _fini
0000000000000588 T _init
.................................免费
.............................. U malloc
.............................. U printf
CreateStructure 似乎在那里。
所以我创建了一个 C main 来测试这个库并且它工作正常。但是,我必须包含用于创建共享库 (./src/structure.cpp) 的源代码的库和标头 (./include/structure.h)。
然后,我将标头复制并粘贴到用于创建共享库的源代码中,因为我找不到在 Python 代码中使用库加载它的方法,并再次构建了共享库。不幸的是,我在执行 python 时仍然遇到同样的错误。这意味着问题不是来自可能丢失的头文件。
因此,我想知道是否可以在使用 ffi.dlopen("./lib/libstructure.so") 加载符号后检查 python 代码中的符号,以确保它们已正确加载。 .. 或不。
有什么办法吗?我在这里缺少什么吗?
编辑:调查
我在源代码中添加了以下函数:
int main(void)
{
return printf("%d\n", 42);
}
和 ffi.cdef 中的“int main(void)”,在 CreateStructure 的原型之上。
当我只调用 lib.main()... 它打印 42... 如果我将 int main(void) 更改为 int test(void) 并调用 lib.test(),它会给我错误“未定义符号:测试“...
如果我将其他函数的名称更改为“main”(一次一个),它们可以正常工作。就好像 cffi 只能使用名为“main”的函数......
编辑:对 cmets 的回答
在simple-example/ 中使用make 时出现以下错误:
username@Ubuntu1204VB:~/tests/python-cffi-example-how-cffi-works/simple-example$ make
clang -shared add.c -o libadd.so
clang -L. -ladd add-example.c -o add-example.exe
/tmp/add-example-r7jvhJ.o: In function \`main': add-example.c:(.text+0x25): undefined reference to `add'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: \*** [add-example.exe] Error 1
请注意,我使用的是 Ubuntu 12.04,并且我刚刚使用 sudo apt-get install clang 安装了 clang。
另外,这里是我用来编译共享库的makefile:
CC = gcc
INC_PATH = -I ./include
DEBUGFLAGS = -g
CFLAGS = -c -fPIC $(DEBUGFLAGS) -Wall -Wextra
LDFLAGS = -fPIC $(DEBUGFLAGS) -Wall -Wextra -shared
OBJS = ./obj/structure.o
TARGET_LIB = ./lib/libstructure.so
RM = rm -f
all: $(OBJS) $(TARGET_LIB)
./obj/structure.o : ./src/structure.cpp
$(CC) $(INC_PATH) $(CFLAGS) $< -o $@
./lib/libstructure.so : $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^
.PHONY:
clean:
-${RM} ${TARGET_LIB} ${OBJS}
【问题讨论】:
-
这很奇怪。你所做的一切看起来都是正确的......所以如果我不得不猜测,我会说这与库和/或 cffi 的编译方式有关,可能吗?尝试检查github.com/wolever/python-cffi-example 的
how-cffi-works分支——在simple-example/目录中运行make之后,python add-example.py是否有效?代码:github.com/wolever/python-cffi-example/tree/how-cffi-works/… -
已编辑问题以回答您的问题。
-
是的,那么在工具链的某个地方肯定会发生一些时髦的事情。如果您安装了 gcc,您可以尝试将
CC=clang替换为CC=gcc,然后运行 make clean; make以查看是否有效。否则我不确定问题是什么,因为libadd.so似乎也有同样的问题。 -
第一个问题是 libstructure.so 是用 C++ 编译的,而不是用 C 编译的。你可以通过 "nm" 看到这个,它产生像 "CreateStructure()" 这样的名称,带有括号和可能的参数类型。 CFFI 期望使用 C 名称“CreateStructure”。不能直接从 CFFI 调用 C++ 代码。不过,您可以调用 C 代码,而 C 代码本身也会调用 C++ 代码。
-
@Armin @David 谢谢,它有效。我唯一改变的是文件名......从
structure.cpp到structure.c。我不认为它的扩展会对 makefile 产生影响,因为我在 Ubuntu 上使用 GCC!但是,这并不能解释我在编译simple-example时遇到的问题...
标签: python shared-libraries wrapper word-wrap python-cffi