最近在使用SPP网络框架进行业务开发的时候,遭遇动态库搜索路径问题,为了避免其他同学继续在这方面浪费精力,简单整理了相关知识点。
【背景知识】
这里不打算深入链接器内部,简明扼要给出链接器进行动态库搜索的一些规则。
以上是man ld结果部分截图,这里着重澄清两个基本概念:"link time"(链接时)和"runtime"(运行时),比如常用的-L选项属于链接时,而-rpath,LD_LIBRARY_PATH都属于运行时。
很多运维同学倾向于使用LD_LIBRARY_PATH,但是个人认为这并不是一种好方法,因为LD_LIBRARY_PATH作用于全局,可能对其他程序造成未预期的影响。有兴趣的同学可以读一读《Why
LD_LIBRARY_PATH is bad》,这篇文章有比较全面的分析。
【实践检验】
目录文件:
// main.c #include <dlfcn.h> typedef void (*FuncA)(void); int main(int argc, char *argv[]) { void *plugin = dlopen("./libfunc_a.so", RTLD_LAZY); FuncA func = (FuncA)dlsym(plugin, "FuncA"); func(); return 0; }
// func_a.c #include <stdio.h> void FuncB(void); void FuncA(void) { printf("[%s]%s:%d\n", __FUNCTION__, __FILE__, __LINE__); FuncB(); }
// func_b_sys.c // func_b_user.c #include <stdio.h> void FuncB(void) { printf("[%s]%s:%d\n", __FUNCTION__, __FILE__, __LINE__); }
# Makefile all: gcc -g -Wall -fPIC -shared -o libfunc_b_sys.so func_b_sys.c gcc -g -Wall -fPIC -shared -o libfunc_b_user.so func_b_user.c ln -sf /data/warezhou/test/ld/libfunc_b_sys.so /usr/lib64/libfunc_b.so ln -sf /data/warezhou/test/ld/libfunc_b_user.so ./lib/libfunc_b.so gcc -g -Wall -fPIC -shared -o libfunc_a.so func_a.c -lfunc_b gcc -g -Wall -o main main.c -ldl gcc -g -Wall -o main_rpath main.c -ldl -Wl,--rpath=./lib,--disable-new-dtags gcc -g -Wall -o main_rpath_runpath main.c -ldl -Wl,--rpath=./lib,--enable-new-dtags clean: rm main main_rpath main_rpath_runpath rm -rf *.so rm -rf /usr/lib64/libfunc_b.so rm -rf ./lib/*
实验结果:
【原因分析】
上图关于动态库搜索路径的总结来自qt工程师的blog,有兴趣的同学可以阅读原文。简单来说,当可执行文件同时设置RPATH和RUNPATH时,两者同时失效。
查看SPP源码后,发现Makefile里面没有显式指定disable-new-dtags,而这个选项的默认值是平台相关的,我们公司老的suse默认关闭,而新的tlinux默认开启。所以导致发行包里的可执行文件同时设置了RPATH和RUNPATH,最终导致业务模块.so依赖的第三方.so查找不到。
当然,上述问题,通过设置libfunc_a.so的RPATH也是可以解决问题的,有兴趣的同学可以试一试,因为整个搜索过程是递归向上执行的。
时间: 2024-10-11 21:12:25