工作中有时会遇到可执行程序运行时使用指定目录下的动态库,若是直接修改环境变量,可能会对其他程序产生影响,因此可以在编译时使用-Wl,rpath来指定运行时路径。
比如 /home/lib 下存在 libtest.so , /home/test 下存在 test.c 和 libtest.so文件,编译出的可执行文件依赖动态库 libtest.so
/home
|--lib
-libtest.so
|--test
- test.c
- libtest.so
假设想让可执行文件运行时使用lib下的动态库,可以使用如下命令
gcc -o test test.c -L./ libtest.so -Wl,-rpath='$ORIGIN/../lib'
其中 -L./ libtest.so 表示编译时使用当前目录下的 libtest.so 进行编译
-Wl,-rpath=’$ORIGIN/…/lib’ 表示运行可执行文件时,从 …/lib 中寻找所需要的动态库。
可以使用ldd命令查看可执行程序的依赖
# ldd test
libtest.so => /home/test/../lib/libtest.so
通过 ldd 命令可知,test 运行时使用的动态库路径为 /home/test/…/lib
还有一种情况是可执行程序test使用的动态库为 libtest.so 而编译时使用的是libtest.so.1.1
比如目录就结构如下
/home
|--lib
-libtest.so.1.1
|--test
- test.c
- libtest.so.1.1
编译生成可执行文件
gcc -o test test.c -L./ libtest.so.1.1 -Wl,-rpath='$ORIGIN/../lib'
运行 ldd 时发现找不到动态库 libtest.so
# ldd test
libtest.so => not found
原因是运行test时他需要的动态库的名字为libtest.so 而 lib 中存放的是libtest.so.1.1, 名字不一样,因此找不到动态库。
解决办法
1、可以把 lib 下的 libtest.so.1.1 名字改为 libtest.so
2、也可以在 lib 下创建一个 libtest.so.1.1 的软连接
# cd lib
# ln -s libtest.so.1.1 libtest.so
# ls
libtest.so libtest.so.1.1
# ldd test
libtest.so => /home/test/../lib/libtest.so
附:
我们编译程序时会常常遇到如下你几个参数
-I (大写的i)
-L (大写l)
-l (小写l)
接下来对这几个参数进行简单的讲解。
先举个例子:
gcc -o test test.c -I /home/test/include -L/home/test/lib -ltest
编译test时:
-I /home/test/include 表示将 /home/test/include 目录作为第一个寻找头文件的目录,其寻找的顺序是:
/home/test/include --> /usr/include --> /usr/local/include
-L/home/test/lib 表示将 /home/test/lib 目录作为第一个寻找库文件的目录,其寻找的顺序是:
/home/test/lib --> /lib -> /usr/lib --> /usr/local/lib
-ltest 表示在上面的lib的路径中寻找 libtest.so 动态库文件(如果 gcc 编译选项中加入了“-static”表示寻找 libtest.a 静态库文件),程序链接的库名是test。
-l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那库名跟真正的库文件名有什么关系呢?
比如数学库,他的库名是 m,他的库文件名是 libm.so,把库文件名的头 lib和尾 .so 去掉就是库名了。
比如当我们使用第三方提供的库名字叫libtest.so,那么我们只要把 libtest.so拷贝到 /usr/lib 里,编译时加上 -ltest 参数,我们就能用上 libtest.so 库了(当然要用 libtest.so 库里的函数,我们还需要与 libtest.so 配套的头文件)。
对于放在 /lib 和 /usr/lib 和 /usr/local/lib 里的库直接用-l参数就能链接了,但如果库文件没放在这三个目录里,而是放在其他目录里,若此时我们只用-l参数的话,链接还是会出错,出错信息大概是:
/usr/bin/ld: cannot find -lxx
也就是说链接程序ld在那3个目录里找不到 libxx.so,这个时候另外一个参数-L就派上用场了。
比如我们使用 test 库 它放在 /usr/test/lib 目录下,我们编译时就要用
-L/usr/test/lib -ltest 参数,-L 参数跟着的是库文件所在的目录名。
再比如我们把libtest.so放在 /var/bbb 目录下,那链接参数就是
-L/var/bbb -ltest
另外,大部分libxx.so只是一个链接,比如libm.so它链接到 lib/libm.so.6,/lib/libm.so.6 又链接到 /lib/libm-2.3.2.so,
如果没有这样的链接,我们运行可执行程序时可能还是会出错,因为 ld 只会找libxx.so。
所以如果你要用到 xx 库,而只有 libxx.so.x 或者 libxx-x.x.x.so 时,做一个软链接就可以了。
命令如下:
ln -s libxx-x.x.x.so libxx.so