一.问题说明
安装xx所软件后在/etc/ld.so.conf.d/下创建了一个JinCEarth.conf的配置文件,ldconfig使其生效,然后安装任意一个包,重启时将会黑屏
1.根本原因:ld.so.cache的改变使得/usr/lib/x86_64-linux-gnu/libXrandr.so.2的库加载不上导致lightdm反复重启,表现为黑屏闪屏。
2.具体原因分析(libXrandr.so.2的库加载不上的原因):
通过跟踪一个系统缓存中可用的库来分析问题
ldconfig -p |grep libXrandr.so.2
(1)在没有安装xx软件并ldconfig之前,只有一个候选路径
libXrandr.so.2 => /usr/lib/x86_64-linux-gnu/libXrandr.so.2
此时查询ldd /usr/sbin/ukui-greeter|grep的结果为
libXrandr.so.2 => /usr/lib/x86_64-linux-gnu/libXrandr.so.2
安装xx所软件后在/etc/ld.so.conf.d/下创建了一个JinCEarth.conf的配置文件,ldconfig使其生效,生成新的ld.so.cache。此时系统有了一点变化。
libXrandr.so.2=> /usr/lib/x86_64-linux-gnu/libXrandr.so.2
libXrandr.so.2 => /opt/ZHXT/.../libXrandr.so.2
此时查询ldd /usr/sbin/ukui-greeter|grep libXrandr.so.2的结果为
libXrandr.so.2 =>/usr/lib/x86_64-linux-gnu/libXrandr.so.2
系统表面上一切正常
(3)在同一个库的候选上有多条路径,会先找ld.so.cache中排名靠前的那个,但是一旦这个排名发生了改变,就会产生不可预知的严重后果,这个后果取决于这个库对于系统正常运行有多重要
而安装任何一个安装包正是使这个排名发生改变的诱因。
dpkg -i xxx.deb的操作会使ldconfig -p |grep libXrandr.so.2的查询结果变为
libXrandr.so.2 => /opt/ZHXT/.../libXrandr.so.2
libXrandr.so.2 => /usr/lib/x86_64-linux-gnu/libXrandr.so.2
而此时查询ldd /usr/sbin/ukui-greeter|grep libXrandr.so.2的结果变为
libXrandr.so.2 => /opt/ZHXT/.../libXrandr.so.2
系统表面上一切正常,但是错误已经产生,一但lightdm重启时加载启动libXrandr.so.2,黑屏现象就这样产生了
那么dpkg究竟做了什么?
答案就是dpkg在安装后设置的过程中也使用了ldconfig,具体使用者为dpkg名下的libc-bin触发器。同样是ldconfig,为何dpkg过后顺序就变了,原因是libc-bin修改了名为
LC_ALL的环境变量,LC_ALL的设置会导致LC_COLLATE也发生改变,这个环境变量即为问题产生的关键,因为LC_COLLATE正是用于定义环境的排序和比较规则。
用户如需验证的话可将/var/lib/dpkg/info/libc-bin.postinst中的export LC_ALL=C注释掉,如此的话dpkg安装的时候将不会改变ld.so.cache的排序
但是一定要记得改回去,该方法不可作为解决问题的方法。
或者在手动执行ldconfig之前先export export LC_ALL=C,然后ldconfig将会改变ld.so.cache的排序,unset LC_ALL,再次ldconfig,ld.so.cache将会还原
那么也就很好解释为什么问题产生之后,再次ldconfig 或者 移除导致问题产生的库使候选路径自动变为原来的一条(/opt/ZHXT/.../libXrandr.so.2下libXrandr.so.2),系统恢复正常
这只是暂时解决的方法,因为外来库的隐患依旧残留在ld.so.cache中
- 如何设置环境变量及风险说明
(不推荐作用于全局的环境变量设置及修改)
如果一定要使用全局变量,可以使用风险较小的方法
1.在ld.so.conf中添加路径或者在ld.so.conf.d中添加新的conf后ldconfig生成新的缓存文件ld.so.cache,风险较大。系统加载会用到ld.so.cache,具体参考上方问题分析
2.在/etc/profile中设置export LD_LIBRARY_PATH=/xxxx/xxx,风险较小,不会影响到ld.so.cache,影响域将会变为profile生效之后启动的系统应用
3.用的时候在终端中设置环境变量,export LD_LIBRARY_PATH=/xxxx/xxx,基本无风险,但仅在当前终端中生效
4.对于Qt来说,只需要在工程文件夹下面创建一个qt.conf,里面加上以下内容即可使程序在运行时默认调用指定路径下的库,该方法是qt官方提供的(网址:https://doc.qt.io/qt-5/qt-conf.html),零风险,合规范,当然不能作用于全局,只能作用于当前工程,无需重复设置。以下为设置方法
如果qt所有相关的lib,plugins等都在同一个文件夹下,只需要
[Paths]
Prefix = /opt/Qt5.9.6
如果qt所有相关的lib,plugins等不是同一个文件夹下,则需要
[Paths]
Libraries = qt的lib对应路径
Plugins = qt的plugins对应路径
这两个是必须的
以下根据需求选择
LibraryExecutables = qt的libexec对应路径
Binaries = qt的bin对应路径
Headers = qt的include对应路径
Imports = qt的imports对应路径
Qml2Imports = qt的qml对应路径
Translations = qt的translations对应路径
Examples = qt的examples对应路径
Tests = qt的tests对应路径
三、共享库的查找顺序
linux中动态链接库的搜索顺序
linux中程序对动态链接库的搜索顺序,如下所述: 1.首先查看程序文件的.dynamic 段是否包含了一个叫DT_RPATH的项(它是一个以冒号分隔的库文件搜索目录列表)。
查看.dynamic 段,readelf -d test(编译好的可执行文件) 怎么设置这个选项? 需要在编译连接程序的时候使用-L选项,假设一个程序test需要使用liblib.so库,如下所示进行编译连接: gcc -o test -L./ -llib test.c 这样在执行test程序时,test便会先到./即当前目录下查找所需要的动态库。-L操作只在编译时生效。如果想使用指定的路径,需要加参数-Wl,rpath,例如 gcc -o test test.c -L. -ltest -Wl,-rpath=/root/mycodes/codes/test,ldd test查看库文件路径/root/mycodes/codes/test路径查找正确 2.查找是否存在环境变量 LD_LIBRARY_PATH(它是一个以冒号分隔的库文件搜索目录列表)。 怎么设置这个选项?当然是设置linux下的环境变量就可以了。 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
当然,这种方法是对当前登录生效的。如果想开机即有效,跟其它环境变量的设置也是一样,需要修改一些配置文件。
修改配置文件的方法如下: 该变量添加位置可以在系统的多个启动文件中如:/etc/profile(该文件在全局变量中起作用) -> /etc/rc.local(在shell下起作用) -> /etc/bashrc(在shell下起作用) ~/.profile(在shell下起作用)-> ~/.bashrc(在shell下起作用) 等。 3.查看库高速缓存文件 /etc/ld.so.conf ,它包含了库名和路径的一个对应列表,如果库名存在,连接器就使用它对应的路径,用这个查找方法能够找到大部分的库。 怎么设置这个选项?可以直接编辑ld.so.conf加入需要查找的路径,也可以在/etc/ld.so.conf.d目录下的己有文件中加入路径,或者在该目录下新建一个文件(名字为*.conf即可),再把需要的路径加入到该文件中。最后执行ldconfig即可生效。ld.so.conf.d中添加的配置为全局变量根据查找顺序,如果有同名库,就会更具规则找到第一路径的库 ldconfig的查找顺序是根据字符集的规则查找的LANG=C(posix规则) 或者zh_CN.UTF-8 字符集决定 4.查找默认路径/lib和/usr/lib, 如果经过了以上的步骤仍然查找失败,则将报错并退出相关程序。 对于前三个步骤来说,我们均是可以进行设置调整的,其中第三个步骤中的设置需要root权限才能进行,且会影响所有的程序。
- 使用同名库,
如果必须使用同名库尽量不要放入全局环境变量也就是不要放在/etc/ld.so.conf.d/路径下,
1、编译软件时将库的查找路径编译进去 gcc -o test test.c -L. -ltest -Wl,-rpath=/root/mycodes/codes/test
2、可以在执行软件时再加载库文件,例如在软件执行时添加export 同名库路径,
或者在类似/etc/profile设置环境变量添加库的查询路径,但是此种加载方式只在shell环境中起作用
3、如果需要写入/etc/ld.so.conf.d/下的xx.conf文件中需要通过ldconfig -p |grep libxxx* 查看确认库文件对系统文件和其他软件的影响,确认系统或其他软件是否会有异常,再做进一步处理