网上有很多C语言编译so库的方法,用C++的偏少,遇见了一些坑,这里记录一下,以作参照。
生成so库
先实现一个最简单的函数,libtest.cpp(先不考虑extern "C"这句话):
#include<iostream>
//extern "C"
double ddd(double a){
return a*2;
}
linux 命令(注意这里生成动态库文件时要加上-fPIC -shared):
[root@localhost jay]# g++ -fPIC -shared libtest.cpp -o libtest.so
至此,so库文件完成。
调用so库
初探
main.cpp(这是最常见,最自然的写法):
#include<iostream>
#include<dlfcn.h>
//extern "C"
int main(){
void *handle = dlopen("./libtest.so",RTLD_LAZY);
double (*ans) (double);
char *error;
ans = (double(*)(double))dlsym(handle,"ddd");
//ans = (double(*)(double))dlsym(handle,"_Z3dddd");
std::cout<<(*ans)(2.0)<<std::endl;
dlclose(handle);
return 0;
}
Linux命令:
[root@localhost jay]# g++ -o a.out main.cpp -ldl
可以成功执行,然而:
[root@localhost jay]# ./a.out
段错误
解决
因为发现别人用C语言都是可以正常编译的,找到wwxxlld大佬的这篇文章,利用ldd命令发现没有依赖缺失情况,使用nm命令:
发现是g++编译器会将函数名进行优化,以便实现c++的重载。所以最简单的方法就是给外部使用的函数需要加上声明,extern “C” 函数名 ,让编译器编译时以c语言的方式去编译,不要优化该函数名,或者直接全局声明 extern “C” :
当然,你也可以直接调用最开始nm得到的g++优化后的新函数名 _Z3dddd……(虽然似乎有点蠢)。
不管怎样,现在问题都能解决了:
[root@localhost jay]# g++ -o a.out main.cpp -ldl
[root@localhost jay]# ./a.out
4
参考资料
[1]: Linux 动态加载并调用动态库(.so)方法介绍
[2]: linux中的nm命令简介
[3]: 程序调用动态库,编译通过,调用动态库函数运行出现undefined symbol错误