共计 1895 个字符,预计需要花费 5 分钟才能阅读完成。
导读 | 这篇文章主要为大家详细介绍了 C 语言中 dlopen 和 dlsym 的使用方式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助 |
背景
为了是不同的逻辑解耦,一般会把各个业务封装成动态库,然后主逻辑去调用各个插件。这里有个问题是,为什么以前我们都是通过 include 第三方的头文件,然后通过连接器实现,现在却要利用 dlopen 呢?考虑以下情况,比如我们要用 cublas 这个库的 sgemm 函数。
int main() | |
{ | |
cublas:: Mat a, b; | |
cublas::sgemm(a,b); | |
} |
我们知道 cublas 是英伟达提供的,人家每年都要更新动态库的,比如今年更新后,动态库的头文件改了 cublas_v2.h, 函数名改为 sgemm_v2, 这样一顿操作后,你不仅要升级库,也要修改已经上线的代码,假如这个 sgemm 函数在你源码中出现了 n 多次,这将是一个灾难。但是通过下面的方式你就可以避免这个问题:
// func.h | |
extern std::once_flag cublas_dso_flag; | |
extern void *cublas_dso_handle; | |
struct DynLoad__add {template | |
inline auto operator()(Args... args) -> DECLARE_TYPE(add, args...) | |
{using cublas_func = decltype(::add(std::declval()...)) (*)(Args...); | |
std::call_once(cublas_dso_flag, []() {cublas_dso_handle = dlopen("./libcublas.so", RTLD_LAZY); | |
}); | |
static void *p_add = dlsym(cublas_dso_handle, "add"); | |
return reinterpret_cast(p_add)(args...); | |
} | |
}; | |
extern DynLoad__add add; | |
// func.c | |
DynLoad__add add; | |
// main.cc | |
int main() | |
{add(2,7)); | |
} |
根据上面的代码可以看到,只要你每次修改 func.h 文件的动态库路劲和函数名就可以了,其他用到的 add 函数根本不需要再去修改。真是很方便,上面的代码参考 paddle 的源码:paddle/fluid/platform/dynload/cublas.h
demo
生产动态库
int add(int a,int b) | |
{return (a + b); | |
} | |
int sub(int a, int b) | |
{return (a - b); | |
} |
gcc -fPIC -shared caculate.c -o libcaculate.so
调用 dlopen
void *dlopen(const char *filename, int flag); | |
char *dlerror(void); | |
void *dlsym(void *handle, const char *symbol); | |
int dlclose(void *handle); |
dlopen 是加载动态链接库,flag 可以设置不同的模式 (RTLD_LAZY 暂缓决定,等有需要时再解出符号, RTLD_NOW 立即决定,返回前解除所有未决定的符号。), dlopen 可以返回动态库的句柄,dlsym 是获取动态库中的具体函数名或者变量名。dlopen 是关闭动态库。
typedef int (*FUNC)(int, int); | |
int main() | |
{ | |
void *handle; | |
char *error; | |
FUNC func = NULL; | |
// 打开动态链接库 | |
handle = dlopen("./libcaculate.so", RTLD_LAZY); | |
// 获取一个函数 | |
*(void **) (&func) = dlsym(handle, "add"); | |
printf("add: %d\n", (*func)(2,7)); | |
// 关闭动态链接库 | |
dlclose(handle); | |
} |
gcc -rdynamic -o main main.c -ldl
本篇文章就到这里了,希望能够给你带来帮助.
正文完
星哥玩云-微信公众号
