1
|
int add( int a, int b); |
如果使用gcc编译器,那么编译生成的名字就叫 add,但是如果使用 g++编译器,可能编译生成的名字就叫类似于ABaddCD这样的,这里面包含了函数名、入参个数、类型、返回值。所以,如果c++中还定义了一个重载的
1
|
float add( float a, float b); |
可能编译生成的名字就叫类似于 EFaddGH这样的,同样包含了函数名、入参、返回值等信息,所以c++可以重载。试想一下,如果使用gcc编译器,那么都叫add,就无法区分哪个函数了,所以无法重载。那么,extern “C”的作用,就是告诉g++编译器,将 int add(int a,int b)编译成 add,而不是编译成 ABaddCD,因为 add 才能被 C 语言识别,ABaddCD无法被C语言识别,C语言会认为 add是'undefined symbol'。所以,从这里我们也可以看出,extern “C”只能用于 c++代码,另外,对于存在重载的c++函数,需要写两个不一样的函数分别调用,保证名字不重复。
python使用extern “C”方式调用c++动态库
知道了extern “C”的本质之后,我们就按照这个方法进行封装。我是直接拿着c++动态库的源码,在源码之上封装一层C接口,然后生成动态库。假设将 add 函数封装成 addc,C++动态库叫做A,封装一层C接口之后生成的动态库叫做B。如果写一个test.c的测试代码,使用纯C代码检验动态库B,调用addc函数,结果是可行的,成功的。但是使用python检验动态库B,调用addc函数,发现会报这样的错误:
AttributeError: B.so: undefined symbol: add
就是说依然不识别add函数。使用
1
|
nm B.so | grep add |
能够得到
addc
ABaddCD
这样的结果,第一个 addc 肯定是可以被 python 识别的,第二个 ABaddCD,是g++编译生成的名字,无法被python调用。我这只是举一个自己的例子,我自己的C++动态库的源码可能写的比较复杂,无法被python 成功调用,网上还有很多例子,说的是可以被成功调用。所以读者可以自行试验,如果能够成功调用,自然是最好的。因为接下来要介绍的使用 boost.python的方式比较曲折。
python使用 boost.python 调用c++动态库
解决c++动态库依赖的其他的第三方库
由于我的动态库依赖了其他第三方的库文件,比如openssl,uuid,libevent,pthread,所以,不管是使用哪种办法调用c++动态库,都需要python加载这些动态库,具体python代码如下:
1
2
3
4
5
6
|
from ctypes import * ctypes.CDLL( "libssl.so" , mode = ctypes.RTLD_GLOBAL) ctypes.CDLL( "libcrypto.so" , mode = ctypes.RTLD_GLOBAL) ctypes.CDLL( "libuuid.so") |
【大 中 小】【打印】 【关闭】 【返回顶部】 | |