共享库链接和加载时的路径搜索优先级
前言
在开发一个新项目时遇到了共享库冲突的问题,因此在这里记录一下共享库的链接和加载过程中库路径的搜索优先级的相关知识。
共享库的链接
现在有一个main.o
可重定位目标文件,其中需要用到开源库log4cpp。在链接的时候,我们可以这样链接:
g++ main.o -o a.out -L/path/to/libs -llog4cpp
其中:
-L/path/to/libs
表示链接器去哪个目录下查找库文件。
注意:通过-L指定的路径的搜索优先级是要高于系统默认的库文件路径的。
使用g++编译时库搜索优先级:
-L指定的路径
>默认库路径
>LIBRARY_PATH指定路径
(我看网上都说优先级为:-L指定的路径
>LIBRARY_PATH指定路径
>默认库路径
,但是我做了个实验发现使用g++时不是这样的,实验过程见《编译期链接时共享库搜索路径优先级实验》
)
-llog4cpp
表示要链接的库,在链接阶段,链接器一般会按照搜索优先级,从库路径中查找名为liblog4cpp.so
或liblog4cpp.a
的文件进行链接。若不特殊说明,默认优先链接共享库。
共享库的加载
在程序开始运行前的加载阶段,动态链接器会读取可执行文件,查找并加载所有必须的共享库。注意此时的搜索路径并不包含上述的/path/to/libs
,因为它只作用于编译时的链接阶段。动态链接器搜索的路径有:LD_LIBRARY_PATH环境变量,/etc/ld.so.cache
文件,默认库路径(/usr/lib
,/lib
等),RPATH(需编译时设置),RUNPATH(需编译时设置)。
如果需要从指定的路径加载共享库,则可以使用下述方法:
- 手动设置LD_LIBRARY_PATH环境变量:在程序运行前设置环境变量,指定共享库的搜索路径:
注意,此方法设置环境变量是临时的,一旦终端关闭设置就会失效。若想使其持久化,需要特殊设置,方法包括但不限于:修改.bashrc文件,修改rc.loacl文件。export LD_LIBRARY_PATH=/path/to/runtime_libs:$LD_LIBRARY_PATH
- 修改
/etc/ld.so.conf
和/etc/ld.so.conf.d/*
配置:
这些文件提供了系统级别的库搜索路径。系统管理员可以在这些文件中定义默认的库搜索路径,这些设置对所有用户和应用程序都有效。 - 在编译期的链接阶段使用
-rpath
:
在编译期的链接阶段,设置RPATH或RUNPATH,将库路径硬编码到可执行文件中
注意若可执行文件中同时包含RPATH和RUNPATH,那么RPATH将会被动态链接器忽略。g++ main.o -o a.out -L/path/to/libs -llog4cpp -Wl,-rpath,/path/to/runtime_libs
共享库的搜索优先级为:
RPATH
>LD_LIBRARY_PATH
>RUNPATH
>/etc/ld.so.conf
和/etc/ld.so.conf.d/*
>默认库路径
我做了个实验验证上述优先级,详见:《运行期加载时共享库路径搜索优先级实验》