在 Linux 中完美的使用 .so 动态库
再阅读本文之前,请看前情提要:在 C++ 中隐式的使用.so 动态库.
本文所有操作皆在 Archlinux 中测试通过。
程序的动态节
程序在链接时有能力告诉动态链接器它需要链接哪些动态库,就也应该有能力提醒动态链接器去哪里搜索动态库。这些信息存储在程序的动态节(dynamic section)中,我们可以通过 readelf 命令查看:1
readelf -d ./a.out
-d
参数就是指查看动态节的内容.
Linux 可执行文件的动态节中有两个与动态库搜索路径相关的条目,一个是 RPATH,一个是 RUNPATH。二者的区别在于优先级,动态链接器会按照下面列举的顺序依次搜索:
- 动态节中的 RPATH 项指定的路径;
- 环境变量 LD_LIBRARY_PATH 指定的路径;
- 系统配置文件 /etc/ld.so.conf 指定的路径;
- 动态节中的 RUNPATH 项指定的路径。
如果程序中写死了 RPATH,就相当于堵死了用户去覆盖搜索路径的可能。因此RPATH 已经被废弃。但实际上 RPATH 很常用,主要用于锁定某一特定版本的动态库。
指定动态节中 RUNPATH 项
那么回到之前的问题中来,新的完美的解决办法就是指定动态节中 RUNPATH 项.
还记的之前我们最后链接时的命令吗,下面这行命令就是。我们要怎么指定动态节中的 RUNPATH 项呢?1
g++ main.cpp -L. -lmyadd -o a.out
其实只需要多加一项参数。1
g++ main.cpp -L. '-Wl,-R${ORIGIN}' -lmyadd -o a.out
-WL
用于在编译器的命令行中向链接器传递参数。-R
就是传过去的参数,链接器参数 -R 正是用于设置 RUNPATH。${ORIGIN}
是-R
参数的值。${ORIGIN}
表示的就是程序所在的目录。用当前工作目录“.”的话,可能会出问题,因为当前目录可能不是程序所在的目录。
现在我们就完美的解决了程序运行时找不到动态库的问题!