指定共享库搜索路径的几种方式
Linux 上有三种方式指定运行时动态链接库的搜索路径, 按照优先级顺序从高到低依次是:
- rpath
- LD_LIBRARY_PATH
- runpath
假设我们有一个程序 a.out 动态链接 liba.so
1 | $ g++ -g -W -fPIC -shared lib.cc -o liba.so |
然后将 liba.so 拷贝到两个独立的目录中:
1 2 | $ mkdir 1 2 $ cp liba.so 1; cp liba.so 2 |
目录结构如下
1 2 3 4 5 6 7 8 9 10 | $ tree . ├── 1 │ └── liba.so ├── 2 │ └── liba.so ├── a.out ├── lib.cc ├── main.cc └── Makefile |
使用 -Wl,–enable-new-dtags 参数,通过 gcc 告诉 linker (ld, ld.gold, lld) 使用新的 dtags,即 runpath
1 2 3 4 | $ g++ -g -W -Wl,--enable-new-dtags -Wl,-rpath='$ORIGIN/1' main.cc liba.so -o a.out $ objdump -x a.out |grep PATH RUNPATH $ORIGIN/1 |
运行时通过环境变量 LD_LIBRARY_PATH 指定共享库查找路径为目录 2;通过调试动态链接器,可以看到优先在目录 2 中寻找 liba.so,即 LD_LIBRARY_PATH 的优先级高于 runpath.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $ LD_LIBRARY_PATH=$PWD/2 LD_DEBUG=libs ./a.out find library=liba.so [0]; searching search path=/home/joy/2/tls:/home/joy/2/x86_64:/home/joy/2 (LD_LIBRARY_PATH) trying file=/home/joy/2/tls/x86_64/liba.so trying file=/home/joy/2/tls/liba.so trying file=/home/joy/2/x86_64/liba.so trying file=/home/joy/2/liba.so find library=libc.so.6 [0]; searching search path=/home/joy/2 (LD_LIBRARY_PATH) trying file=/home/joy/2/libc.so.6 search path=/home/joy/1/tls:/home/joy/1/x86_64:/home/joy/1 (RUNPATH from file ./a.out) trying file=/home/joy/1/tls/x86_64/libc.so.6 trying file=/home/joy/1/tls/libc.so.6 trying file=/home/joy/1/x86_64/libc.so.6 trying file=/home/joy/1/libc.so.6 search cache=/etc/ld.so.cache trying file=/lib/x86_64-linux-gnu/libc.so.6 calling init: /lib/x86_64-linux-gnu/libc.so.6 calling init: /home/joy/2/liba.so initialize program: ./a.out transferring control: ./a.out calling fini: ./a.out [0] calling fini: /home/joy/2/liba.so [0] |
如果不指定 –enable-new-dtags 这个 linker 参数,或者使用 –disable-new-dtags,则会使用旧的 dtags,即 rpath
1 2 3 4 | $ g++ -g -W -Wl,--disable-new-dtags -Wl,-rpath='$ORIGIN/1' main.cc liba.so -o a.out $ objdump -x a.out |grep PATH RPATH $ORIGIN/1 |
运行时通过环境变量 LD_LIBRARY_PATH 指定共享库查找路径为目录 2;通过调试动态链接器,可以看到优先在目录 1 中寻找 liba.so;即 rpath 的优先级高于 LD_LIBRARY_PATH.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | $ LD_LIBRARY_PATH=$PWD/2 LD_DEBUG=libs ./a.out find library=liba.so [0]; searching search path=/home/joy/1/tls:/home/joy/1/x86_64:/home/joy/1 (RPATH from file ./a.out) trying file=/home/joy/1/tls/x86_64/liba.so trying file=/home/joy/1/tls/liba.so trying file=/home/joy/1/x86_64/liba.so trying file=/home/joy/1/liba.so find library=libc.so.6 [0]; searching search path=/home/joy/1 (RPATH from file ./a.out) trying file=/home/joy/1/libc.so.6 search path=/home/joy/2/tls:/home/joy/2/x86_64:/home/joy/2 (LD_LIBRARY_PATH) trying file=/home/joy/2/tls/x86_64/libc.so.6 trying file=/home/joy/2/tls/libc.so.6 trying file=/home/joy/2/x86_64/libc.so.6 trying file=/home/joy/2/libc.so.6 search cache=/etc/ld.so.cache trying file=/lib/x86_64-linux-gnu/libc.so.6 calling init: /lib/x86_64-linux-gnu/libc.so.6 calling init: /home/joy/1/liba.so initialize program: ./a.out transferring control: ./a.out calling fini: ./a.out [0] calling fini: /home/joy/1/liba.so [0] |