良许Linux教程网 干货合集 详解C语言中dlopen和dlsym

详解C语言中dlopen和dlsym

这篇文章主要为大家详细介绍了C语言中dlopen和dlsym的使用方式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

image-20220621225609602


背景

为了是不同的逻辑解耦,一般会把各个业务封装成动态库,然后主逻辑去调用各个插件。这里有个问题是,为什么以前我们都是通过include第三方的头文件,然后通过连接器实现,现在却要利用dlopen呢?考虑以下情况,比如我们要用cublas这个库的sgemm函数。

#include "cublas.h"
int main()
{
    cublas:: Mat a, b;
    cublas::sgemm(a,b);
}

我们知道cublas是英伟达提供的,人家每年都要更新动态库的,比如今年更新后,动态库的头文件改了cublas_v2.h, 函数名改为sgemm_v2, 这样一顿操作后,你不仅要升级库,也要修改已经上线的代码,假如这个sgemm函数在你源码中出现了n多次,这将是一个灾难。但是通过下面的方式你就可以避免这个问题:

// func.h
#include 
#include 
#include  // 如果你知道确切的函数返回信息,这个对应下面的cublas_func可以自己写。
#include 
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
#include 
#include 
#include "func.h"
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

#include 
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是关闭动态库。

#include 
#include 
#include 
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

本篇文章就到这里了,希望能够给你带来帮助.

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

邮箱地址不会被公开。 必填项已用*标注

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部