编译器可以通过-Wl将选项传递给链接器ld。
例如指定动态库搜索路径,see also ^0d5d11
gcc -Wl,-rpath=./
# 等价于
gcc -Wl,rpath,./
# 传多个path
gcc -Wl,-rpath=/path1,-rpath=/path2
gcc -Wl,-rpath=/path1 -Wl,-rpath=/path2上面的命令其实会将这些路径写到elf文件的rpath/runpath字段下。然后运行时会读取这个路径去检索其以来的动态库。
今天(26/7/10)又踩了一个坑。如果你的代码要连接一个外部库A,但是libA.so依然依赖A1, A2, A3. 为了让你的程序(假设叫myapp)正确链接A,你已经知道要在编译选项里面加上
gcc -Wl,-rpath=/path/to/libA但是对于动态库 libA.so 本身的依赖,诸如 libA1.so, libA2.so 等等,运行时不会再根据 myapp 的 rpath 去搜索它们。表现出来的结果就是,
$ ldd myapp
libA.so => /path/to/libA.so
libA1.so => not found
libA2.so => not found
...即便libA1.so, libA2.so就和libA.so在同一目录下也不行!这就是动态库的依赖链,顶层程序的 rpath 用于搜索它的一级依赖,一级依赖本身的依赖,会用一级依赖本身的 rpath(而非 myapp 的 rpath)去搜索。而一级依赖本身的 rpath 通常是别人提供的,其目录于你本地目录迥然不同,所以通常是找不到的。这种情况下,只好把所有依赖库全部拷到当前目录(因为别人提供rpath通常带当前目录)。或者设置 LD_LIBRARY_PATH 环境变量,
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/libA
./myapp举个例子,
$ ldd libfxcm.so
linux-vdso.so.1 (0x00007fffa44f3000)
libForexConnect.so => /home/yychi/code/mdl_src/3rd/libs/forexconnect/libForexConnect.so (0x00007f712be3c000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f712bc46000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f712bc2b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f712ba39000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f712ba14000)
libgsexpat.so => not found
libfxtp.so => not found
libfxmsg.so => not found
libgstool3.so => not found
liblog4cplus.so => not foundlibfxcm.so是我自己编出来的,我指定了 rpath 为 /home/yychi/code/mdl_src/3rd/libs/forexconnect. 所以我的直接依赖 libForexconnect.so 可以被找到。但是 libForexconnect.so 本身的那些依赖都是 not found. 可以通过下面的命令查看rpath/runpath,
$ readelf -d libfxcm.so|grep -iE 'rpath|runpath'
0x000000000000001d (RUNPATH) Library runpath: [./:./bin:/usr/local/lib:/yychi/code/mdl_src/3rd/libs/forexconnect]
$ readelf -d ../../3rd/libs/forexconnect/libForexConnect.so | grep -i rpath
0x000000000000000f (RPATH) Library rpath: [.:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/CandleWorks/WindowsTradingApplications/Order2Go2/cpp/../../../../3rd_party/expat/lib:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/CandleWorks/WindowsTradingApplications/Order2Go2/cpp/../../../../3rd_party/expat:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/CandleWorks/WindowsTradingApplications/Order2Go2/cpp/../../../../3rd_party/log4cplus:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/CandleWorks/WindowsTradingApplications/Order2Go2/cpp/../../../../3rd_party/zlib:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/CandleWorks/WindowsTradingApplications/Order2Go2/cpp/../../../../3rd_party/gehtsoft/gstool3/lib:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/CandleWorks/WindowsTradingApplications/Order2Go2/cpp/../../../../FXCM_SRC/fxtc:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/CandleWorks/WindowsTradingApplications/Order2Go2/cpp/../../../../FXCM_SRC/Tiramisu/messaging/cpp/fxmsg/lib:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/CandleWorks/WindowsTradingApplications/Order2Go2/cpp/../../../../FXCM_SRC/Tiramisu/messaging/cpp/fxtp/lib:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/CandleWorks/WindowsTradingApplications/Order2Go2/cpp/../../../../3rd_party/CppEvents/lib:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/FXCM_SRC/Tiramisu/messaging/cpp/fxtp/lib:/usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/3rd_party/gehtsoft/gstool3/lib]可以看到 libfxcm.so 的依赖搜索路径里面已经指定了 /home/yychi/code/mdl_src/3rd/libs/forexconnect,而 libForexconnect.so 在这个目录下1,所以可以被找到。但间接依赖就 not found 了。因为 libForexconnect.so 的 rpath 里没有上面的目录。可以看到那一大串都是别人机器上的目录,所以对本地环境没啥用。还可以看到,他的第一个路径是当前目录!所以拷到同目录或者同目录创建软链接就能搜到了。
小技巧
- 可通过
readelf -d myapp | grep -iE 'rpath|runpath'查看 elf 文件的 rpath. - 可通过
LD_DEBUG=libs ldd myapp 2>&1 | less查看详细的搜索路径。
查找示例
$ LD_DEBUG=libs ldd libfxcm.so 2>&1|less ...... 877765: find library=libForexConnect.so [0]; searching 877765: search path=./tls/haswell/x86_64:./tls/haswell:./tls/x86_64:./tls:./haswell/x86_64:./haswell:./x86_64:.:./bin/tls/haswell/x86_64:./bin/tls/haswell:./bin/tls/x86_64:./bin/tls:./bin/haswe ll/x86_64:./bin/haswell:./bin/x86_64:./bin:/usr/local/lib/tls/haswell/x86_64:/usr/local/lib/tls/haswell:/usr/local/lib/tls/x86_64:/usr/local/lib/tls:/usr/local/lib/haswell/x86_64:/usr/local/lib/haswell:/usr/local/lib/x86_64:/usr/local/lib:/home/yychi/code/mdl_src/3rd/libs/forexconnect/tls/haswell/x86_64:/home/yychi/code/mdl_src/3rd/libs/forexconnect/tls/haswell:/home/yychi/code/mdl_src/3rd/libs/forexconnect/tls/x86_64:/home/yychi/code/mdl_src/3rd/libs/forexconnect/tls:/home/yychi/code/mdl_src/3rd/libs/forexconnect/haswell/x86_64:/home/yychi/code/mdl_src/3rd/libs/forexconnect/haswell:/home/yychi/code/mdl_src/3rd/libs/forexconnect/x86_64:/home/yychi/code/mdl_src/3rd/libs/forexconnect (RUNPATH from file ./libfxcm.so) 877765: trying file=./tls/haswell/x86_64/libForexConnect.so 877765: trying file=./tls/haswell/libForexConnect.so 877765: trying file=./tls/x86_64/libForexConnect.so 877765: trying file=./tls/libForexConnect.so 877765: trying file=./haswell/x86_64/libForexConnect.so 877765: trying file=./haswell/libForexConnect.so 877765: trying file=./x86_64/libForexConnect.so 877765: trying file=./libForexConnect.so 877765: trying file=./bin/tls/haswell/x86_64/libForexConnect.so 877765: trying file=./bin/tls/haswell/libForexConnect.so 877765: trying file=./bin/tls/x86_64/libForexConnect.so 877765: trying file=./bin/tls/libForexConnect.so 877765: trying file=./bin/haswell/x86_64/libForexConnect.so 877765: trying file=./bin/haswell/libForexConnect.so 877765: trying file=./bin/x86_64/libForexConnect.so 877765: trying file=./bin/libForexConnect.so 877765: trying file=/usr/local/lib/tls/haswell/x86_64/libForexConnect.so 877765: trying file=/usr/local/lib/tls/haswell/libForexConnect.so 877765: trying file=/usr/local/lib/tls/x86_64/libForexConnect.so 877765: trying file=/usr/local/lib/tls/libForexConnect.so 877765: trying file=/usr/local/lib/haswell/x86_64/libForexConnect.so 877765: trying file=/usr/local/lib/haswell/libForexConnect.so 877765: trying file=/usr/local/lib/x86_64/libForexConnect.so 877765: trying file=/usr/local/lib/libForexConnect.so 877765: trying file=/home/yychi/code/mdl_src/3rd/libs/forexconnect/tls/haswell/x86_64/libForexConnect.so 877765: trying file=/home/yychi/code/mdl_src/3rd/libs/forexconnect/tls/haswell/libForexConnect.so 877765: trying file=/home/yychi/code/mdl_src/3rd/libs/forexconnect/tls/x86_64/libForexConnect.so 877765: trying file=/home/yychi/code/mdl_src/3rd/libs/forexconnect/tls/libForexConnect.so 877765: trying file=/home/yychi/code/mdl_src/3rd/libs/forexconnect/haswell/x86_64/libForexConnect.so 877765: trying file=/home/yychi/code/mdl_src/3rd/libs/forexconnect/haswell/libForexConnect.so 877765: trying file=/home/yychi/code/mdl_src/3rd/libs/forexconnect/x86_64/libForexConnect.so 877765: trying file=/home/yychi/code/mdl_src/3rd/libs/forexconnect/libForexConnect.so 877765: ...... 877765: find library=libfxmsg.so [0]; searching 877765: search path=./tls/haswell/x86_64:./tls/haswell:./tls/x86_64:./tls:./haswell/x86_64:./haswell:./x86_64:. (RUNPATH from file ./libfxcm.so) 877765: trying file=./tls/haswell/x86_64/libfxmsg.so 877765: trying file=./tls/haswell/libfxmsg.so 877765: trying file=./tls/x86_64/libfxmsg.so 877765: trying file=./tls/libfxmsg.so 877765: trying file=./haswell/x86_64/libfxmsg.so 877765: trying file=./haswell/libfxmsg.so 877765: trying file=./x86_64/libfxmsg.so 877765: trying file=./libfxmsg.so 877765: search path= (RPATH from file /home/yychi/code/mdl_src/3rd/libs/forexconnect/libForexConnect.so) 877765: search cache=/etc/ld.so.cache 877765: search path=/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/lib:/usr/lib (system search path) 877765: trying file=/lib/x86_64-linux-gnu/libfxmsg.so 877765: trying file=/usr/lib/x86_64-linux-gnu/libfxmsg.so 877765: trying file=/lib/libfxmsg.so 877765: trying file=/usr/lib/libfxmsg.so
可见,查找 libForexconnect.so 时,按照我指定的目录去找了。而找 libfxmsg.so 时,只找了系统目录。如果任选一个 libForexconnect.so 搜索目录,在本机创建之,然后在那个目录下创建软链接,立马就能找到间接依赖。
$ mkdir -p /usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/3rd_party/gehtsoft/gstool3/lib
$ cd /usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/3rd_party/gehtsoft/gstool3/lib
$ ln -s /home/bingbing.hu/code/mdl_src/3rd/libs/forexconnect/libfxmsg.so
$ ll
total 12
drwxr-xr-x 2 root root 4096 Jul 10 15:22 ./
drwxr-xr-x 3 root root 4096 Jul 10 15:22 ../
lrwxrwxrwx 1 root root 64 Jul 10 15:22 libfxmsg.so -> /home/yychi/code/mdl_src/3rd/libs/forexconnect/libfxmsg.so
$ ldd libfxcm.so
linux-vdso.so.1 (0x00007ffe61bfd000)
libForexConnect.so => /home/yychi/code/mdl_src/3rd/libs/forexconnect/libForexConnect.so (0x00007fc888bc7000)
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fc8889d1000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fc8889b6000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc8887c4000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc88879f000)
libgsexpat.so => not found
libfxtp.so => not found
libfxmsg.so => /usr/local/gehtsoft/jenkins_service/workspace/FXAPI_build_Linux64/3rd_party/gehtsoft/gstool3/lib/libfxmsg.so (0x00007fc8882fc000)
libgstool3.so => not found
liblog4cplus.so => not found
...当然,一般还是在当前目录创建软链接更方便,更通用。
Footnotes
-
其他二级依赖如 libfxmsg.so 也都在这个目录下。 ↩