一.问题说明

安装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

  1. 安装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*  查看确认库文件对系统文件和其他软件的影响,确认系统或其他软件是否会有异常,再做进一步处理

Logo

鸿蒙生态一站式服务平台。

更多推荐