当前位置: 首页 > news >正文

【C/C++】动态加载(dlopen)和直接链接 库的区别

动态加载(dlopen)方式加载库和直接链接库 有什么区别

动态加载(dlopen 方式)和直接链接库是程序使用外部库的两种不同方式,主要区别体现在加载时机、灵活性、依赖管理等方面,具体如下:

直接链接库 vs. 动态加载 (dlopen) 对比表

特性维度直接链接库动态加载 (dlopen)
1. 加载时机在程序启动时由操作系统自动加载。在程序运行时通过代码手动加载。
2. 灵活性。库在编译时确定,路径和名称固定,更换库通常需重新编译。。可根据配置、用户输入等动态选择加载不同的库,支持热更新。
3. 依赖管理强依赖。程序启动时,所有被链接的库必须存在,否则启动失败。弱依赖。程序启动时不依赖目标库,库不存在时可进行错误处理,程序健壮性更强。
4. 内存占用启动时即加载所有依赖库,内存占用相对固定。按需加载,未使用的库不占用内存,有利于减少内存占用。
5. 符号解析编译链接阶段完成,符号缺失会导致编译错误。运行时通过 dlsym 查找,符号缺失需在代码中判断,否则导致运行时错误。
6. 适用场景核心库、标准库、依赖关系固定的常用库。插件系统、按需加载的功能模块、

