当编译可执行程序时,若采用隐式链接,那么需要在编译时为可执行程序指定运行时动态库搜索地址,即利用rpath选项来告诉链接器在程序执行时到哪里去找它依赖的动态库。例子如下:
-Wl,-rpath,<path/to/lib>
注:有的编译器也支持-Wl,rpath = <path/to/lib>这种用法
那么,这里的路径应该采用相对路径还是绝对路径呢?
答:在rpath中使用相对路径是没有意义的,因为相对路径是相对于当前工作路径,而非相对于可执行程序本身所在的路径!!
举个例子:在home/test/下有个可执行程序mytest,它的依赖库是home/lib/下的mylib,在编译mytest时使用的命令是:
-Wl,-rpath,../lib
也就是告诉mytest,它依赖于一个动态库,动态库的运行时路径是../lib。那么,当cd到test下执行mytest时,可以成功运行;但假如切换到home下再执行/test/mytest,由于此时的工作路径是home,相对于当前路径并没有../lib,所以就找不到动态库了。
正确用法是利用$ORIGIN这个符号:
-Wl,-rpath,$ORIGIN../lib
这里的$ORIGIN代表了可执行文件所在的地址,那么,无论从什么位置唤醒(invoke)可执行程序,它都会从可执行程序所在的路径的../lib位置去找动态库。
事实上,$ORIGIN是一个ELF替代序列,代表了被载入的可执行程序在文件系统中所处的位置。其目的是允许可执行程序去指定一个动态库的相对搜索路径。在编译mytest时,这个符号被保留在mytes中。当我从home下执行/test/mytest时,runtime linker会把$ORIGIN替换为home/test/,那么动态库的位置就变成了home/test/../lib,也就是home/lib
后记:为了不被shell解释器误认为是一个变量,你需要使用单引号将$ORIGIN扩起来,像这样:
-Wl,-rpath,‘$ORIGIN’
如果你想在makefile中使用它,那么你还需要写成这样:
-Wl,-rpath,‘$$ORIGIN’
使用两个$$是因为:若只使用一个$,$O连在一起会被make认为是makefile自身定义的变量。
对于运行时加载器(或运行时链接器)是怎么去搜索动态库的,可使用man ld.so来查看更详细的说明。