0

我正在尝试使用 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
Traceback(最近一次调用最后):
文件“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"

因此,我使用 nm -DC 检查了 ./lib/libstructure.so 内部的内容:

@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 A _edata
0000000000201040 A _end
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”的函数......

编辑:回答评论
我收到以下make错误simple-example/

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}
4

1 回答 1

1

这是修复:

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

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

于 2016-02-29T16:00:22.103 回答