1. 加载时机

  • 直接链接库:在程序编译链接阶段就会将库文件(静态库 .a 或动态库 .so/.dll)的信息编入可执行文件中。程序启动时,操作系统会自动加载所需的库到内存中,完成符号解析。
  • 动态加载(dlopen:库的加载推迟到程序运行时。程序通过 dlopen 函数手动指定库文件路径,在需要使用库中功能时才加载,加载后通过 dlsym 获取符号(函数 / 变量)地址来调用。

2. 灵活性

  • 直接链接库:编译时必须明确知道要链接的库,且库的路径和名称在编译后固定。如果需要更换库,通常需要重新编译链接。
  • 动态加载:运行时可以根据条件(如配置文件、用户输入)动态选择加载不同的库,甚至可以在程序运行中卸载(dlclose)并重新加载库,无需重新编译程序。

3. 依赖管理

  • 直接链接库:程序启动时必须能找到依赖的库,否则会启动失败(如 Linux 中报 error while loading shared libraries)。
  • 动态加载:程序启动时不依赖目标库,即使库不存在,也可以通过错误处理(如判断 dlopen 返回值)让程序继续运行,提高了程序的健壮性。

4. 内存占用

  • 直接链接库:所有依赖的库在程序启动时即被加载(动态库会被映射到内存,静态库则被合并到可执行文件)。
  • 动态加载:只在需要时加载库,未使用的库不会占用内存,适合功能模块较多且不常同时使用的场景(如插件系统)。

5. 符号解析

  • 直接链接库:编译链接时会进行符号检查,若库中缺少程序调用的符号,会直接报错。
  • 动态加载:符号解析在运行时进行,编译阶段无法检查符号是否存在,需要在代码中通过 dlsym 调用后判断是否成功,否则可能导致运行时错误(如段错误)。

6. 适用场景

  • 直接链接库:适用于依赖关系固定、启动时就需要加载的核心库(如标准库、常用工具库)。
  • 动态加载:适用于插件系统(如浏览器插件、IDE 插件)、按需加载的功能模块、热更新场景,或需要在运行时选择不同实现的场景。

示例对比

  • 直接链接

    // 编译时需链接 math 库(-lm)
    #include <math.h>
    int main() {double result = sqrt(2.0); // 直接调用库函数return 0;
    }
    
  • 动态加载(dlopen

    #include <dlfcn.h>
    #include <stdio.h>
    int main() {// 运行时加载 math 库void* handle = dlopen("libm.so", RTLD_LAZY);if (!handle) {fprintf(stderr, "dlopen error: %s\n", dlerror());return 1;}// 获取 sqrt 函数地址double (*sqrt_func)(double) = dlsym(handle, "sqrt");if (!sqrt_func) {fprintf(stderr, "dlsym error: %s\n", dlerror());dlclose(handle);return 1;}double result = sqrt_func(2.0); // 调用动态获取的函数dlclose(handle); // 卸载库return 0;
    }
    

总结来说,直接链接库更简单、安全,适合固定依赖;

动态加载更灵活,适合按需加载或动态扩展,但需要手动处理加载、符号解析和错误检查。


ncclResult_t buildIbvSymbols(struct ncclIbvSymbols* ibvSymbols) {static void* ibvhandle = NULL;void* tmp;void** cast;ibvhandle=dlopen("libibverbs.so", RTLD_NOW);if (!ibvhandle) {ibvhandle=dlopen("libibverbs.so.1", RTLD_NOW);if (!ibvhandle) {INFO(NCCL_INIT, "Failed to open libibverbs.so[.1]");goto teardown;}}#define LOAD_SYM(handle, symbol, funcptr) do {           \cast = (void**)&funcptr;                             \tmp = dlvsym(handle, symbol, IBVERBS_VERSION);       \if (tmp == NULL) {                                   \WARN("dlvsym failed on %s - %s version %s", symbol, dlerror(), IBVERBS_VERSION);  \goto teardown;                                     \}                                                    \*cast = tmp;                                         \} while (0)// Attempt to load a specific symbol version - fail silently
#define LOAD_SYM_VERSION(handle, symbol, funcptr, version) do {  \cast = (void**)&funcptr;                                     \*cast = dlvsym(handle, symbol, version);                     \} while (0)LOAD_SYM(ibvhandle, "ibv_get_device_list", ibvSymbols->ibv_internal_get_device_list);LOAD_SYM(ibvhandle, "ibv_free_device_list", ibvSymbols->ibv_internal_free_device_list);LOAD_SYM(ibvhandle, "ibv_get_device_name", ibvSymbols->ibv_internal_get_device_name);LOAD_SYM(ibvhandle, "ibv_open_device", ibvSymbols->ibv_internal_open_device);LOAD_SYM(ibvhandle, "ibv_close_device", ibvSymbols->ibv_internal_close_device);LOAD_SYM(ibvhandle, "ibv_get_async_event", ibvSymbols->ibv_internal_get_async_event);LOAD_SYM(ibvhandle, "ibv_ack_async_event", ibvSymbols->ibv_internal_ack_async_event);LOAD_SYM(ibvhandle, "ibv_query_device", ibvSymbols->ibv_internal_query_device);LOAD_SYM(ibvhandle, "ibv_query_port", ibvSymbols->ibv_internal_query_port);LOAD_SYM(ibvhandle, "ibv_query_gid", ibvSymbols->ibv_internal_query_gid);LOAD_SYM(ibvhandle, "ibv_query_qp", ibvSymbols->ibv_internal_query_qp);LOAD_SYM(ibvhandle, "ibv_alloc_pd", ibvSymbols->ibv_internal_alloc_pd);LOAD_SYM(ibvhandle, "ibv_dealloc_pd", ibvSymbols->ibv_internal_dealloc_pd);LOAD_SYM(ibvhandle, "ibv_reg_mr", ibvSymbols->ibv_internal_reg_mr);// Cherry-pick the ibv_reg_mr_iova2 API from IBVERBS 1.8LOAD_SYM_VERSION(ibvhandle, "ibv_reg_mr_iova2", ibvSymbols->ibv_internal_reg_mr_iova2, "IBVERBS_1.8");// Cherry-pick the ibv_reg_dmabuf_mr API from IBVERBS 1.12LOAD_SYM_VERSION(ibvhandle, "ibv_reg_dmabuf_mr", ibvSymbols->ibv_internal_reg_dmabuf_mr, "IBVERBS_1.12");LOAD_SYM(ibvhandle, "ibv_dereg_mr", ibvSymbols->ibv_internal_dereg_mr);LOAD_SYM(ibvhandle, "ibv_create_cq", ibvSymbols->ibv_internal_create_cq);LOAD_SYM(ibvhandle, "ibv_destroy_cq", ibvSymbols->ibv_internal_destroy_cq);LOAD_SYM(ibvhandle, "ibv_create_qp", ibvSymbols->ibv_internal_create_qp);LOAD_SYM(ibvhandle, "ibv_modify_qp", ibvSymbols->ibv_internal_modify_qp);LOAD_SYM(ibvhandle, "ibv_destroy_qp", ibvSymbols->ibv_internal_destroy_qp);LOAD_SYM(ibvhandle, "ibv_fork_init", ibvSymbols->ibv_internal_fork_init);LOAD_SYM(ibvhandle, "ibv_event_type_str", ibvSymbols->ibv_internal_event_type_str);LOAD_SYM_VERSION(ibvhandle, "ibv_query_ece", ibvSymbols->ibv_internal_query_ece, "IBVERBS_1.10");LOAD_SYM_VERSION(ibvhandle, "ibv_set_ece",   ibvSymbols->ibv_internal_set_ece, "IBVERBS_1.10");return ncclSuccess;teardown:
……if (ibvhandle != NULL) dlclose(ibvhandle);return ncclSystemError;
}

rccl中verbs是动态加载的,所以当使用mlx5中的接口时,如果没有在编译文件中添加连接mlx5的选项就会报错:


ncclResult_t buildIbvSymbols(struct ncclIbvSymbols* ibvSymbols) {static void* ibvhandle = NULL;void* tmp;void** cast;ibvhandle=dlopen("libibverbs.so", RTLD_NOW);if (!ibvhandle) {ibvhandle=dlopen("libibverbs.so.1", RTLD_NOW);if (!ibvhandle) {INFO(NCCL_INIT, "Failed to open libibverbs.so[.1]");goto teardown;}}

http://www.dtcms.com/a/529034.html

相关文章:

  • 集团内部协同项目管理模式整理表
  • 基于yolov11的机场跑道异物检测系统python源码+pytorch模型+训练数据集+精美GUI界面
  • 【开题答辩全过程】以 滨海游泳馆管理系统为例,包含答辩的问题和答案
  • 阿里云网站实名认证设备租赁业务网站如何做
  • 2025年9月电子学会全国青少年软件编程等级考试(scratch图形化四级)真题及答案
  • 中国万网icp网站备案专题wordpress播放器问题
  • MATLAB图形绘制基础(一)二维图形
  • 软件开发和网站建设泰安网站设计
  • 一文读懂 AUTOSAR 中的 CAN 模块:通俗图解与发送接收全流程
  • 弹窗网站制作器中国空间站
  • 网站建设会议纪要wordpress创建页面地址设置
  • 软装设计素材网站地方宣传网站建设的必要性
  • Auto CAD二次开发——创建圆弧对象
  • 深度解析pose_add:三维空间位姿复合运算的核心实现
  • LeetCode 153. 寻找旋转排序数组中的最小值
  • 做外汇看什么网站怎样做建网站做淘客
  • 网站设计说明书800字o2o网站做推广公司
  • 【Linux】传输层协议UDP
  • 网站制作的主要流程零基础建设网站视频教程
  • Flutter 异步体系终章:FutureBuilder 与 StreamBuilder 架构优化指南
  • 刷题集(13)
  • 洮南市城乡和住房建设局网站深圳十大景观设计公司排名
  • discuz 旅游网站模版做外贸推广的网站有哪些
  • 遵义做百度网站一年多少钱定制开发网站如何报价单
  • 玛哈特整平机助力苹果17的不锈钢电池壳多重提升
  • 第 10 天:环境变量、别名与 Shell 自定义
  • 网站安全太复杂?雷池SafeLine+cpolar实现“躺平式”防护!
  • Spring环境配置与属性管理完全指南
  • Java_final关键字
  • 2025年9月电子学会全国青少年软件编程等级考试(scratch图形化一级)真题及答案