CFFI 找不到函数,即使它们在库中

CFFI cannot find functions even though they are in the library

我正在尝试使用 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$pythonmain.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 访问器[名称](名称)
文件“/usr/local/lib/python2.7/dist-packages/cffi/api.py”,第 751 行,在 accessor_function 中 raise AttributeError('%s: %s' % (name, e))
属性错误:CreateStructure:"function 'CreateStructure' not found in library './lib/libstructure.so': ./lib/libstructure.so: undefined symbol: CreateStructure"

所以,我检查了里面的内容。/lib/libstructure。所以,使用 nm -DC:

@Ubuntu1204VB:~/tests/cffi_tests/structure$纳米-DC ./lib/libstructure.so
................... w _Jv_RegisterClasses
0000000000000731 T 自由结构(结构*)
0000000000000702 T 打印结构(结构*)
00000000000006bc T CreateStructure()
0000000000201028 A __bss_start
................... w __cxa_finalize
................... w __gmon_start__
0000000000201028 一个_edata
0000000000201040 A _end
0000000000000788 T _fini
0000000000000588 T _init
...................................你有空
......................... U malloc
......................... U printf

CreateStructure 似乎在那里。

所以我创建了一个 C main 来测试这个库并且它工作了。但是,我必须包含用于创建共享库 (./src/structure.cpp) 的库和源代码的 header (./include/structure.h)。

然后,我将 header 复制并粘贴到我用来创建共享库的源代码中,因为我找不到用 Python 代码中的库加载它的方法,并再次构建共享库。不幸的是,我在执行 python 时仍然遇到同样的错误。这意味着问题不是来自可能丢失的 header 文件。

因此,我想知道在使用 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(),它会给我错误 "undefined symbol: test"...
如果我将其他函数的名称更改为 "main"(一次一个),它们将正常工作。好像 cffi 只能使用名为 "main"...

的函数

编辑:对评论的回答
我在 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}

修复如下:

Armin Rigo 指出 nm 显示代码被编译为 C++,通过显示像 CreateStructure() 这样的函数而不是像 C 标准库中的 printf 这样的函数(注意括号存在,因为 C++ 依赖于名称修饰的参数,而 C 不允许多个函数具有相同的名称)。

因此,要用 C 编译,源文件的名称必须从 structure.cpp 更改为 structure.c,因为文件扩展名对 GCC 很重要。