2013.08.23 updated
一 概念:这里将共享库(shared library)称做了动态库。
在Linux中,ELF格式的可执行文件或动态库有两个域,DT_RPATH,DT_RUNPATH(这个是新版本加入的)。
// 这个方法只写入DT_RPATH域 gcc -g -Wall -o prog prog.c -Wl,-rpath,/home/dir1 -ldemo // 这个方法,同时写入DT_RPATH和DT_RUNPATH gcc -g -Wall -o prog prog.c -Wl,--enable-new-dtags -Wl,-rpath,/home/dir1 -ldemo
编译分为几个阶段,其中-W表示在哪个阶段将后面参数加入,-Wl表示在link阶段加入后面参数,-rpath是为linker指定runtime dynamic path参数。
至于为什么后面的要同时写入DT_RPATH和DT_RUNPATH域,是因为之前的版本没有DT_RUNTIME,为了和老版本程序兼容。
0> 如果DT_RUNPATH域为空,且DT_RPATH不为空,则搜索DT_RPATH指定的路径列表(多个用冒号隔开);
1> 环境变量LD_LIBRARY_PATH指定的动态库搜索路径,多个路径可以用“:”分开;
2> 如果DT_RUNPATH不为空,那么搜索DT_RUNPATH对应的路径列表;
3> 在/etc/ld.so.cache文件中指定,这个文件是一个二进制文件,如果想添加,先编辑配置文件/etc/ld.so.conf(这个文件是文本的),然后运行ldconfig生成新的/etc/ld.so.cache;
4> 默认的动态库搜索路径/lib;
5> 默认的动态库搜索路径/usr/lib。
以下是使用LD_LIBRARY_PATH的建议:
1> 不要全局设置LD_LIBRARY_PATH
2> 如果一定要用动态库的方式发布你的代码,并且允许用户自定义安装路径,那么
讲一个我亲身体验的例子。
一个已经安装的软件包A,构建于平台Platform 1.0,所有的平台相关动态库文件位于/opt/lib64/
一个新的软件包B,构建于平台Platform 2.0,所有平台相关动态库位于本软件目录的/lib下
启动软件B,发现运行错误,运行ldd命令,发现连接的动态库不对,应该连本目录的lib,却连到了/opt/lib64/
用设置LD_LIBRARY_PATH的方法启动还是不行,因为路径已经写死到可执行文件里了,用strings命令可以看到二进制里的字符串。
后来查到两种解决办法:
1> 用二进制编辑器将可执行文件内的路径改写,/opt/lib64改成/opt/lib65,这样运行时找不到/opt/lib65,那么LD_LIBRARY_PATH就开始生效了。
2> 编译B之前,将configure.ac中的路径修改一下,使得传递给-Wl,-rpath的参数是一个不可能存在的路径。