在 Linux 系统中,动态链接库(.so 文件)是实现代码模块化和资源共享的重要方式,与静态库(.a 文件)不同,动态库在程序运行时才被加载到内存,多个程序可共享同一份库文件,节省存储空间并便于更新,调用 so 库主要分为编译时链接和运行时加载两种方式,本文将详细介绍具体操作步骤及注意事项。
创建 so 动态库
首先需要编写源代码并编译为 so 文件,以简单的加法函数为例,创建 add.c
文件:
// add.c int add(int a, int b) { return a + b; }
编译时需添加 -fPIC
(生成位置无关代码,确保库可在任意内存地址加载)和 -shared
(生成共享库)选项:
gcc -fPIC -shared add.c -o libadd.so
执行后会生成 libadd.so
文件,即动态库文件名通常以 lib
开头,.so
编译时调用 so 库(静态绑定)
若程序在编译阶段明确需要链接 so 库,可通过 -l
选项指定库名(去掉 lib
和 .so
后缀),并用 -L
指定库的搜索路径,假设调用库的 main.c
如下:
// main.c #include <stdio.h> extern int add(int a, int b); // 声明外部函数 int main() { int result = add(3, 5); printf("3 + 5 = %dn", result); return 0; }
编译时需链接 libadd.so
,并指定头文件路径(若有)和库路径:
gcc main.c -L. -ladd -o main
参数说明:
-L.
:表示在当前目录搜索库文件(默认搜索/usr/lib
等系统路径)。-ladd
:链接libadd.so
库。
编译后生成可执行文件 main
,运行时需确保 libadd.so
在系统库路径(如 /usr/lib
)或通过 LD_LIBRARY_PATH
指定路径,否则会报错“cannot open shared object file”。
运行时调用 so 库(动态绑定)
运行时加载(动态绑定)允许程序在运行过程中按需加载 so 库,适用于插件化或延迟加载场景,核心函数包括 dlopen
(打开库)、dlsym
(获取符号地址)、dlclose
(关闭库)和 dlerror
(获取错误信息)。
仍以 libadd.so
为例,创建 main_rt.c
:
// main_rt.c #include <stdio.h> #include <dlfcn.h> int main() { void *handle = dlopen("./libadd.so", RTLD_LAZY); // 延迟加载符号 if (!handle) { fprintf(stderr, "dlopen error: %sn", dlerror()); return 1; } // 获取 add 函数地址 int (*add_func)(int, int) = dlsym(handle, "add"); if (!add_func) { fprintf(stderr, "dlsym error: %sn", dlerror()); dlclose(handle); return 1; } int result = add_func(3, 5); printf("3 + 5 = %dn", result); dlclose(handle); // 关闭库 return 0; }
编译时需链接 dl
库(提供动态加载功能):
gcc main_rt.c -ldl -o main_rt
运行时直接执行 ./main_rt
,无需额外配置路径(因指定了 ./libadd.so
)。
动态加载函数说明
函数名 | 功能 | 参数说明 |
---|---|---|
dlopen |
打开动态库 | 参数1:库路径(绝对/相对路径);参数2:标志位(如 RTLD_LAZY 延迟加载) |
dlsym |
获取库中符号(函数/变量) | 参数1:dlopen 返回的句柄;参数2:符号名称(字符串) |
dlclose |
关闭动态库 | 参数:dlopen 返回的句柄 |
dlerror |
获取动态链接错误信息 | 无参数,返回错误字符串(若成功则返回 NULL ) |
环境变量配置
若 so 库不在系统默认路径(如 /usr/lib
),可通过 LD_LIBRARY_PATH
环境变量指定搜索路径,
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./ # 添加当前路径 ./main # 运行编译时链接的程序
临时设置仅对当前终端有效,若需永久生效,可写入 ~/.bashrc
或 /etc/ld.so.conf
并执行 ldconfig
更新缓存。
相关问答 FAQs
问题1:编译时报错 “undefined reference to 'add'” 是什么原因?如何解决?
解答:该错误表示链接阶段未找到 add
函数的定义,可能原因包括:未使用 -ladd
链接库、库路径未通过 -L
指定、库名与实际文件名不匹配(如文件名为 libadd.so
但编译时误用 -ladd.so
),解决方法:检查编译命令是否正确包含 -l库名
和 -L路径
,确保库文件存在且库名去掉 lib
和 .so
后缀。
问题2:运行时报错 “cannot open shared object file: No such file or directory” 如何处理?
解答:该错误表示运行时找不到 so 库,解决方法:
- 使用
ldd
命令检查程序依赖的库路径:ldd main
,查看libadd.so
是否显示为not found
; - 若库在非标准路径,可通过
LD_LIBRARY_PATH
指定:export LD_LIBRARY_PATH=/your/lib/path:$LD_LIBRARY_PATH
; - 将库文件复制到系统默认路径(如
/usr/lib
)并执行ldconfig
更新缓存。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/23216.html