使用dlopen()加载依赖其他共享库的so文件报错如何解决
问题现象
使用dlopen()加载依赖其他共享库的目标库时,抛出报错:cannot open shared object file: No such file or directory
复现代码:
void *handle; char *error; handle = dlopen("lib/mylib.so", RTLD_NOW | RTLD_GLOBAL); if (!handle) { fprintf(stderr, "%s\n", dlerror()); exit(EXIT_FAILURE); } dlerror();
报错原因
dlopen()加载指定共享库时,动态链接器会自动递归加载该库依赖的所有下游共享库,查找下游依赖时不会参考你传入的lib/mylib.so路径前缀,只会按照动态链接器默认的搜索规则定位文件,当依赖库不在搜索路径范围内时就会触发该报错。另外你传入的是相对路径,程序工作目录变化时,连mylib.so本身都可能加载失败。
解决方案
- 编译目标库时写入RPATH(推荐,适配便携部署)
编译mylib.so时给链接器传rpath参数,指定依赖库相对于当前库文件的搜索路径,动态链接器内置$ORIGIN变量代表当前加载库所在的绝对目录:- 如果依赖库和
mylib.so同在lib/目录下,编译参数加-Wl,-rpath,'$ORIGIN' - 如果依赖库在
mylib.so所在目录的子目录,比如lib/deps/,就写-Wl,-rpath,'$ORIGIN/deps'
示例编译命令:
注意gcc -shared -fPIC mylib.c -o lib/mylib.so -lyour_dep_lib -Wl,-rpath,'$ORIGIN'$ORIGIN必须用单引号包裹,避免被Shell提前解析为错误值。 - 如果依赖库和
- 进程启动阶段提前设置动态库搜索路径
在调用dlopen()之前,通过setenv把依赖库所在目录加入LD_LIBRARY_PATH环境变量,该变量是动态链接器识别的额外搜索路径,注意设置逻辑要放在程序启动的最早期,避免链接器初始化完成后配置不生效:// 示例:将./lib目录加入搜索路径,生产环境建议替换为基于程序安装位置拼接的绝对路径 setenv("LD_LIBRARY_PATH", "./lib", 1); handle = dlopen("lib/mylib.so", RTLD_NOW | RTLD_GLOBAL); - 配置系统全局动态库搜索路径(适合全局部署场景)
有root权限的情况下,将依赖库所在的绝对路径写入/etc/ld.so.conf.d/目录下的.conf配置文件,执行ldconfig命令刷新动态库缓存后,系统所有进程都能搜索到对应路径下的共享库。 - 按依赖顺序提前加载所有下游库
明确所有依赖层级的前提下,可以先逐个调用dlopen(依赖库路径, RTLD_NOW | RTLD_GLOBAL)加载所有依赖库,再加载目标mylib.so,此时链接器发现依赖已经存在于进程地址空间,就不会再执行文件搜索逻辑。
排查技巧
执行ldd lib/mylib.so命令,输出结果中标记为not found的行就是缺失的依赖库,可以直接定位问题点,无需盲目猜是哪个库加载失败。
内容的提问来源于stack exchange,提问作者phorever
相关产品推荐
相关产品推荐

